Adam PIppin
3 years ago
16 changed files with 491 additions and 290 deletions
@ -0,0 +1 @@ |
|||
* Add "Scenes" to group tasks/etc and simplify separating input and figuring out what to draw |
@ -1,312 +1,75 @@ |
|||
#include "watchos.h" |
|||
#include "Module_EAT.h" |
|||
#include "Module_UI.h" |
|||
#include "watchos_fonts.h" |
|||
#include "Module_Menu.h" |
|||
#include "Events.h" |
|||
|
|||
|
|||
|
|||
struct MenuItem |
|||
{ |
|||
byte id; |
|||
char label[MENU_MAX_OPTION_LENGTH]; |
|||
int window_hwnd; |
|||
}; |
|||
|
|||
/*
|
|||
* EAT Layout |
|||
* byte selected_idx |
|||
* byte view_offset |
|||
* |
|||
* each entry: |
|||
* byte id |
|||
* char[31] label |
|||
*/ |
|||
|
|||
class Task_Menu : public Task |
|||
{ |
|||
private: |
|||
int m_hwnd; |
|||
Module_UI* ui; |
|||
Module_EAT* eat; |
|||
MenuItem* m_item[MENU_MAX_OPTIONS]; |
|||
int m_hwnd_menu_option[MENU_SHOW_OPTIONS]; |
|||
int m_prev_root_hwnd; |
|||
|
|||
int m_view_offset = 0; |
|||
int m_selected = 0; |
|||
|
|||
bool m_result_ok = false; |
|||
bool m_result_back = false; |
|||
Module_Menu* menu; |
|||
bool m_waiting_for_menu = false; |
|||
|
|||
public: |
|||
Task_Menu() |
|||
{ |
|||
ui = (Module_UI*)Kernel::get()->getModule(MODULE_UI); |
|||
m_hwnd = ui->createWindow((Task*)this, -1, 0); |
|||
ui->setLayoutMode(m_hwnd, MODULE_UI_LAYOUT_MODE_SPLIT_HORIZONTAL); |
|||
for (int i = 0; i < MENU_SHOW_OPTIONS; i++) |
|||
{ |
|||
m_hwnd_menu_option[i] = ui->createWindow((Task*)this, m_hwnd, 0); |
|||
} |
|||
|
|||
for (int i = 0; i < MENU_MAX_OPTIONS; i++) |
|||
{ |
|||
m_item[i] = nullptr; |
|||
} |
|||
|
|||
eat = (Module_EAT*)Kernel::get()->getModule(MODULE_EAT); |
|||
int item_length = (1 + MENU_MAX_OPTION_LENGTH); |
|||
if (!eat->allocate(MENU_EAT_ID, MENU_EAT_OFFSET + item_length * MENU_MAX_OPTIONS)) |
|||
{ |
|||
m_selected = eat->read(MENU_EAT_ID, 0); |
|||
m_view_offset = eat->read(MENU_EAT_ID, 1); |
|||
m_prev_root_hwnd = eat->read(MENU_EAT_ID, 2); |
|||
|
|||
byte id; |
|||
for (int i = 0; i < MENU_MAX_OPTIONS; i++) |
|||
{ |
|||
id = eat->read(MENU_EAT_ID, MENU_EAT_OFFSET + (i * item_length)); |
|||
if (id != 0xFF) |
|||
{ |
|||
m_item[i] = new MenuItem(); |
|||
m_item[i]->id = id; |
|||
for (int j = 0; j < MENU_MAX_OPTION_LENGTH; j++) |
|||
{ |
|||
m_item[i]->label[j] = (char)eat->read(MENU_EAT_ID, MENU_EAT_OFFSET + (i * item_length) + j + 1); |
|||
if (m_item[i]->label[j] == '\0') |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
menu = (Module_Menu*)Kernel::get()->getModule(MODULE_MENU); |
|||
Kernel::get()->subscribe(this, MODULE_INPUT, MODULE_INPUT_EVENT_PRESS); |
|||
} |
|||
|
|||
void initialize() |
|||
{ |
|||
ui->setDirty(m_hwnd); |
|||
for (int i = 0; i < MENU_SHOW_OPTIONS; i++) |
|||
{ |
|||
ui->setDirty(m_hwnd_menu_option[i]); |
|||
} |
|||
} |
|||
|
|||
void tick(unsigned int signal) |
|||
{ |
|||
char msg[255]; |
|||
Event* e; |
|||
int prev_selected = -1; |
|||
byte scroll_direction = 128; // not const'ing this... 128=middle, 0=up, 255=down
|
|||
while (this->hasEvent()) |
|||
{ |
|||
e = this->popEvent(); |
|||
|
|||
if (ui->getRootWindow() != m_hwnd) continue; |
|||
|
|||
if (e->source == MODULE_INPUT && e->event == MODULE_INPUT_EVENT_PRESS) |
|||
|
|||
|
|||
if (m_waiting_for_menu && (menu->isSelected() || menu->isCancelled())) |
|||
{ |
|||
if ((e->param1 & MODULE_INPUT_BUTTON_UP) != 0) |
|||
{ |
|||
Kernel::debug("Scroll up"); |
|||
prev_selected = m_selected; |
|||
m_selected -= 1; |
|||
if (m_selected < 0) |
|||
m_selected = 0; |
|||
else |
|||
scroll_direction = 0; |
|||
|
|||
} |
|||
if ((e->param1 & MODULE_INPUT_BUTTON_DOWN) != 0) |
|||
{ |
|||
Kernel::debug("Scroll down"); |
|||
prev_selected = m_selected; |
|||
m_selected += 1; |
|||
if (m_item[m_selected] == nullptr) |
|||
m_selected -= 1; |
|||
else |
|||
scroll_direction = 255; |
|||
} |
|||
if ((e->param1 & MODULE_INPUT_BUTTON_OK) != 0) |
|||
if (menu->isSelected()) |
|||
{ |
|||
Kernel::debug("OK"); |
|||
hide(); |
|||
m_result_ok = true; |
|||
return; |
|||
sprintf(msg, "Selected option %d", menu->getSelected()); |
|||
Kernel::debug(msg); |
|||
} |
|||
if ((e->param1 & MODULE_INPUT_BUTTON_BACK) != 0) |
|||
else if (menu->isCancelled()) |
|||
{ |
|||
Kernel::debug("Back"); |
|||
m_result_back = true; |
|||
return; |
|||
Kernel::debug("Menu cancelled!"); |
|||
} |
|||
m_waiting_for_menu = false; |
|||
} |
|||
} |
|||
|
|||
if (scroll_direction == 0 && m_selected < m_view_offset) |
|||
{ |
|||
m_view_offset -= MENU_SHOW_OPTIONS; |
|||
if (m_view_offset < 0) m_view_offset = 0; |
|||
} |
|||
else if (scroll_direction == 255 && m_selected >= m_view_offset + MENU_SHOW_OPTIONS) |
|||
{ |
|||
m_view_offset += MENU_SHOW_OPTIONS; |
|||
} |
|||
|
|||
// if (scroll)
|
|||
// elseif (dirty individual items)
|
|||
|
|||
// Drawing individual menu items is sloooow, let's just refresh everything.
|
|||
/*
|
|||
if (prev_selected >= 0 && m_selected != prev_selected) |
|||
{ |
|||
if (prev_selected - m_view_offset >= 0 && prev_selected - m_view_offset < MENU_MAX_OPTIONS) |
|||
// Hacky, but it'll work for now
|
|||
else if (ui->getRootWindow() == 0 && (e->param1 & MODULE_INPUT_BUTTON_OK) == MODULE_INPUT_BUTTON_OK) |
|||
{ |
|||
ui->setDirty(m_hwnd_menu_option[prev_selected - m_view_offset]); |
|||
sprintf(msg, "Marking dirty idx %d hwnd %d", prev_selected - m_view_offset, m_hwnd_menu_option[prev_selected - m_view_offset]); |
|||
Kernel::debug(msg); |
|||
} |
|||
if (m_selected - m_view_offset >= 0 && m_selected - m_view_offset < MENU_MAX_OPTIONS) |
|||
{ |
|||
ui->setDirty(m_hwnd_menu_option[m_selected - m_view_offset]); |
|||
sprintf(msg, "Marking dirty idx %d hwnd %d", m_selected - m_view_offset, m_hwnd_menu_option[m_selected - m_view_offset]); |
|||
Kernel::debug(msg); |
|||
} |
|||
} |
|||
*/ |
|||
|
|||
if (prev_selected >= 0 && m_selected != prev_selected) |
|||
{ |
|||
ui->setDirty(m_hwnd); |
|||
for (int i = 0; i < MENU_SHOW_OPTIONS; i++) |
|||
{ |
|||
ui->setDirty(m_hwnd_menu_option[i]); |
|||
Kernel::debug("show menu"); |
|||
show(); |
|||
m_waiting_for_menu = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void suspend() |
|||
{ |
|||
eat->write(MENU_EAT_ID, 0, (byte)m_selected); |
|||
eat->write(MENU_EAT_ID, 1, (byte)m_view_offset); |
|||
eat->write(MENU_EAT_ID, 2, (byte)m_prev_root_hwnd); |
|||
|
|||
int item_length = (1 + MENU_MAX_OPTION_LENGTH); |
|||
for (int i = 0; i < MENU_MAX_OPTIONS; i++) |
|||
{ |
|||
if (m_item[i] == nullptr) |
|||
{ |
|||
eat->write(MENU_EAT_ID, MENU_EAT_OFFSET + (i * item_length), 0xFF); |
|||
} |
|||
else |
|||
{ |
|||
eat->write(MENU_EAT_ID, MENU_EAT_OFFSET + (i * item_length), m_item[i]->id); |
|||
for (int j = 0; j < MENU_MAX_OPTION_LENGTH && m_item[i]->label[j] != '\0'; j++) |
|||
{ |
|||
eat->write(MENU_EAT_ID, MENU_EAT_OFFSET + (i * item_length) + j + 1, (byte)(m_item[i]->label[j])); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void draw(int hwnd, int x, int y, int width, int height) |
|||
{ |
|||
if (hwnd == m_hwnd) |
|||
{ |
|||
// Root window
|
|||
ui->getGfx()->fillRect(x, y, width, height, COLOUR_SECONDARY); |
|||
} |
|||
else |
|||
{ |
|||
// Menu option
|
|||
for (int i = 0; i < MENU_SHOW_OPTIONS; i++) |
|||
{ |
|||
if (m_hwnd_menu_option[i] == hwnd) |
|||
{ |
|||
int idx = m_view_offset + i; |
|||
if (m_item[idx] != nullptr) |
|||
{ |
|||
ui->getGfx()->setFont(&FreeMono12pt7b); |
|||
if (idx == m_selected) |
|||
{ |
|||
ui->getGfx()->fillRect(x, y, width, height, COLOUR_PRIMARY); |
|||
ui->getGfx()->setTextColor(COLOUR_SECONDARY); |
|||
} |
|||
else |
|||
{ |
|||
ui->getGfx()->fillRect(x, y, width, height, COLOUR_SECONDARY); |
|||
ui->getGfx()->setTextColor(COLOUR_PRIMARY); |
|||
} |
|||
ui->getGfx()->setCursor(x, y + height - (int)((height - 12) / 2)); |
|||
ui->getGfx()->print(m_item[idx]->label); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void addItem(byte id, char* label) |
|||
{ |
|||
for (int i = 0; i < MENU_MAX_OPTIONS; i++) |
|||
{ |
|||
if (m_item[i] == nullptr) |
|||
{ |
|||
m_item[i] = new MenuItem(); |
|||
m_item[i]->id = id; |
|||
strcpy(m_item[i]->label, label); |
|||
return; |
|||
} |
|||
} |
|||
Kernel::panic("Tried to add more options to menu than MENU_MAX_OPTIONS."); |
|||
|
|||
} |
|||
|
|||
void clear() |
|||
{ |
|||
for (int i = 0; i < MENU_MAX_OPTIONS; i++) |
|||
{ |
|||
if (m_item[i] != nullptr) |
|||
{ |
|||
delete m_item[i]; |
|||
m_item[i] = nullptr; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void show() |
|||
{ |
|||
m_prev_root_hwnd = ui->getRootWindow(); |
|||
ui->setRootWindow(m_hwnd); |
|||
} |
|||
|
|||
void hide() |
|||
{ |
|||
ui->setRootWindow(m_prev_root_hwnd); |
|||
m_prev_root_hwnd = NULL; |
|||
} |
|||
|
|||
bool isSelected() |
|||
{ |
|||
return m_result_ok; |
|||
} |
|||
|
|||
bool isCancelled() |
|||
{ |
|||
return m_result_back; |
|||
} |
|||
|
|||
bool isDone() |
|||
{ |
|||
return m_result_ok || m_result_back; |
|||
} |
|||
|
|||
byte getSelectedId() |
|||
{ |
|||
return m_item[m_selected]->id; |
|||
Kernel::debug("Task_Menu::show"); |
|||
menu->reset(); |
|||
menu->addItem(1, "Option 1"); |
|||
menu->addItem(2, "Option Two"); |
|||
menu->addItem(3, "Option Tres"); |
|||
menu->show(); |
|||
} |
|||
|
|||
}; |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue