newtx/ui/dev_menu.cpp

462 lines
11 KiB
C++
Raw Normal View History

2024-02-02 08:53:17 +00:00
#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);
}
}