|
|
@ -12,6 +12,8 @@ struct UiWindow |
|
|
|
byte layout_mode; |
|
|
|
UiWindow* parent; |
|
|
|
bool dirty; |
|
|
|
bool needs_draw; |
|
|
|
byte x, y, w, h; |
|
|
|
}; |
|
|
|
|
|
|
|
struct UiFont |
|
|
@ -57,7 +59,6 @@ void Module_UI::start() |
|
|
|
} |
|
|
|
|
|
|
|
m_root = createWindow(WATCHOS_HANDLE_NULL); |
|
|
|
|
|
|
|
module_power = static_cast<Module_Power*>(watchos::module(WATCHOS_MODULE_POWER)); |
|
|
|
} |
|
|
|
|
|
|
@ -81,6 +82,7 @@ kernel_handle_t Module_UI::createWindow(IDrawable* drawable, kernel_handle_t par |
|
|
|
m_window[i]->layout_mode = MODULE_UI_LAYOUT_MODE_NONE; |
|
|
|
m_window[i]->parent = nullptr; |
|
|
|
m_window[i]->dirty = true; |
|
|
|
m_window[i]->needs_draw = false; |
|
|
|
|
|
|
|
if (parent != WATCHOS_HANDLE_NULL) |
|
|
|
{ |
|
|
@ -162,12 +164,47 @@ void Module_UI::do_draw() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: Redraw only parts of the screen if necessary, etc
|
|
|
|
// Also confirm that anything was actually drawn. Could mitigate the risk of extraenous draw calls
|
|
|
|
// from multicore (see above comments in draw())
|
|
|
|
// false does a full invert/etc, true just updates in place and can leave ghosting/etc
|
|
|
|
// do false on a full-screen redraw, false otherwise? trigger a full-screen redraw every certain number of redraws?
|
|
|
|
gfx.display(!m_redraw); |
|
|
|
// Actually figure out what to draw
|
|
|
|
bool whole_screen = false; |
|
|
|
int x, y; |
|
|
|
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|
|
|
{ |
|
|
|
if (m_window[i] != nullptr && m_window[i]->needs_draw) |
|
|
|
{ |
|
|
|
get_screen_coordinates(m_window[i], &x, &y); |
|
|
|
if (x == 0 && y == 0 && m_window[i]->w == DISPLAY_WIDTH && m_window[i]->h == DISPLAY_HEIGHT) |
|
|
|
{ |
|
|
|
whole_screen = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (whole_screen) |
|
|
|
{ |
|
|
|
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|
|
|
{ |
|
|
|
if (m_window[i] != nullptr) |
|
|
|
{ |
|
|
|
m_window[i]->needs_draw = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
gfx.display(!m_redraw); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|
|
|
{ |
|
|
|
if (m_window[i] != nullptr && m_window[i]->needs_draw) |
|
|
|
{ |
|
|
|
get_screen_coordinates(m_window[i], &x, &y); |
|
|
|
gfx.displayWindow(x, y, m_window[i]->w, m_window[i]->h); |
|
|
|
m_window[i]->needs_draw = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
m_redraw = false; |
|
|
|
|
|
|
|
module_power->enableDeepSleep(); |
|
|
@ -181,11 +218,27 @@ void Module_UI::draw_window(UiWindow* window, int x, int y, int width, int heigh |
|
|
|
m_draw_w = width; |
|
|
|
m_draw_h = height; |
|
|
|
|
|
|
|
// Track the last calculated position for this window so we can actually figure out
|
|
|
|
// where to update the screen.
|
|
|
|
if (window->parent != nullptr) |
|
|
|
{ |
|
|
|
window->x = x - window->parent->x; |
|
|
|
window->y = y - window->parent->y; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
window->x = x; |
|
|
|
window->y = y; |
|
|
|
} |
|
|
|
window->w = width; |
|
|
|
window->h = height; |
|
|
|
|
|
|
|
// Draw window
|
|
|
|
if (window->drawable != nullptr && (window->dirty || m_redraw)) |
|
|
|
{ |
|
|
|
window->drawable->draw(window->handle); |
|
|
|
window->dirty = false; |
|
|
|
window->needs_draw = true; |
|
|
|
} |
|
|
|
|
|
|
|
// Count children
|
|
|
@ -238,7 +291,13 @@ void Module_UI::draw_window(UiWindow* window, int x, int y, int width, int heigh |
|
|
|
} |
|
|
|
break; |
|
|
|
case MODULE_UI_LAYOUT_MODE_ABSOLUTE: |
|
|
|
// TODO:
|
|
|
|
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|
|
|
{ |
|
|
|
if (m_window[i] != nullptr && m_window[i]->parent == window) |
|
|
|
{ |
|
|
|
draw_window(m_window[i], x + m_window[i]->x, y + m_window[i]->y, m_window[i]->w, m_window[i]->h); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -256,6 +315,23 @@ void Module_UI::setLayoutMode(kernel_handle_t window_handle, byte layout_mode) |
|
|
|
watchos::panic("Trying to set layout mode on non-existent handle: %#010x", window_handle); |
|
|
|
} |
|
|
|
|
|
|
|
void Module_UI::setAbsolutePosition(kernel_handle_t window_handle, byte x, byte y, byte w, byte h) |
|
|
|
{ |
|
|
|
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|
|
|
{ |
|
|
|
if (m_window[i] != nullptr && m_window[i]->handle == window_handle) |
|
|
|
{ |
|
|
|
m_window[i]->x = x; |
|
|
|
m_window[i]->y = y; |
|
|
|
m_window[i]->w = w; |
|
|
|
m_window[i]->h = h; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
watchos::panic("Trying to set position on non-existent handle: %#010x", window_handle); |
|
|
|
} |
|
|
|
|
|
|
|
void Module_UI::setDirty(kernel_handle_t window_handle) |
|
|
|
{ |
|
|
|
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|
|
@ -283,7 +359,7 @@ int Module_UI::getHeight() |
|
|
|
|
|
|
|
void Module_UI::fill(uint16_t colour) |
|
|
|
{ |
|
|
|
fill(m_draw_x, m_draw_y, m_draw_w, m_draw_h, colour); |
|
|
|
fill(0, 0, m_draw_w, m_draw_h, colour); |
|
|
|
} |
|
|
|
|
|
|
|
void Module_UI::fill(int x, int y, int width, int height, uint16_t colour) |
|
|
@ -328,6 +404,18 @@ void Module_UI::local_to_screen(int* x, int* y) |
|
|
|
*y = m_draw_y + *y; |
|
|
|
} |
|
|
|
|
|
|
|
void Module_UI::get_screen_coordinates(UiWindow* window, int* x, int* y) |
|
|
|
{ |
|
|
|
*x = window->x; |
|
|
|
*y = window->y; |
|
|
|
while (window->parent != nullptr) |
|
|
|
{ |
|
|
|
window = window->parent; |
|
|
|
*x = *x + window->x; |
|
|
|
*y = *y + window->y; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void Module_UI::registerFont(byte id, const void* font) |
|
|
|
{ |
|
|
|
for (int i = 0; i < MODULE_UI_MAX_FONTS; i++) |
|
|
|