462 lines
11 KiB
C++
462 lines
11 KiB
C++
|
#include "dev_menu.h"
|
|||
|
|
|||
|
#include <string.h>
|
|||
|
#include "Displaydef.h"
|
|||
|
#include <base/words.h>
|
|||
|
#include "keymonitor.h"
|
|||
|
#include "Lcd.h"
|
|||
|
#include "font.h"
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
|
// dev_menu
|
|||
|
dev_menu::dev_menu()
|
|||
|
{}
|
|||
|
dev_menu::~dev_menu()
|
|||
|
{
|
|||
|
set_parent(nullptr);
|
|||
|
for(auto& v: items_)
|
|||
|
{
|
|||
|
if(!v.leaf)
|
|||
|
{
|
|||
|
v.child->set_parent(nullptr);
|
|||
|
v.child->release();
|
|||
|
}
|
|||
|
}
|
|||
|
items_.clear();
|
|||
|
}
|
|||
|
|
|||
|
int dev_menu::find_item(const char* text)
|
|||
|
{
|
|||
|
int ind = -1;
|
|||
|
|
|||
|
for(size_t i = 0; i < items_.size(); ++i)
|
|||
|
{
|
|||
|
if(items_[i].text == text)
|
|||
|
{
|
|||
|
ind = i;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ind;
|
|||
|
}
|
|||
|
|
|||
|
void dev_menu::set_parent(dev_menu* parent)
|
|||
|
{
|
|||
|
if(parent_)
|
|||
|
{
|
|||
|
parent_->release();
|
|||
|
if(items_.size() && items_[0].id == MENU_ID_RETURN)
|
|||
|
items_.erase(items_.begin());
|
|||
|
}
|
|||
|
parent_ = parent;
|
|||
|
if(parent_)
|
|||
|
{
|
|||
|
parent_->add_ref();
|
|||
|
if(!items_.size() || items_[0].id != MENU_ID_RETURN)
|
|||
|
{
|
|||
|
MITEM mi;
|
|||
|
mi.text = WORDS_MENU_RETURN;
|
|||
|
mi.leaf = true;
|
|||
|
mi.id = MENU_ID_RETURN;
|
|||
|
items_.insert(items_.begin(), mi);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bool dev_menu::add_menu(const char* text, int id)
|
|||
|
{
|
|||
|
int ind = find_item(text);
|
|||
|
|
|||
|
if(ind != -1)
|
|||
|
return false;
|
|||
|
|
|||
|
MITEM mi;
|
|||
|
|
|||
|
mi.id = id;
|
|||
|
mi.leaf = true;
|
|||
|
mi.text = text;
|
|||
|
items_.push_back(mi);
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
bool dev_menu::add_menu(const char* text, dev_menu* submenu)
|
|||
|
{
|
|||
|
int ind = find_item(text);
|
|||
|
|
|||
|
if(ind != -1 || !submenu)
|
|||
|
return false;
|
|||
|
|
|||
|
MITEM mi;
|
|||
|
|
|||
|
mi.child = submenu;
|
|||
|
mi.leaf = false;
|
|||
|
mi.text = text;
|
|||
|
items_.push_back(mi);
|
|||
|
submenu->add_ref();
|
|||
|
submenu->set_parent(this);
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
bool dev_menu::remove_menu(const char* text)
|
|||
|
{
|
|||
|
int ind = find_item(text);
|
|||
|
|
|||
|
if(ind == -1)
|
|||
|
return false;
|
|||
|
|
|||
|
if(!items_[ind].leaf)
|
|||
|
items_[ind].child->release();
|
|||
|
items_.erase(items_.begin() + ind);
|
|||
|
if(cur_ >= items_.size())
|
|||
|
cur_ = items_.size() - 1;
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
bool dev_menu::move_to(bool next)
|
|||
|
{
|
|||
|
bool ret = false;
|
|||
|
|
|||
|
if(next)
|
|||
|
{
|
|||
|
if(cur_ < (int)items_.size() - 1)
|
|||
|
{
|
|||
|
cur_++;
|
|||
|
ret = true;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if(cur_ > 0)
|
|||
|
{
|
|||
|
cur_--;
|
|||
|
ret = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
bool dev_menu::select(const char* txt)
|
|||
|
{
|
|||
|
int ind = find_item(txt);
|
|||
|
|
|||
|
if(ind == -1)
|
|||
|
return false;
|
|||
|
|
|||
|
cur_ = ind;
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
void dev_menu::reset_pos(void)
|
|||
|
{
|
|||
|
cur_ = 0;
|
|||
|
}
|
|||
|
|
|||
|
dev_menu* dev_menu::enter(int* id)
|
|||
|
{
|
|||
|
dev_menu *menu = this;
|
|||
|
|
|||
|
if(id)
|
|||
|
*id = -1;
|
|||
|
if(cur_ >= 0 && cur_ < items_.size())
|
|||
|
{
|
|||
|
if(items_[cur_].leaf)
|
|||
|
{
|
|||
|
if(items_[cur_].id == MENU_ID_RETURN)
|
|||
|
{
|
|||
|
if(parent_)
|
|||
|
menu = parent_;
|
|||
|
}
|
|||
|
else if(id)
|
|||
|
*id = items_[cur_].id;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
menu = items_[cur_].child;
|
|||
|
menu->reset_pos();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
menu->add_ref();
|
|||
|
|
|||
|
return menu;
|
|||
|
}
|
|||
|
int dev_menu::get_menu_text(std::vector<std::string>& text)
|
|||
|
{
|
|||
|
for(auto& v: items_)
|
|||
|
text.push_back(v.text);
|
|||
|
|
|||
|
return cur_;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|||
|
// ui_mgr
|
|||
|
enum
|
|||
|
{
|
|||
|
MENU_CMD_ID_GET_ROLLER_COUNT = 0x100,
|
|||
|
MENU_CMD_ID_CLEAR_ROLLER_COUNT,
|
|||
|
MENU_CMD_ID_SLEEP_NOW,
|
|||
|
MENU_CMD_ID_SHUTDOWN,
|
|||
|
};
|
|||
|
|
|||
|
ui_mgr::ui_mgr() : disp_data_("lcd-msg")
|
|||
|
{
|
|||
|
init();
|
|||
|
|
|||
|
auto ke = [this](int key) -> void
|
|||
|
{
|
|||
|
key_event(key);
|
|||
|
};
|
|||
|
lcd_.reset(new Lcd());
|
|||
|
lcd_->Lcd_Initial_Lcd(false);
|
|||
|
lcd_->clear();
|
|||
|
|
|||
|
keyboard_.reset(new KeyMonitor(ke));
|
|||
|
disp_thrd_.reset(new std::thread(&ui_mgr::thread_display, this));
|
|||
|
refresh_lcd(true);
|
|||
|
}
|
|||
|
ui_mgr::~ui_mgr()
|
|||
|
{
|
|||
|
run_ = false;
|
|||
|
disp_data_.trigger();
|
|||
|
if(disp_thrd_.get() && disp_thrd_->joinable())
|
|||
|
disp_thrd_->join();
|
|||
|
|
|||
|
clear();
|
|||
|
}
|
|||
|
|
|||
|
void ui_mgr::do_menu_command(int cmd)
|
|||
|
{
|
|||
|
if(handler_.count(cmd))
|
|||
|
handler_[cmd](cur_, cmd);
|
|||
|
|
|||
|
// at last, we return to main menu OR parent ?
|
|||
|
cur_->release();
|
|||
|
cur_ = root_; // main menu
|
|||
|
cur_->add_ref();
|
|||
|
}
|
|||
|
void ui_mgr::init(void)
|
|||
|
{
|
|||
|
dev_menu *child = nullptr;
|
|||
|
|
|||
|
root_ = new dev_menu();
|
|||
|
|
|||
|
// 分纸强度(低中高)
|
|||
|
{
|
|||
|
child = new dev_menu();
|
|||
|
child->add_menu(WORDS_MENU_LOW, (int)DisType::Dis_Set_PollPI_Low);
|
|||
|
child->add_menu(WORDS_MENU_MID, (int)DisType::Dis_Set_PollPI_Mid);
|
|||
|
child->add_menu(WORDS_MENU_HIGH, (int)DisType::Dis_Set_PollPI_High);
|
|||
|
root_->add_menu(WORDS_MENU_SEPARATE_STRENGTH, child);
|
|||
|
child->release();
|
|||
|
}
|
|||
|
// 休眠时间(不休眠,5min, 10min, 20min, 30min, 1h, 2h, 4h)
|
|||
|
{
|
|||
|
child = new dev_menu();
|
|||
|
child->add_menu(WORDS_MENU_SLEEP_NONE, (int)DisType::Dis_Set_SleepMode_NEVER);
|
|||
|
child->add_menu(WORDS_MENU_SLEEP_5_MIN, (int)DisType::Dis_Set_SleepMode_5M);
|
|||
|
child->add_menu(WORDS_MENU_SLEEP_10_MIN, (int)DisType::Dis_Set_SleepMode_10M);
|
|||
|
child->add_menu(WORDS_MENU_SLEEP_20_MIN, (int)DisType::Dis_Set_SleepMode_20M);
|
|||
|
child->add_menu(WORDS_MENU_SLEEP_30_MIN, (int)DisType::Dis_Set_SleepMode_30M);
|
|||
|
child->add_menu(WORDS_MENU_SLEEP_1_HOUR, (int)DisType::Dis_Set_SleepMode_1H);
|
|||
|
child->add_menu(WORDS_MENU_SLEEP_2_HOUR, (int)DisType::Dis_Set_SleepMode_2H);
|
|||
|
child->add_menu(WORDS_MENU_SLEEP_4_HOUR, (int)DisType::Dis_Set_SleepMode_4H);
|
|||
|
root_->add_menu(WORDS_MENU_POWER, child);
|
|||
|
child->release();
|
|||
|
}
|
|||
|
// 升降台位置(低中高)
|
|||
|
{
|
|||
|
child = new dev_menu();
|
|||
|
child->add_menu(WORDS_MENU_LOW, (int)DisType::Dis_Set_TrayPosition_Low);
|
|||
|
child->add_menu(WORDS_MENU_MID, (int)DisType::Dis_Set_TrayPosition_Mid);
|
|||
|
child->add_menu(WORDS_MENU_HIGH, (int)DisType::Dis_Set_TrayPosition_High);
|
|||
|
root_->add_menu(WORDS_MENU_LIFTER_POS, child);
|
|||
|
child->release();
|
|||
|
}
|
|||
|
|
|||
|
// 计数模式、手动模式、清理纸道、历史张数、滚轴张数、清除滚轴张数(确定,取消)、进入休眠、关机
|
|||
|
root_->add_menu(WORDS_MENU_COUNT_MODE, (int)DisType::Dis_Count_Page);
|
|||
|
root_->add_menu(WORDS_MENU_MANUAL_MODE, (int)DisType::Dis_HandMode);
|
|||
|
root_->add_menu(WORDS_MENU_CLEAR_PASSWAY, (int)DisType::Dis_Set_ClearPaperPass);
|
|||
|
root_->add_menu(WORDS_MENU_HISTORY_COUNT, (int)DisType::Dis_Set_Get_History_ScanNum);
|
|||
|
root_->add_menu(WORDS_MENU_ROLLER_COUNT, MENU_CMD_ID_GET_ROLLER_COUNT);
|
|||
|
{
|
|||
|
child = new dev_menu();
|
|||
|
child->add_menu(WORDS_MENU_YES, (int)DisType::Dis_Set_YES);
|
|||
|
child->add_menu(WORDS_MENU_NO, (int)DisType::Dis_Set_No);
|
|||
|
root_->add_menu(WORDS_MENU_RESET_ROLLOER_CNT, child);
|
|||
|
child->release();
|
|||
|
}
|
|||
|
root_->add_menu(WORDS_MENU_SLEEP_NOW, MENU_CMD_ID_SLEEP_NOW);
|
|||
|
root_->add_menu(WORDS_MENU_SHUTDOWN, MENU_CMD_ID_SHUTDOWN);
|
|||
|
|
|||
|
cur_ = root_;
|
|||
|
cur_->add_ref();
|
|||
|
}
|
|||
|
void ui_mgr::clear(void)
|
|||
|
{
|
|||
|
if(cur_)
|
|||
|
cur_->release();
|
|||
|
cur_ = nullptr;
|
|||
|
|
|||
|
if(root_)
|
|||
|
root_->release();
|
|||
|
root_ = nullptr;
|
|||
|
}
|
|||
|
void ui_mgr::refresh_lcd(bool cur_at_top)
|
|||
|
{
|
|||
|
std::vector<std::string> text, disp;
|
|||
|
int cur = cur_->get_menu_text(text), sel = 0,
|
|||
|
rows = Lcd::LCD_HEIGHT / font_size_.cy;
|
|||
|
|
|||
|
if(cur >= 0 && cur < text.size())
|
|||
|
{
|
|||
|
disp.push_back(text[cur]);
|
|||
|
if(cur_at_top)
|
|||
|
{
|
|||
|
for(int i = cur + 1; i < text.size() && disp.size() < rows; ++i)
|
|||
|
disp.push_back(text[i]);
|
|||
|
for(int i = cur - 1; i >= 0 && disp.size() < rows; --i, sel++)
|
|||
|
disp.insert(disp.begin(), text[i]);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
for(int i = cur - 1; i >= 0 && disp.size() < rows; --i, sel++)
|
|||
|
disp.insert(disp.begin(), text[i]);
|
|||
|
for(int i = cur + 1; i < text.size() && disp.size() < rows; ++i)
|
|||
|
disp.push_back(text[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
rows = 0;
|
|||
|
for(int i = 0; i < disp.size(); ++i)
|
|||
|
{
|
|||
|
DISPDATA dd;
|
|||
|
|
|||
|
memset(&dd, 0, sizeof(dd));
|
|||
|
if(i == 0)
|
|||
|
disp_data_.save(dd, true);
|
|||
|
dd.mask = i == sel ? 0x0ff : 0;
|
|||
|
dd.x = font_size_.cx;
|
|||
|
dd.y = rows;
|
|||
|
dd.rows = font_size_.cy;
|
|||
|
dd.cols = font_size_.cx;
|
|||
|
dd.cnt = get_string_font(disp[i].c_str(), dd.ptr);
|
|||
|
cur = disp_data_.save(dd, true);
|
|||
|
rows += font_size_.cy;
|
|||
|
printf("display '%s', queue = %d, mask = %02x\n", disp[i].c_str(), cur, dd.mask);
|
|||
|
}
|
|||
|
}
|
|||
|
void ui_mgr::move_to(bool next)
|
|||
|
{
|
|||
|
if(cur_)
|
|||
|
{
|
|||
|
if(cur_->move_to(next))
|
|||
|
{
|
|||
|
// refresh LCD
|
|||
|
refresh_lcd(!next);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
void ui_mgr::enter(void)
|
|||
|
{
|
|||
|
if(!menu_mode_)
|
|||
|
{
|
|||
|
menu_mode_ = true;
|
|||
|
if(cur_)
|
|||
|
cur_->release();
|
|||
|
cur_ = root_;
|
|||
|
if(cur_)
|
|||
|
cur_->add_ref();
|
|||
|
}
|
|||
|
|
|||
|
if(cur_)
|
|||
|
{
|
|||
|
int id = -1;
|
|||
|
dev_menu* bef = cur_;
|
|||
|
|
|||
|
cur_ = cur_->enter(&id);
|
|||
|
bef->release();
|
|||
|
if(id != -1)
|
|||
|
{
|
|||
|
do_menu_command(id);
|
|||
|
}
|
|||
|
if(cur_ != bef)
|
|||
|
{
|
|||
|
// refresh LCD
|
|||
|
refresh_lcd(true);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
int ui_mgr::get_string_font(const char* text, uint8_t** ptr)
|
|||
|
{
|
|||
|
DISPDATA dd;
|
|||
|
int cnt = 0, ind = 0;
|
|||
|
|
|||
|
for(; text[ind] && cnt < _countof(dd.ptr); ++cnt)
|
|||
|
{
|
|||
|
// Fixed ME !!! how to count a character width ? here I assume 3-bytes
|
|||
|
char utf8[4] = {text[ind], text[ind + 1], text[ind + 2], 0};
|
|||
|
|
|||
|
if(text[ind] >= 0 && text[ind] <= 0x7f)
|
|||
|
{
|
|||
|
utf8[1] = utf8[2] = 0;
|
|||
|
ind++;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ind += 3;
|
|||
|
}
|
|||
|
ptr[cnt] = get_font_data(utf8) + 2; // skip height and widht data
|
|||
|
}
|
|||
|
|
|||
|
return cnt;
|
|||
|
}
|
|||
|
|
|||
|
void ui_mgr::thread_display(void)
|
|||
|
{
|
|||
|
DISPDATA dd;
|
|||
|
while(run_)
|
|||
|
{
|
|||
|
if(disp_data_.take(dd, true))
|
|||
|
{
|
|||
|
if(dd.cnt)
|
|||
|
lcd_->write_line(dd.rows, dd.cols, dd.cnt, dd.ptr, dd.x, dd.y, dd.mask);
|
|||
|
else
|
|||
|
lcd_->clear();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void ui_mgr::key_event(int key)
|
|||
|
{
|
|||
|
if(key == (int)KeyMonitor::HGKey::Key_Enter)
|
|||
|
enter();
|
|||
|
else if(key == (int)KeyMonitor::HGKey::Key_Left)
|
|||
|
move_to(false);
|
|||
|
else if(key == (int)KeyMonitor::HGKey::Key_Right)
|
|||
|
move_to(true);
|
|||
|
else if(key == (int)KeyMonitor::HGKey::Key_Cancle)
|
|||
|
{
|
|||
|
// stop scanning here ...
|
|||
|
}
|
|||
|
else if(key == -1) // interrupted by status message, we return to main menu
|
|||
|
{
|
|||
|
if(cur_)
|
|||
|
cur_->release();
|
|||
|
cur_ = root_;
|
|||
|
if(cur_)
|
|||
|
{
|
|||
|
cur_->add_ref();
|
|||
|
cur_->reset_pos();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
utils::to_log(LOG_LEVEL_ALL, "Unhandled keyboard event: %02X\n", key);
|
|||
|
}
|
|||
|
}
|