newtx/ui/dev_menu.cpp

462 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}
}