|
|
@ -37,11 +37,16 @@ Module_UI::Module_UI() |
|
|
|
} |
|
|
|
|
|
|
|
m_root = createWindow(WATCHOS_HANDLE_NULL); |
|
|
|
m_dirty = true; |
|
|
|
m_redraw = true; |
|
|
|
} |
|
|
|
|
|
|
|
void Module_UI::tick() |
|
|
|
{ |
|
|
|
draw(); |
|
|
|
if (m_dirty) |
|
|
|
{ |
|
|
|
draw(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
kernel_handle_t Module_UI::createWindow(IDrawable* drawable, kernel_handle_t parent) |
|
|
@ -55,7 +60,7 @@ kernel_handle_t Module_UI::createWindow(IDrawable* drawable, kernel_handle_t par |
|
|
|
m_window[i]->handle = watchos::kernel()->allocHandle(WATCHOS_HANDLE_TYPE_UI_WINDOW, m_window[i], (kernel_handle_destructor_t)destruct_window); |
|
|
|
m_window[i]->layout_mode = MODULE_UI_LAYOUT_MODE_NONE; |
|
|
|
m_window[i]->parent = nullptr; |
|
|
|
m_window[i]->dirty = false; |
|
|
|
m_window[i]->dirty = true; |
|
|
|
|
|
|
|
if (parent != WATCHOS_HANDLE_NULL) |
|
|
|
{ |
|
|
@ -93,18 +98,31 @@ kernel_handle_t Module_UI::getRoot() |
|
|
|
|
|
|
|
void Module_UI::draw() |
|
|
|
{ |
|
|
|
#ifdef WATCHOS_UI_MULTICORE |
|
|
|
if (draw_task == nullptr) |
|
|
|
if (m_dirty) |
|
|
|
{ |
|
|
|
xTaskCreatePinnedToCore(draw_wrapper, "Draw", MODULE_UI_MULTICORE_STACK_SIZE, this, 0, &draw_task, 0); |
|
|
|
} |
|
|
|
#ifdef WATCHOS_UI_MULTICORE |
|
|
|
if (draw_task == nullptr) |
|
|
|
{ |
|
|
|
// In multi-core mode we clear this _before_ the draw. That way if anything else is marked dirty during
|
|
|
|
// the draw, we'll be primed to do another draw as soon as this one is complete.
|
|
|
|
// Chances are the thing marked dirty may end up drawn during the on-going call anyway (if it hasn't been
|
|
|
|
// drawn yet) and this will generate a extraenous draw, but that's preferable to _not_ drawing an update
|
|
|
|
// and having out-of-date information on the screen.
|
|
|
|
m_dirty = false; |
|
|
|
xTaskCreatePinnedToCore(draw_wrapper, "Draw", MODULE_UI_MULTICORE_STACK_SIZE, this, 0, &draw_task, 0); |
|
|
|
} |
|
|
|
#else |
|
|
|
do_draw(); |
|
|
|
do_draw(); |
|
|
|
// If we're doing synchronous draws then we know everything is now clean once this completes, so we mark that
|
|
|
|
// we don't need another draw.
|
|
|
|
m_dirty = false; |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void Module_UI::do_draw() |
|
|
|
{ |
|
|
|
watchos::debug("Draw!"); |
|
|
|
// TODO: Disable light/deep sleep
|
|
|
|
|
|
|
|
// Initialize gfx if necessary
|
|
|
@ -124,7 +142,12 @@ void Module_UI::do_draw() |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: Redraw only parts of the screen if necessary, etc
|
|
|
|
gfx.display(true); |
|
|
|
// 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); |
|
|
|
m_redraw = false; |
|
|
|
|
|
|
|
// TODO: Reenable sleep
|
|
|
|
} |
|
|
@ -137,9 +160,10 @@ void Module_UI::draw_window(UiWindow* window, int x, int y, int width, int heigh |
|
|
|
m_draw_h = height; |
|
|
|
|
|
|
|
// Draw window
|
|
|
|
if (window->drawable != nullptr) |
|
|
|
if (window->drawable != nullptr && (window->dirty || m_redraw)) |
|
|
|
{ |
|
|
|
window->drawable->draw(window->handle); |
|
|
|
window->dirty = false; |
|
|
|
} |
|
|
|
|
|
|
|
// Count children
|
|
|
@ -221,6 +245,7 @@ void Module_UI::setDirty(kernel_handle_t window_handle) |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
// TODO: Check if window is actually visible before marking m_dirty
|
|
|
|
watchos::panic("Trying to set dirty non-existent window handle: %#010x", window_handle); |
|
|
|
} |
|
|
|
|
|
|
|