#include "dev_menu.h" #include #include "Displaydef.h" #include #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& 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 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); } }