diff --git a/watchos2/Module_UI.cpp b/watchos2/Module_UI.cpp index f7704dd..d87b3ff 100644 --- a/watchos2/Module_UI.cpp +++ b/watchos2/Module_UI.cpp @@ -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(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++) diff --git a/watchos2/Module_UI.h b/watchos2/Module_UI.h index 1619231..4e4c5c4 100644 --- a/watchos2/Module_UI.h +++ b/watchos2/Module_UI.h @@ -38,6 +38,7 @@ class Module_UI : public Task, public IRunnable void draw_window(UiWindow* window, int x, int y, int width, int height); void local_to_screen(int* x, int* y); + void get_screen_coordinates(UiWindow* window, int* x, int* y); public: Module_UI(); @@ -53,6 +54,7 @@ public: void do_draw(); void setLayoutMode(kernel_handle_t window_handle, byte layout_mode); + void setAbsolutePosition(kernel_handle_t window_handle, byte x, byte y, byte w, byte h); void setDirty(kernel_handle_t window_handle); int getWidth();