From 5ecb53effe76ce75c7bd34d3363c7f5518f0791d Mon Sep 17 00:00:00 2001 From: Martin Vladic Date: Mon, 6 Dec 2021 14:53:10 +0100 Subject: [PATCH] single widget state buffer --- src/bb3/keyboard.cpp | 31 +- src/bb3/mouse.cpp | 18 +- src/bb3/psu/dlog_view.cpp | 2 +- src/bb3/psu/event_queue.cpp | 2 +- src/bb3/psu/gui/data.cpp | 12 +- src/bb3/psu/gui/file_manager.cpp | 2 +- src/bb3/psu/gui/keypad.cpp | 6 +- src/bb3/psu/gui/keypad.h | 1 - src/bb3/psu/gui/page.cpp | 47 +- src/bb3/psu/gui/page.h | 12 +- src/bb3/psu/gui/psu.cpp | 52 +- src/bb3/psu/gui/psu.h | 2 +- src/eez/gui/app_context.cpp | 58 +- src/eez/gui/app_context.h | 6 +- src/eez/gui/data.h | 9 - src/eez/gui/event.cpp | 25 +- src/eez/gui/gui.cpp | 2 - src/eez/gui/gui.h | 2 - src/eez/gui/overlay.h | 4 +- src/eez/gui/page.h | 4 +- src/eez/gui/update.cpp | 79 ++- src/eez/gui/update.h | 5 +- src/eez/gui/widget.cpp | 245 +++++---- src/eez/gui/widget.h | 62 ++- src/eez/gui/widgets/bar_graph.cpp | 451 ++++++++-------- src/eez/gui/widgets/bar_graph.h | 42 +- src/eez/gui/widgets/bitmap.cpp | 66 +-- src/eez/gui/widgets/bitmap.h | 18 +- src/eez/gui/widgets/button.cpp | 61 ++- src/eez/gui/widgets/button.h | 24 +- src/eez/gui/widgets/button_group.cpp | 26 +- src/eez/gui/widgets/button_group.h | 19 +- src/eez/gui/widgets/canvas.cpp | 27 +- src/eez/gui/widgets/canvas.h | 13 +- src/eez/gui/widgets/containers/app_view.cpp | 33 +- src/eez/gui/widgets/containers/app_view.h | 6 +- src/eez/gui/widgets/containers/container.cpp | 235 ++++---- src/eez/gui/widgets/containers/container.h | 13 +- src/eez/gui/widgets/containers/grid.cpp | 59 +- src/eez/gui/widgets/containers/grid.h | 7 +- .../gui/widgets/containers/layout_view.cpp | 94 ++-- src/eez/gui/widgets/containers/layout_view.h | 10 +- src/eez/gui/widgets/containers/list.cpp | 67 +-- src/eez/gui/widgets/containers/list.h | 7 +- src/eez/gui/widgets/containers/select.cpp | 56 +- src/eez/gui/widgets/containers/select.h | 8 +- src/eez/gui/widgets/display_data.cpp | 164 +++--- src/eez/gui/widgets/display_data.h | 44 +- src/eez/gui/widgets/gauge.cpp | 502 +++++++++--------- src/eez/gui/widgets/gauge.h | 18 +- src/eez/gui/widgets/input.cpp | 75 +-- src/eez/gui/widgets/input.h | 21 +- src/eez/gui/widgets/list_graph.cpp | 176 +++--- src/eez/gui/widgets/list_graph.h | 18 +- src/eez/gui/widgets/multiline_text.cpp | 56 +- src/eez/gui/widgets/multiline_text.h | 16 +- src/eez/gui/widgets/progress.cpp | 67 +-- src/eez/gui/widgets/progress.h | 12 +- src/eez/gui/widgets/rectangle.cpp | 29 +- src/eez/gui/widgets/rectangle.h | 10 +- src/eez/gui/widgets/scroll_bar.cpp | 159 +++--- src/eez/gui/widgets/scroll_bar.h | 20 +- src/eez/gui/widgets/text.cpp | 162 +++--- src/eez/gui/widgets/text.h | 26 +- src/eez/gui/widgets/toggle_button.cpp | 34 +- src/eez/gui/widgets/toggle_button.h | 16 +- src/eez/gui/widgets/up_down.cpp | 65 ++- src/eez/gui/widgets/up_down.h | 16 +- src/eez/gui/widgets/yt_graph.cpp | 141 +++-- src/eez/gui/widgets/yt_graph.h | 70 +-- src/eez/memory.h | 4 +- src/third_party/stm32_cubeide/.cproject | 10 +- 72 files changed, 1907 insertions(+), 2054 deletions(-) diff --git a/src/bb3/keyboard.cpp b/src/bb3/keyboard.cpp index 50c3b7ecb..5da77653d 100644 --- a/src/bb3/keyboard.cpp +++ b/src/bb3/keyboard.cpp @@ -76,10 +76,7 @@ void onKeyDown(uint16_t param) { bool handled = false; if (g_focusWidgetCursor) { - auto widgetState = getWidgetState(g_focusWidgetCursor); - if (widgetState) { - handled = widgetState->onKeyboard(key, mod); - } + handled = g_focusWidgetCursor.currentState->onKeyboard(g_focusWidgetCursor, key, mod); } if (!handled) { @@ -198,9 +195,7 @@ void onKeyboardEvent(SDL_KeyboardEvent *key) { static int g_findFocusCursorState; static WidgetCursor g_focusWidgetCursorIter; -static bool isKeyboardEnabledForWidget(WidgetState *widgetState) { - const WidgetCursor &widgetCursor = widgetState->widgetCursor; - +static bool isKeyboardEnabledForWidget(const WidgetCursor& widgetCursor) { Overlay *overlay = getOverlay(widgetCursor); if (overlay && !overlay->state) { return false; @@ -211,16 +206,15 @@ static bool isKeyboardEnabledForWidget(WidgetState *widgetState) { return true; } - if (widgetState->hasOnKeyboard()) { + if (widgetCursor.currentState->hasOnKeyboard()) { return true; } return false; } -static bool findNextFocusCursor(WidgetState *widgetState) { - const WidgetCursor &widgetCursor = widgetState->widgetCursor; - if (isKeyboardEnabledForWidget(widgetState)) { +static void findNextFocusCursor(const WidgetCursor& widgetCursor) { + if (isKeyboardEnabledForWidget(widgetCursor)) { if (g_findFocusCursorState == 0) { g_focusWidgetCursorIter = widgetCursor; g_findFocusCursorState = 1; @@ -235,15 +229,13 @@ static bool findNextFocusCursor(WidgetState *widgetState) { g_findFocusCursorState = 3; } } - - return true; } static void moveToNextFocusCursor() { g_findFocusCursorState = 0; g_focusWidgetCursorIter = 0; - forEachWidget(&getRootAppContext(), findNextFocusCursor); + forEachWidget(findNextFocusCursor); if (g_findFocusCursorState > 0) { g_focusWidgetCursor = g_focusWidgetCursorIter; @@ -252,9 +244,8 @@ static void moveToNextFocusCursor() { } } -static bool findPreviousFocusCursor(WidgetState *widgetState) { - const WidgetCursor &widgetCursor = widgetState->widgetCursor; - if (isKeyboardEnabledForWidget(widgetState)) { +static void findPreviousFocusCursor(const WidgetCursor& widgetCursor) { + if (isKeyboardEnabledForWidget(widgetCursor)) { if (g_findFocusCursorState == 0) { g_focusWidgetCursorIter = widgetCursor; g_findFocusCursorState = 1; @@ -266,15 +257,13 @@ static bool findPreviousFocusCursor(WidgetState *widgetState) { } } } - - return true; } static void moveToPreviousFocusCursor() { g_findFocusCursorState = 0; g_focusWidgetCursorIter = 0; - - forEachWidget(&getRootAppContext(), findPreviousFocusCursor); + + forEachWidget(findPreviousFocusCursor); if (g_findFocusCursorState > 0) { g_focusWidgetCursor = g_focusWidgetCursorIter; diff --git a/src/bb3/mouse.cpp b/src/bb3/mouse.cpp index 90c93d681..0d90fc4fa 100644 --- a/src/bb3/mouse.cpp +++ b/src/bb3/mouse.cpp @@ -47,13 +47,11 @@ static int g_mouseWasCursorX; static int g_mouseWasCursorY; static WidgetCursor g_foundWidgetAtMouse; -static OnTouchFunctionType g_onTouchFunctionAtMouse; static bool g_lastMouseCursorVisible; static int g_lastMouseCursorX; static int g_lastMouseCursorY; static WidgetCursor g_lastFoundWidgetAtMouse; -static OnTouchFunctionType g_lastOnTouchFunctionAtMouse; MouseInfo g_mouseInfo; @@ -89,8 +87,12 @@ void getEvent(bool &mouseCursorVisible, EventType &mouseEventType, int &mouseX, g_mouseWasCursorX = g_mouseCursorX; g_mouseWasCursorY = g_mouseCursorY; - g_foundWidgetAtMouse = findWidget(&getRootAppContext(), g_mouseCursorX, g_mouseCursorY, false); - g_onTouchFunctionAtMouse = getWidgetTouchFunction(g_foundWidgetAtMouse); + auto foundWidgetAtMouse = findWidget(g_mouseCursorX, g_mouseCursorY, false); + if (getWidgetTouchFunction(foundWidgetAtMouse)) { + g_foundWidgetAtMouse = foundWidgetAtMouse; + } else { + g_foundWidgetAtMouse = 0; + } mouseCursorVisible = true; mouseX = g_mouseCursorX; @@ -101,7 +103,6 @@ void getEvent(bool &mouseCursorVisible, EventType &mouseEventType, int &mouseX, g_mouseWasCursorY = 0; g_foundWidgetAtMouse = 0; - g_onTouchFunctionAtMouse = 0; mouseCursorVisible = false; mouseX = 0; @@ -114,14 +115,12 @@ bool isDisplayDirty() { g_lastMouseCursorVisible != g_mouseCursorVisible || g_lastMouseCursorX != g_mouseCursorX || g_lastMouseCursorY != g_mouseCursorY || - g_lastFoundWidgetAtMouse != g_foundWidgetAtMouse || - g_lastOnTouchFunctionAtMouse != g_onTouchFunctionAtMouse + g_lastFoundWidgetAtMouse != g_foundWidgetAtMouse ) { g_lastMouseCursorVisible = g_mouseCursorVisible; g_lastMouseCursorX = g_mouseCursorX; g_lastMouseCursorY = g_mouseCursorY; g_lastFoundWidgetAtMouse = g_foundWidgetAtMouse; - g_lastOnTouchFunctionAtMouse = g_onTouchFunctionAtMouse; return true; } @@ -153,7 +152,7 @@ void updateDisplay() { image.height = getDisplayHeight() - g_lastMouseCursorY; } - if (g_foundWidgetAtMouse && g_onTouchFunctionAtMouse) { + if (g_foundWidgetAtMouse) { int16_t w; int16_t h; @@ -176,7 +175,6 @@ void updateDisplay() { void onPageChanged() { g_foundWidgetAtMouse = 0; - g_onTouchFunctionAtMouse = 0; } void onMouseXMove(int x) { diff --git a/src/bb3/psu/dlog_view.cpp b/src/bb3/psu/dlog_view.cpp index 924c8146b..b51b0c99c 100644 --- a/src/bb3/psu/dlog_view.cpp +++ b/src/bb3/psu/dlog_view.cpp @@ -40,7 +40,7 @@ #endif #include -#include +#include #include diff --git a/src/bb3/psu/event_queue.cpp b/src/bb3/psu/event_queue.cpp index 3523eace5..c1a1c0413 100644 --- a/src/bb3/psu/event_queue.cpp +++ b/src/bb3/psu/event_queue.cpp @@ -42,7 +42,7 @@ #if OPTION_DISPLAY #include -#include +#include #include #include diff --git a/src/bb3/psu/gui/data.cpp b/src/bb3/psu/gui/data.cpp index 7c47691ed..994a9917f 100644 --- a/src/bb3/psu/gui/data.cpp +++ b/src/bb3/psu/gui/data.cpp @@ -2072,7 +2072,10 @@ void data_no_channel_index(int slotIndex, DataOperationEnum operation, const Wid } void data_slot_channel_index(int slotIndex, Channel *channel, DataOperationEnum operation, const WidgetCursor &widgetCursor, Value &value) { - auto testResult = g_slots[slotIndex]->getTestResult(); + // TODO trtMrt + if (slotIndex == -1) return; + + auto testResult = g_slots[slotIndex]->getTestResult(); if (channel && g_slots[slotIndex]->enabled && (testResult == TEST_OK || testResult == TEST_SKIPPED)) { data_channel_index(*channel, operation, widgetCursor, value); } else { @@ -4119,15 +4122,14 @@ void data_ethernet_dhcp(DataOperationEnum operation, const WidgetCursor &widgetC void data_ethernet_mac(DataOperationEnum operation, const WidgetCursor &widgetCursor, Value &value) { #if OPTION_ETHERNET - static uint8_t s_macAddressData[2][6]; + static uint8_t g_macAddressData[6]; if (operation == DATA_OPERATION_GET) { SysSettingsEthernetPage *page = (SysSettingsEthernetPage *)getPage(PAGE_ID_SYS_SETTINGS_ETHERNET); if (page) { - uint8_t *macAddress = &s_macAddressData[getCurrentStateBufferIndex()][0]; - memcpy(macAddress, page->m_macAddress, 6); - value = MakeMacAddressValue(macAddress); + memcpy(g_macAddressData, page->m_macAddress, 6); + value = MakeMacAddressValue(g_macAddressData); } } #endif diff --git a/src/bb3/psu/gui/file_manager.cpp b/src/bb3/psu/gui/file_manager.cpp index 628242c31..3267b0f1c 100644 --- a/src/bb3/psu/gui/file_manager.cpp +++ b/src/bb3/psu/gui/file_manager.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/src/bb3/psu/gui/keypad.cpp b/src/bb3/psu/gui/keypad.cpp index e6cc30bf1..801cdd6d8 100644 --- a/src/bb3/psu/gui/keypad.cpp +++ b/src/bb3/psu/gui/keypad.cpp @@ -138,9 +138,9 @@ void Keypad::init(AppContext *appContext, const char *label_) { } Value Keypad::getKeypadTextValue() { - char *text = &m_stateText[getCurrentStateBufferIndex()][0]; - getKeypadText(text, sizeof(m_stateText[0])); - return Value(text); + char text[MAX_KEYPAD_TEXT_LENGTH + 2]; + getKeypadText(text, sizeof(text)); + return Value::makeStringRef(text, strlen(text), 0x893cbf99); } void Keypad::getKeypadText(char *text, size_t count) { diff --git a/src/bb3/psu/gui/keypad.h b/src/bb3/psu/gui/keypad.h index 2a9f3fbc5..38cc9342f 100644 --- a/src/bb3/psu/gui/keypad.h +++ b/src/bb3/psu/gui/keypad.h @@ -82,7 +82,6 @@ class Keypad : public Page { protected: AppContext *m_appContext; - char m_stateText[2][MAX_KEYPAD_TEXT_LENGTH + 2]; char m_label[MAX_KEYPAD_LABEL_LENGTH + 1]; char m_keypadText[MAX_KEYPAD_TEXT_LENGTH + 2]; int m_cursorPosition; diff --git a/src/bb3/psu/gui/page.cpp b/src/bb3/psu/gui/page.cpp index d257d776e..cb2e3ff5b 100644 --- a/src/bb3/psu/gui/page.cpp +++ b/src/bb3/psu/gui/page.cpp @@ -135,9 +135,9 @@ void ToastMessagePage::onEncoderClicked() { } } -void ToastMessagePage::updateInternalPage(const WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState) { - WidgetCursor toastPageWidgetCursor(widgetCursor.assets, appContext, &actionWidget, actionWidget.x, actionWidget.y); - if (previousState && actionWidgetIsActive == isActiveWidget(toastPageWidgetCursor)) { +void ToastMessagePage::updateInternalPage(const WidgetCursor &widgetCursor) { + WidgetCursor toastPageWidgetCursor(widgetCursor.assets, appContext, &actionWidget, actionWidget.x, actionWidget.y, widgetCursor.currentState, widgetCursor.hasPreviousState); + if (widgetCursor.hasPreviousState && actionWidgetIsActive == isActiveWidget(toastPageWidgetCursor)) { return; } @@ -284,7 +284,7 @@ void ToastMessagePage::updateInternalPage(const WidgetCursor &widgetCursor, Widg } } -WidgetCursor ToastMessagePage::findWidgetInternalPage(int x, int y, bool clicked) { +WidgetCursor ToastMessagePage::findWidgetInternalPage(const WidgetCursor &widgetCursor, int x, int y, bool clicked) { if (x >= this->x && x < this->x + width && y >= this->y && y < this->y + height) { const Style *style = getStyle(type == INFO_TOAST ? STYLE_ID_INFO_ALERT : STYLE_ID_ERROR_ALERT); font::Font font = styleGetFont(style); @@ -296,10 +296,10 @@ WidgetCursor ToastMessagePage::findWidgetInternalPage(int x, int y, bool clicked y >= (actionWidget.y - textHeight / 4) && y < (actionWidget.y + actionWidget.h - 1 + textHeight / 4) ) { - return WidgetCursor(g_mainAssets, appContext, &actionWidget, actionWidget.x, actionWidget.y); + return WidgetCursor(g_mainAssets, appContext, &actionWidget, actionWidget.x, actionWidget.y, widgetCursor.currentState, widgetCursor.hasPreviousState); } widget.action = ACTION_ID_INTERNAL_DIALOG_CLOSE; - return WidgetCursor(g_mainAssets, appContext, &widget, x, y); + return WidgetCursor(g_mainAssets, appContext, &widget, x, y, widgetCursor.currentState, widgetCursor.hasPreviousState); } return WidgetCursor(); @@ -486,8 +486,8 @@ void SelectFromEnumPage::findPagePosition() { } } -void SelectFromEnumPage::updateInternalPage(const WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState) { - if (previousState && !dirty) { +void SelectFromEnumPage::updateInternalPage(const WidgetCursor &widgetCursor) { + if (widgetCursor.hasPreviousState && !dirty) { return; } @@ -512,7 +512,7 @@ void SelectFromEnumPage::updateInternalPage(const WidgetCursor &widgetCursor, Wi dirty = false; } -WidgetCursor SelectFromEnumPage::findWidgetInternalPage(int x, int y, bool clicked) { +WidgetCursor SelectFromEnumPage::findWidgetInternalPage(const WidgetCursor &widgetCursor, int x, int y, bool clicked) { for (int i = 0; i < numItems; ++i) { int xItem, yItem; getItemPosition(i, xItem, yItem); @@ -527,7 +527,7 @@ WidgetCursor SelectFromEnumPage::findWidgetInternalPage(int x, int y, bool click widget.action = ACTION_ID_INTERNAL_SELECT_ENUM_ITEM; widget.data = (uint16_t)i; - return WidgetCursor(g_mainAssets, appContext, &widget, x, y); + return WidgetCursor(g_mainAssets, appContext, &widget, x, y, widgetCursor.currentState, widgetCursor.hasPreviousState); } } } @@ -663,26 +663,25 @@ void MenuWithButtonsPage::init(AppContext *appContext, const char *message, cons } -void MenuWithButtonsPage::updateInternalPage(const WidgetCursor &widgetCursor2, WidgetState *currentState, WidgetState *previousState) { +void MenuWithButtonsPage::updateInternalPage(const WidgetCursor &widgetCursor2) { WidgetCursor widgetCursor; widgetCursor.appContext = m_appContext; - if (!previousState) { + if (!widgetCursor2.hasPreviousState) { widgetCursor.widget = &m_containerRectangleWidget; widgetCursor.x = x + m_containerRectangleWidget.x; widgetCursor.y = y + m_containerRectangleWidget.y; - currentState->flags.active = 0; - - RectangleWidgetState rectangleWidgetState(widgetCursor); - rectangleWidgetState.draw(previousState); + RectangleWidgetState rectangleWidgetState; + rectangleWidgetState.flags.active = 0; + rectangleWidgetState.render(widgetCursor); widgetCursor.widget = &m_messageTextWidget; widgetCursor.x = x + m_messageTextWidget.x; widgetCursor.y = y + m_messageTextWidget.y; - currentState->flags.active = 0; - TextWidgetState textWidgetState(widgetCursor); - textWidgetState.draw(previousState); + TextWidgetState textWidgetState; + textWidgetState.flags.active = 0; + textWidgetState.render(widgetCursor); } for (size_t i = 0; i < m_numButtonTextWidgets; i++) { @@ -690,14 +689,14 @@ void MenuWithButtonsPage::updateInternalPage(const WidgetCursor &widgetCursor2, widgetCursor.x = x + m_buttonTextWidgets[i].x; widgetCursor.y = y + m_buttonTextWidgets[i].y; widgetCursor.cursor = i; - currentState->flags.active = isActiveWidget(widgetCursor); - TextWidgetState textWidgetState(widgetCursor); - textWidgetState.draw(previousState); + TextWidgetState textWidgetState; + textWidgetState.flags.active = isActiveWidget(widgetCursor); + textWidgetState.render(widgetCursor); } } -WidgetCursor MenuWithButtonsPage::findWidgetInternalPage(int x, int y, bool clicked) { - WidgetCursor widgetCursor; +WidgetCursor MenuWithButtonsPage::findWidgetInternalPage(const WidgetCursor &widgetCursor2, int x, int y, bool clicked) { + WidgetCursor widgetCursor = widgetCursor2; widgetCursor.appContext = m_appContext; diff --git a/src/bb3/psu/gui/page.h b/src/bb3/psu/gui/page.h index ddde1658e..24d8cfa39 100644 --- a/src/bb3/psu/gui/page.h +++ b/src/bb3/psu/gui/page.h @@ -51,8 +51,8 @@ class ToastMessagePage : public InternalPage { void onEncoder(int counter); void onEncoderClicked(); - void updateInternalPage(const WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState); - WidgetCursor findWidgetInternalPage(int x, int y, bool clicked); + void updateInternalPage(const WidgetCursor &widgetCursor); + WidgetCursor findWidgetInternalPage(const WidgetCursor &widgetCursor, int x, int y, bool clicked); bool canClickPassThrough(); bool hasAction() { @@ -108,8 +108,8 @@ class SelectFromEnumPage : public InternalPage { void init(); - void updateInternalPage(const WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState); - WidgetCursor findWidgetInternalPage(int x, int y, bool clicked); + void updateInternalPage(const WidgetCursor &widgetCursor); + WidgetCursor findWidgetInternalPage(const WidgetCursor &widgetCursor, int x, int y, bool clicked); void selectEnumItem(); @@ -165,8 +165,8 @@ class MenuWithButtonsPage : public InternalPage { public: static MenuWithButtonsPage *create(AppContext *appContext, const char *message, const char **menuItems, void (*callback)(int)); - void updateInternalPage(const WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState); - WidgetCursor findWidgetInternalPage(int x, int y, bool clicked); + void updateInternalPage(const WidgetCursor &widgetCursor); + WidgetCursor findWidgetInternalPage(const WidgetCursor &widgetCursor, int x, int y, bool clicked); static void executeAction(); diff --git a/src/bb3/psu/gui/psu.cpp b/src/bb3/psu/gui/psu.cpp index 4783d6f6f..2bc631c12 100644 --- a/src/bb3/psu/gui/psu.cpp +++ b/src/bb3/psu/gui/psu.cpp @@ -1149,8 +1149,8 @@ bool PsuAppContext::canExecuteActionWhenTouchedOutsideOfActivePage(int pageId, i return false; } -void PsuAppContext::updatePage(int i, WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState) { - AppContext::updatePage(i, widgetCursor, currentState, previousState); +void PsuAppContext::updatePage(int i, WidgetCursor &widgetCursor) { + AppContext::updatePage(i, widgetCursor); if (getActivePageId() == PAGE_ID_TOUCH_CALIBRATION_YES_NO || getActivePageId() == PAGE_ID_TOUCH_CALIBRATION_YES_NO_CANCEL) { auto eventType = touch::getEventType(); @@ -1162,21 +1162,23 @@ void PsuAppContext::updatePage(int i, WidgetCursor &widgetCursor, WidgetState *c eez::display::fillRect(x - 1, y - 1, x + 1, y + 1); } } else if (getActivePageId() == PAGE_ID_TOUCH_TEST) { - display::selectBuffer(m_pageNavigationStack[i].displayBufferIndex); - - if (get(widgetCursor, DATA_ID_TOUCH_CALIBRATED_PRESSED).getInt()) { - int x = MIN(MAX(get(widgetCursor, DATA_ID_TOUCH_CALIBRATED_X).getInt(), 1), eez::display::getDisplayWidth() - 2); - int y = MIN(MAX(get(widgetCursor, DATA_ID_TOUCH_CALIBRATED_Y).getInt(), 1), eez::display::getDisplayHeight() - 2); - eez::display::setColor(0, 0, 255); - eez::display::fillRect(x - 1, y - 1, x + 1, y + 1); - } + if (g_findCallback == nullptr) { + display::selectBuffer(m_pageNavigationStack[i].displayBufferIndex); + + if (get(widgetCursor, DATA_ID_TOUCH_CALIBRATED_PRESSED).getInt()) { + int x = MIN(MAX(get(widgetCursor, DATA_ID_TOUCH_CALIBRATED_X).getInt(), 1), eez::display::getDisplayWidth() - 2); + int y = MIN(MAX(get(widgetCursor, DATA_ID_TOUCH_CALIBRATED_Y).getInt(), 1), eez::display::getDisplayHeight() - 2); + eez::display::setColor(0, 0, 255); + eez::display::fillRect(x - 1, y - 1, x + 1, y + 1); + } - if (get(widgetCursor, DATA_ID_TOUCH_FILTERED_PRESSED).getInt()) { - int x = MIN(MAX(get(widgetCursor, DATA_ID_TOUCH_FILTERED_X).getInt(), 1), eez::display::getDisplayWidth() - 2); - int y = MIN(MAX(get(widgetCursor, DATA_ID_TOUCH_FILTERED_Y).getInt(), 1), eez::display::getDisplayHeight() - 2); - eez::display::setColor(0, 255, 0); - eez::display::fillRect(x - 1, y - 1, x + 1, y + 1); - } + if (get(widgetCursor, DATA_ID_TOUCH_FILTERED_PRESSED).getInt()) { + int x = MIN(MAX(get(widgetCursor, DATA_ID_TOUCH_FILTERED_X).getInt(), 1), eez::display::getDisplayWidth() - 2); + int y = MIN(MAX(get(widgetCursor, DATA_ID_TOUCH_FILTERED_Y).getInt(), 1), eez::display::getDisplayHeight() - 2); + eez::display::setColor(0, 255, 0); + eez::display::fillRect(x - 1, y - 1, x + 1, y + 1); + } + } } } @@ -1518,8 +1520,7 @@ static bool isEncoderEnabledForWidget(const WidgetCursor &widgetCursor) { static bool g_focusCursorIsEnabled; static int16_t g_focusCursorAction; -bool isEnabledFocusCursorStep(WidgetState *widgetState) { - const WidgetCursor &widgetCursor = widgetState->widgetCursor; +void isEnabledFocusCursorStep(const WidgetCursor &widgetCursor) { if (isEncoderEnabledForWidget(widgetCursor)) { if (g_focusCursor == widgetCursor && g_focusDataId == widgetCursor.widget->data) { g_focusCursorIsEnabled = true; @@ -1527,30 +1528,27 @@ bool isEnabledFocusCursorStep(WidgetState *widgetState) { g_focusCursorAction = action; } } - return true; } bool isEnabledFocusCursor(const WidgetCursor& cursor, int16_t dataId) { g_focusCursorIsEnabled = false; g_focusCursorAction = ACTION_ID_NONE; - forEachWidget(&g_psuAppContext, isEnabledFocusCursorStep); + forEachWidget(isEnabledFocusCursorStep); return g_focusCursorIsEnabled; } -bool isEncoderEnabledInActivePageCheckWidget(WidgetState *widgetState) { - const WidgetCursor &widgetCursor = widgetState->widgetCursor; +void isEncoderEnabledInActivePageCheckWidget(const WidgetCursor &widgetCursor) { if (widgetCursor.isPage()) { g_isEncoderEnabledInActivePage = false; } else if (isEncoderEnabledForWidget(widgetCursor)) { g_isEncoderEnabledInActivePage = true; } - return true; } void testIsEncoderEnabledInActivePage() { // encoder is enabled if active page contains widget with "edit" action g_isEncoderEnabledInActivePage = false; - forEachWidget(&g_psuAppContext, isEncoderEnabledInActivePageCheckWidget); + forEachWidget(isEncoderEnabledInActivePageCheckWidget); } bool isEncoderEnabledInActivePage() { @@ -1859,8 +1857,7 @@ static int g_findNextFocusCursorState = 0; static WidgetCursor g_nextFocusCursor = 0; static uint16_t g_nextFocusDataId = DATA_ID_CHANNEL_U_EDIT; -bool findNextFocusCursor(WidgetState *widgetState) { - const WidgetCursor &widgetCursor = widgetState->widgetCursor; +void findNextFocusCursor(const WidgetCursor &widgetCursor) { if (isEncoderEnabledForWidget(widgetCursor)) { if (g_findNextFocusCursorState == 0) { g_nextFocusCursor = widgetCursor; @@ -1878,12 +1875,11 @@ bool findNextFocusCursor(WidgetState *widgetState) { g_findNextFocusCursorState = 3; } } - return true; } static void moveToNextFocusCursor() { g_findNextFocusCursorState = 0; - forEachWidget(&g_psuAppContext, findNextFocusCursor); + forEachWidget(findNextFocusCursor); if (g_findNextFocusCursorState > 0) { g_focusCursor = g_nextFocusCursor; g_focusDataId = g_nextFocusDataId; diff --git a/src/bb3/psu/gui/psu.h b/src/bb3/psu/gui/psu.h index b5ea4159a..ca0e076d0 100644 --- a/src/bb3/psu/gui/psu.h +++ b/src/bb3/psu/gui/psu.h @@ -285,7 +285,7 @@ class PsuAppContext : public AppContext { void onPageTouch(const WidgetCursor &foundWidget, Event &touchEvent) override; bool testExecuteActionOnTouchDown(int action) override; bool canExecuteActionWhenTouchedOutsideOfActivePage(int pageId, int action) override; - void updatePage(int i, WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState) override; + void updatePage(int i, WidgetCursor &widgetCursor) override; private: void doShowProgressPage(); diff --git a/src/eez/gui/app_context.cpp b/src/eez/gui/app_context.cpp index 185092676..3df4c208d 100644 --- a/src/eez/gui/app_context.cpp +++ b/src/eez/gui/app_context.cpp @@ -270,15 +270,16 @@ void AppContext::onPageTouch(const WidgetCursor &foundWidget, Event &touchEvent) if (!pointInsideRect(touchEvent.x, touchEvent.y, foundWidget.appContext->rect.x + page->x, foundWidget.appContext->rect.y + page->y, page->w, page->h)) { int activePageId = getActivePageId(); + // clicked outside page, close page popPage(); - auto widgetCursor = findWidget(&getRootAppContext(), touchEvent.x, touchEvent.y); + auto widgetCursor = findWidget(touchEvent.x, touchEvent.y); if (widgetCursor.widget) { - auto action = getWidgetAction(widgetCursor); - if (action != ACTION_ID_NONE && canExecuteActionWhenTouchedOutsideOfActivePage(activePageId, action)) { - eventHandling(); - } + auto action = getWidgetAction(widgetCursor); + if (action != ACTION_ID_NONE && canExecuteActionWhenTouchedOutsideOfActivePage(activePageId, action)) { + eventHandling(); + } } } } @@ -287,13 +288,14 @@ void AppContext::onPageTouch(const WidgetCursor &foundWidget, Event &touchEvent) //////////////////////////////////////////////////////////////////////////////// -void AppContext::updatePage(int i, WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState) { - if (!previousState || m_pageNavigationStack[i].displayBufferIndex == -1) { - m_pageNavigationStack[i].displayBufferIndex = display::allocBuffer(); - previousState = nullptr; - } +void AppContext::updatePage(int i, WidgetCursor &widgetCursor) { + if (g_findCallback == nullptr) { + if (!widgetCursor.hasPreviousState) { + m_pageNavigationStack[i].displayBufferIndex = display::allocBuffer(); + } - display::selectBuffer(m_pageNavigationStack[i].displayBufferIndex); + display::selectBuffer(m_pageNavigationStack[i].displayBufferIndex); + } auto savedPageNavigationStackPointer = m_pageNavigationStackPointer; m_pageNavigationStackPointer = i; @@ -307,29 +309,35 @@ void AppContext::updatePage(int i, WidgetCursor &widgetCursor, WidgetState *curr if (isPageInternal(m_pageNavigationStack[i].pageId)) { auto internalPage = ((InternalPage *)m_pageNavigationStack[i].page); - x = internalPage->x; - y = internalPage->y; - width = internalPage->width; - height = internalPage->height; - withShadow = true; + x = internalPage->x; + y = internalPage->y; + width = internalPage->width; + height = internalPage->height; + withShadow = true; - internalPage->updateInternalPage(widgetCursor, currentState, previousState); + if (g_findCallback == nullptr) { + internalPage->updateInternalPage(widgetCursor); + } - enumNoneWidget(widgetCursor, currentState, previousState); + enumNoneWidget(widgetCursor); } else { auto page = getPageAsset(m_pageNavigationStack[i].pageId, widgetCursor); - x = widgetCursor.x + page->x; - y = widgetCursor.y + page->y; - width = page->w; - height = page->h; - withShadow = page->x > 0; + x = widgetCursor.x + page->x; + y = widgetCursor.y + page->y; + width = page->w; + height = page->h; + withShadow = page->x > 0; + auto savedWidget = widgetCursor.widget; widgetCursor.widget = page; - enumWidget(widgetCursor, currentState, previousState); + enumWidget(widgetCursor); + widgetCursor.widget = savedWidget; } - display::setBufferBounds(m_pageNavigationStack[i].displayBufferIndex, x, y, width, height, withShadow, 255, 0, 0, withShadow && activePageHasBackdropHook() ? &rect : nullptr); + if (g_findCallback == nullptr) { + display::setBufferBounds(m_pageNavigationStack[i].displayBufferIndex, x, y, width, height, withShadow, 255, 0, 0, withShadow && activePageHasBackdropHook() ? &rect : nullptr); + } m_pageNavigationStackPointer = savedPageNavigationStackPointer; } diff --git a/src/eez/gui/app_context.h b/src/eez/gui/app_context.h index 2d49b8f67..aaf86d9ae 100644 --- a/src/eez/gui/app_context.h +++ b/src/eez/gui/app_context.h @@ -87,8 +87,6 @@ class AppContext { virtual bool isWidgetActionEnabled(const WidgetCursor &widgetCursor); - void updateAppView(WidgetCursor &widgetCursor); - virtual int getLongTouchActionHook(const WidgetCursor &widgetCursor); virtual int getExtraLongTouchActionHook(const WidgetCursor &widgetCursor); @@ -107,8 +105,8 @@ class AppContext { void doShowPage(int index, Page *page, int previousPageId); void setPage(int pageId); - virtual void updatePage(int i, WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState); - + virtual void updatePage(int i, WidgetCursor &widgetCursor); + bool isPageFullyCovered(int pageNavigationStackIndex); virtual bool canExecuteActionWhenTouchedOutsideOfActivePage(int pageId, int action); diff --git a/src/eez/gui/data.h b/src/eez/gui/data.h index 5b8d35298..b504dddf7 100644 --- a/src/eez/gui/data.h +++ b/src/eez/gui/data.h @@ -231,15 +231,6 @@ struct Value { pVoidValue = 0; } - void freeRef() { - if (options & VALUE_OPTIONS_REF) { - if (--refValue->refCounter == 0) { - free(refValue); - } - clear(); - } - } - const Value& operator = (const Value &value) { if (options & VALUE_OPTIONS_REF) { if (--refValue->refCounter == 0) { diff --git a/src/eez/gui/event.cpp b/src/eez/gui/event.cpp index db0c160da..42643a91c 100644 --- a/src/eez/gui/event.cpp +++ b/src/eez/gui/event.cpp @@ -59,17 +59,18 @@ void eventHandling() { return; } + touch::tick(); + + auto eventType = touch::getEventType(); + bool mouseCursorVisible = false; EventType mouseEventType = EVENT_TYPE_TOUCH_NONE; int mouseX = 0; int mouseY = 0; - #if OPTION_MOUSE mouse::getEvent(mouseCursorVisible, mouseEventType, mouseX, mouseY); #endif - auto eventType = touch::getEventType(); - int eventX; int eventY; if (eventType == EVENT_TYPE_TOUCH_NONE && mouseCursorVisible) { @@ -120,7 +121,7 @@ void eventHandling() { static void processTouchEvent(EventType type, int x, int y) { if (type == EVENT_TYPE_TOUCH_DOWN) { - m_foundWidgetAtDown = findWidget(&getRootAppContext(), x, y); + m_foundWidgetAtDown = findWidget(x, y); m_onTouchFunction = getWidgetTouchFunction(m_foundWidgetAtDown); if (!m_onTouchFunction) { m_onTouchFunction = onPageTouch; @@ -140,10 +141,7 @@ static void processTouchEvent(EventType type, int x, int y) { } static void onWidgetTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { - auto widgetState = getWidgetState(widgetCursor); - if (widgetState) { - widgetState->onTouch(touchEvent); - } + widgetCursor.currentState->onTouch(widgetCursor, touchEvent); } OnTouchFunctionType getWidgetTouchFunction(const WidgetCursor &widgetCursor) { @@ -153,11 +151,8 @@ OnTouchFunctionType getWidgetTouchFunction(const WidgetCursor &widgetCursor) { return nullptr; } - auto widgetState = getWidgetState(widgetCursor); - if (widgetState) { - if (widgetState->hasOnTouch()) { - return onWidgetTouch; - } + if (widgetCursor.currentState->hasOnTouch()) { + return onWidgetTouch; } if (widgetCursor.appContext->isWidgetActionEnabled(widgetCursor)) { @@ -171,7 +166,9 @@ OnTouchFunctionType getWidgetTouchFunction(const WidgetCursor &widgetCursor) { } static void onPageTouch(const WidgetCursor &foundWidget, Event &touchEvent) { - foundWidget.appContext->onPageTouch(foundWidget, touchEvent); + if (foundWidget) { + foundWidget.appContext->onPageTouch(foundWidget, touchEvent); + } } static void onWidgetDefaultTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { diff --git a/src/eez/gui/gui.cpp b/src/eez/gui/gui.cpp index 04d128cf0..0f076d39f 100644 --- a/src/eez/gui/gui.cpp +++ b/src/eez/gui/gui.cpp @@ -50,8 +50,6 @@ void guiTick() { g_wasBlinkTime = g_isBlinkTime; g_isBlinkTime = (millis() % (2 * CONF_GUI_BLINK_TIME)) > CONF_GUI_BLINK_TIME; - touch::tick(); - eventHandling(); stateManagmentHook(); diff --git a/src/eez/gui/gui.h b/src/eez/gui/gui.h index b6d7669e5..c4d725345 100644 --- a/src/eez/gui/gui.h +++ b/src/eez/gui/gui.h @@ -71,8 +71,6 @@ void executeAction(int actionId); int16_t getAppContextId(AppContext *pAppContext); AppContext *getAppContextFromId(int16_t id); -int getCurrentStateBufferIndex(); - //////////////////////////////////////////////////////////////////////////////// enum Buffer { diff --git a/src/eez/gui/overlay.h b/src/eez/gui/overlay.h index eef85ecbf..271817199 100644 --- a/src/eez/gui/overlay.h +++ b/src/eez/gui/overlay.h @@ -64,7 +64,9 @@ bool isOverlay(const WidgetCursor &widgetCursor); Overlay *getOverlay(const WidgetCursor &widgetCursor); void getOverlayOffset(const WidgetCursor &widgetCursor, int &xOffset, int &yOffset); void dragOverlay(Event &touchEvent); -void overlayEnumWidgetHook(WidgetCursor &widgetCursor, EnumWidgetsCallback callback); + +extern int g_xOverlayOffset; +extern int g_yOverlayOffset; } // namespace gui } // namespace eez \ No newline at end of file diff --git a/src/eez/gui/page.h b/src/eez/gui/page.h index ae0665d32..a0e4a37f4 100644 --- a/src/eez/gui/page.h +++ b/src/eez/gui/page.h @@ -55,8 +55,8 @@ class SetPage : public Page { class InternalPage : public Page { public: - virtual void updateInternalPage(const WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState) = 0; - virtual WidgetCursor findWidgetInternalPage(int x, int y, bool clicked) = 0; + virtual void updateInternalPage(const WidgetCursor &widgetCursor) = 0; + virtual WidgetCursor findWidgetInternalPage(const WidgetCursor &widgetCursor, int x, int y, bool clicked) = 0; virtual bool canClickPassThrough(); int x; diff --git a/src/eez/gui/update.cpp b/src/eez/gui/update.cpp index 3e17dc01d..3c38fc00d 100644 --- a/src/eez/gui/update.cpp +++ b/src/eez/gui/update.cpp @@ -19,61 +19,82 @@ #include #include -#include +#include namespace eez { namespace gui { static uint8_t g_stateBuffer[GUI_STATE_BUFFER_SIZE]; -static WidgetState *g_previousState; -WidgetState *g_currentState; static bool g_refreshScreen; +static Widget *g_rootWidget; -int getCurrentStateBufferIndex() { - return (uint8_t *)g_currentState == g_stateBuffer ? 0 : 1; -} +WidgetState *g_widgetStateStart; +WidgetState *g_widgetStateEnd; void refreshScreen() { - g_refreshScreen = true; + g_refreshScreen = true; } void updateScreen() { - if (g_refreshScreen) { - g_refreshScreen = false; + if (!g_rootWidget) { + static AppViewWidget g_rootAppViewWidget; + + g_rootWidget = &g_rootAppViewWidget; + + g_rootWidget->type = WIDGET_TYPE_APP_VIEW; + g_rootWidget->data = DATA_ID_NONE; + g_rootWidget->action = ACTION_ID_NONE; + g_rootWidget->x = 0; + g_rootWidget->y = 0; + g_rootWidget->w = display::getDisplayWidth(); + g_rootWidget->h = display::getDisplayHeight(); + g_rootWidget->style = 0; + } - if (g_currentState != nullptr) { - freeWidgetStates(g_currentState); - g_currentState = nullptr; + if (g_refreshScreen) { + g_refreshScreen = false; + + if (g_widgetStateStart) { + // invalidate widget states + freeWidgetStates(g_widgetStateStart); + g_widgetStateStart = nullptr; } display::freeAllBuffers(); - } + } + + bool hasPreviousState = g_widgetStateStart != nullptr; + g_widgetStateStart = (WidgetState *)g_stateBuffer; g_isActiveWidget = false; - if (g_previousState) { - freeWidgetStates(g_previousState); - } + WidgetCursor widgetCursor; + widgetCursor.assets = g_mainAssets; + widgetCursor.appContext = &getRootAppContext(); + widgetCursor.widget = g_rootWidget; + widgetCursor.currentState = g_widgetStateStart; + widgetCursor.hasPreviousState = hasPreviousState; - g_previousState = g_currentState; - g_currentState = (WidgetState *)(g_stateBuffer + CONF_MAX_STATE_SIZE * (getCurrentStateBufferIndex() == 0 ? 1 : 0));; + enumWidget(widgetCursor); + + g_widgetStateEnd = widgetCursor.currentState; +} - static AppViewWidget widget; - widget.type = WIDGET_TYPE_APP_VIEW; - widget.data = DATA_ID_NONE; - widget.action = ACTION_ID_NONE; - widget.x = 0; - widget.y = 0; - widget.w = display::getDisplayWidth(); - widget.h = display::getDisplayHeight(); - widget.style = 0; +void enumRootWidget() { + if (!g_widgetStateStart || g_refreshScreen) { + return; + } + + g_isActiveWidget = false; WidgetCursor widgetCursor; widgetCursor.assets = g_mainAssets; widgetCursor.appContext = &getRootAppContext(); - widgetCursor.widget = &widget; + widgetCursor.widget = g_rootWidget; + widgetCursor.currentState = g_widgetStateStart; + widgetCursor.hasPreviousState = true; - enumWidget(widgetCursor, g_currentState, g_previousState); + enumWidget(widgetCursor); } } // namespace gui diff --git a/src/eez/gui/update.h b/src/eez/gui/update.h index f0134e27f..5fadb5a8a 100644 --- a/src/eez/gui/update.h +++ b/src/eez/gui/update.h @@ -21,9 +21,12 @@ namespace eez { namespace gui { -extern WidgetState *g_currentState; +extern WidgetState *g_widgetStateStart; +extern WidgetState *g_widgetStateEnd; void updateScreen(); +void enumRootWidget(); + } // namespace gui } // namespace eez \ No newline at end of file diff --git a/src/eez/gui/widget.cpp b/src/eez/gui/widget.cpp index d5f137c1c..ea3ce35de 100644 --- a/src/eez/gui/widget.cpp +++ b/src/eez/gui/widget.cpp @@ -27,25 +27,26 @@ #include #include -#include +#include +#include +#include +#include +#include +#include + #include #include #include #include #include -#include #include #include -#include #include -#include #include -#include #include #include #include #include -#include #include #include #include @@ -57,77 +58,65 @@ namespace gui { //////////////////////////////////////////////////////////////////////////////// bool g_isActiveWidget; +EnumWidgetsCallback g_findCallback; //////////////////////////////////////////////////////////////////////////////// struct NoneWidgetState : public WidgetState { - NoneWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } + void render(WidgetCursor &widgetCursor) {} }; +static Widget g_noneWidget = { WIDGET_TYPE_NONE }; + struct ReservedWidgetState : public WidgetState { - ReservedWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } + void render(WidgetCursor &widgetCursor) {} }; +// widget placementNew functions #define WIDGET_TYPE(NAME_PASCAL_CASE, NAME, ID) \ -void NAME##placementNew(void *ptr, const WidgetCursor& widgetCursor) { new (ptr) NAME_PASCAL_CASE##WidgetState(widgetCursor); } +void NAME##_placementNew(void *ptr) { new (ptr) NAME_PASCAL_CASE##WidgetState(); } WIDGET_TYPES #undef WIDGET_TYPE -typedef void (*WidgetStatePlacementNewFunctionType)(void *ptr, const WidgetCursor& widgetCursor); +typedef void (*WidgetStatePlacementNewFunctionType)(void *ptr); -#define WIDGET_TYPE(NAME_PASCAL_CASE, NAME, ID) NAME##placementNew, +#define WIDGET_TYPE(NAME_PASCAL_CASE, NAME, ID) NAME##_placementNew, static WidgetStatePlacementNewFunctionType g_widgetStatePlacementNewFunctions[] = { WIDGET_TYPES }; #undef WIDGET_TYPE +// widget state sizes #define WIDGET_TYPE(NAME_PASCAL_CASE, NAME, ID) sizeof(NAME_PASCAL_CASE##WidgetState), -static size_t g_widgetStateSize[] = { +static size_t g_widgetStateSizes[] = { WIDGET_TYPES }; #undef WIDGET_TYPE //////////////////////////////////////////////////////////////////////////////// -WidgetCursor WidgetState::getFirstChildWidgetCursor(WidgetCursor &widgetCursor, WidgetState *¤tState, WidgetState *&previousState) { - auto widgetStateSize = g_widgetStateSize[widgetCursor.widget->type]; - - if (previousState) { - previousState = (WidgetState *)((uint8_t *)previousState + widgetStateSize); +bool WidgetState::updateState(const WidgetCursor &widgetCursor) { + return false; } - currentState = (WidgetState *)((uint8_t *)currentState + widgetStateSize); - - // - uint32_t stateSize = (uint8_t *)currentState - (uint8_t *)g_currentState; - assert(stateSize <= CONF_MAX_STATE_SIZE); - - return widgetCursor; +void WidgetState::render(WidgetCursor &widgetCursor) { } -void WidgetState::draw(WidgetState *previousState) { - const Widget *widget = widgetCursor.widget; - - bool refresh = !previousState || previousState->flags.active != flags.active; - if (refresh) { - drawRectangle(widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, getStyle(widget->style), flags.active, false, true); - } +void WidgetState::enumChildren(WidgetCursor &widgetCursor) { } bool WidgetState::hasOnTouch() { return false; } -void WidgetState::onTouch(Event &touchEvent) { +void WidgetState::onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { } bool WidgetState::hasOnKeyboard() { return false; } -bool WidgetState::onKeyboard(uint8_t key, uint8_t mod) { +bool WidgetState::onKeyboard(const WidgetCursor &widgetCursor, uint8_t key, uint8_t mod) { return false; } @@ -139,148 +128,153 @@ bool WidgetCursor::isPage() const { //////////////////////////////////////////////////////////////////////////////// -void enumWidget(WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState) { +void enumWidget(WidgetCursor &widgetCursor) { const Widget *widget = widgetCursor.widget; - bool savedIsActiveWidget = g_isActiveWidget; - g_isActiveWidget = g_isActiveWidget || isActiveWidget(widgetCursor); + auto savedX = widgetCursor.x; + auto savedY = widgetCursor.y; + + widgetCursor.x += widget->x; + widgetCursor.y += widget->y; + + auto widgetState = widgetCursor.currentState; + + bool savedIsActiveWidget = g_isActiveWidget; + g_isActiveWidget = g_isActiveWidget || isActiveWidget(widgetCursor); + + if (g_findCallback) { + g_findCallback(widgetCursor); + } else { + if (widgetCursor.hasPreviousState && widget->type == widgetState->type) { + if (widgetState->updateState(widgetCursor)) { + widgetState->render(widgetCursor); + } + } + else { + if (widgetCursor.hasPreviousState) { + freeWidgetStates(widgetState); + widgetCursor.hasPreviousState = false; + } + g_widgetStatePlacementNewFunctions[widget->type](widgetState); + widgetState->type = widget->type; + + widgetState->updateState(widgetCursor); + widgetState->render(widgetCursor); + } + } - auto widgetState = currentState; + widgetCursor.currentState = (WidgetState *)((uint8_t *)widgetCursor.currentState + g_widgetStateSizes[widget->type]); - g_widgetStatePlacementNewFunctions[widget->type](widgetState, widgetCursor); + uint32_t stateSize = (uint8_t *)widgetCursor.currentState - (uint8_t *)g_widgetStateStart; + assert(stateSize <= CONF_MAX_STATE_SIZE); - widgetState->widgetStateSize = g_widgetStateSize[widget->type]; - widgetState->widgetCursor.x += widget->x; - widgetState->widgetCursor.y += widget->y; + widgetState->enumChildren(widgetCursor); - widgetState->draw(previousState); + g_isActiveWidget = savedIsActiveWidget; - g_isActiveWidget = savedIsActiveWidget; + widgetCursor.x = savedX; + widgetCursor.y = savedY; } -void enumNoneWidget(WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState) { - static Widget g_noneWidget = { WIDGET_TYPE_NONE }; - const Widget *widget = &g_noneWidget; - - auto widgetState = currentState; - - g_widgetStatePlacementNewFunctions[widget->type](widgetState, widgetCursor); - - widgetState->widgetCursor = widgetCursor; - widgetState->widgetCursor.widget = widget; - widgetState->widgetStateSize = g_widgetStateSize[widget->type]; -} +void enumNoneWidget(WidgetCursor &widgetCursor) { + auto savedWidget = widgetCursor.widget; + widgetCursor.widget = &g_noneWidget; + enumWidget(widgetCursor); + widgetCursor.widget = savedWidget; +} //////////////////////////////////////////////////////////////////////////////// -void forEachWidget(AppContext* appContext, EnumWidgetsCallback callback) { - if (!g_currentState) { - return; - } - - WidgetState *widgetState = g_currentState; - WidgetState *widgetStateEnd = nextWidgetState(g_currentState); - while (widgetState != widgetStateEnd) { - if (!callback(widgetState)) { - break; - } - widgetState = (WidgetState *)((uint8_t*)widgetState + g_widgetStateSize[widgetState->widgetCursor.widget->type]); +void freeWidgetStates(WidgetState *widgetStateStart) { + WidgetState *widgetState = widgetStateStart; + while (widgetState < g_widgetStateEnd) { + auto nextWidgetState = (WidgetState *)((uint8_t*)widgetState + g_widgetStateSizes[widgetState->type]); + widgetState->~WidgetState(); + widgetState = nextWidgetState; } } -WidgetState *getWidgetState(const WidgetCursor &widgetCursor) { - if (!g_currentState) { - return nullptr; - } - - WidgetState *widgetState = g_currentState; - WidgetState *widgetStateEnd = nextWidgetState(g_currentState); - while (widgetState != widgetStateEnd) { - if (widgetState->widgetCursor == widgetCursor) { - return widgetState; - } - widgetState = (WidgetState *)((uint8_t*)widgetState + g_widgetStateSize[widgetState->widgetCursor.widget->type]); - } +//////////////////////////////////////////////////////////////////////////////// - return nullptr; -} - -void freeWidgetStates(WidgetState *topWidgetState) { - WidgetState *widgetState = topWidgetState; - WidgetState *widgetStateEnd = nextWidgetState(topWidgetState); - while (widgetState != widgetStateEnd) { - auto nextWidgetState = (WidgetState *)((uint8_t*)widgetState + g_widgetStateSize[widgetState->widgetCursor.widget->type]); - widgetState->~WidgetState(); - widgetState = nextWidgetState; - } +void forEachWidget(EnumWidgetsCallback callback) { + g_findCallback = callback; + enumRootWidget(); + g_findCallback = nullptr; } //////////////////////////////////////////////////////////////////////////////// static int g_findWidgetAtX; static int g_findWidgetAtY; +static bool g_clicked; + +static bool g_found; static WidgetCursor g_foundWidget; static int g_distanceToFoundWidget; -static bool g_clicked; -static int g_xOverlayOffset = 0; -static int g_yOverlayOffset = 0; -static WidgetState *g_widgetStateAfterOverlay = nullptr; +int g_xOverlayOffset = 0; +int g_yOverlayOffset = 0; -static bool findWidgetStep(WidgetState *widgetState) { - const WidgetCursor &widgetCursor = widgetState->widgetCursor; +static AppContext *g_popPageAppContext; + +static void findWidgetStep(const WidgetCursor &widgetCursor) { + if (g_found) { + return; + } if (widgetCursor.appContext->isActivePageInternal()) { auto internalPage = ((InternalPage *)widgetCursor.appContext->getActivePage()); - WidgetCursor foundWidget = internalPage->findWidgetInternalPage(g_findWidgetAtX, g_findWidgetAtY, g_clicked); + WidgetCursor foundWidget = internalPage->findWidgetInternalPage(widgetCursor, g_findWidgetAtX, g_findWidgetAtY, g_clicked); if (foundWidget) { g_foundWidget = foundWidget; - return false; + g_found = true; + return; } if (g_clicked) { // clicked outside internal page, close internal page - widgetCursor.appContext->popPage(); + g_popPageAppContext = widgetCursor.appContext; } bool passThrough = internalPage->canClickPassThrough(); if (!passThrough) { g_foundWidget = 0; - return false; - } + g_found = true; + return; + } } if (widgetCursor.isPage()) { - g_foundWidget = widgetCursor; - g_distanceToFoundWidget = INT_MAX; + if (g_foundWidget && g_foundWidget.appContext == widgetCursor.appContext) { + g_foundWidget = widgetCursor; + g_distanceToFoundWidget = INT_MAX; + } } const Widget *widget = widgetCursor.widget; Overlay *overlay = getOverlay(widgetCursor); + if (overlay) { + getOverlayOffset(widgetCursor, g_xOverlayOffset, g_yOverlayOffset); + } - if (widgetState == g_widgetStateAfterOverlay) { - g_xOverlayOffset = 0; - g_yOverlayOffset = 0; - g_widgetStateAfterOverlay = nullptr; - } + int x = widgetCursor.x + g_xOverlayOffset; + int y = widgetCursor.y + g_yOverlayOffset; - if (overlay) { - getOverlayOffset(widgetCursor, g_xOverlayOffset, g_yOverlayOffset); - g_widgetStateAfterOverlay = nextWidgetState(widgetState); - } + if (overlay) { + g_xOverlayOffset = 0; + g_yOverlayOffset = 0; + } static const int MIN_SIZE = 50; - int x = widgetCursor.x + g_xOverlayOffset; int w = overlay ? overlay->width : widget->w; if (w < MIN_SIZE) { x = x - (MIN_SIZE - w) / 2; w = MIN_SIZE; } - int y = widgetCursor.y + g_yOverlayOffset; int h = overlay ? overlay->height : widget->h; if (h < MIN_SIZE) { y = y - (MIN_SIZE - h) / 2; @@ -299,7 +293,7 @@ static bool findWidgetStep(WidgetState *widgetState) { auto action = getWidgetAction(widgetCursor); if (action == EEZ_CONF_ACTION_ID_DRAG_OVERLAY) { if (overlay && !overlay->state) { - return true; + return; } g_foundWidget = widgetCursor; g_distanceToFoundWidget = INT_MAX; @@ -325,11 +319,10 @@ static bool findWidgetStep(WidgetState *widgetState) { } } } - - return true; } -WidgetCursor findWidget(AppContext* appContext, int16_t x, int16_t y, bool clicked) { +WidgetCursor findWidget(int16_t x, int16_t y, bool clicked) { + g_found = false; g_foundWidget = 0; g_clicked = clicked; @@ -338,9 +331,15 @@ WidgetCursor findWidget(AppContext* appContext, int16_t x, int16_t y, bool click g_xOverlayOffset = 0; g_yOverlayOffset = 0; - g_widgetStateAfterOverlay = nullptr; - forEachWidget(appContext, findWidgetStep); + g_popPageAppContext = nullptr; + + forEachWidget(findWidgetStep); + + if (g_popPageAppContext) { + g_popPageAppContext->popPage(); + g_popPageAppContext = nullptr; + } return g_foundWidget; } diff --git a/src/eez/gui/widget.h b/src/eez/gui/widget.h index fa25a9179..8bf3b566e 100644 --- a/src/eez/gui/widget.h +++ b/src/eez/gui/widget.h @@ -100,6 +100,9 @@ struct WidgetCursor { int16_t x; int16_t y; + WidgetState *currentState; + bool hasPreviousState; + WidgetCursor() : assets(nullptr) , appContext(nullptr) @@ -108,6 +111,8 @@ struct WidgetCursor { , flowState(nullptr) , x(0) , y(0) + , currentState(nullptr) + , hasPreviousState(false) { iterators[0] = -1; iterators[1] = -1; iterators[2] = -1; iterators[3] = -1; } @@ -117,7 +122,9 @@ struct WidgetCursor { AppContext *appContext_, const Widget *widget_, int16_t x_, - int16_t y_ + int16_t y_, + WidgetState *currentState_, + bool hasPreviousState_ ) : assets(assets_) , appContext(appContext_) @@ -126,6 +133,8 @@ struct WidgetCursor { , flowState(nullptr) , x(x_) , y(y_) + , currentState(currentState_) + , hasPreviousState(hasPreviousState_) { iterators[0] = -1; iterators[1] = -1; iterators[2] = -1; iterators[3] = -1; } @@ -138,6 +147,8 @@ struct WidgetCursor { , flowState(nullptr) , x(0) , y(0) + , currentState(nullptr) + , hasPreviousState(false) { iterators[0] = -1; iterators[1] = -1; iterators[2] = -1; iterators[3] = -1; } @@ -174,45 +185,46 @@ struct WidgetCursor { extern bool g_isActiveWidget; struct WidgetState { - WidgetCursor widgetCursor; - size_t widgetStateSize; - WidgetStateFlags flags; - Value data; - - WidgetState(const WidgetCursor& widgetCursor_) : widgetCursor(widgetCursor_) { - flags.active = g_isActiveWidget; - flags.focused = 0; - flags.blinking = 0; - flags.enabled = 0; - } + uint16_t type; virtual ~WidgetState() {} - WidgetCursor getFirstChildWidgetCursor(WidgetCursor &widgetCursor, WidgetState *¤tState, WidgetState *&previousState); + virtual bool updateState(const WidgetCursor &widgetCursor); - virtual void draw(WidgetState *previousState); + virtual void render(WidgetCursor &widgetCursor); + virtual void enumChildren(WidgetCursor &widgetCursor); virtual bool hasOnTouch(); - virtual void onTouch(Event &touchEvent); + virtual void onTouch(const WidgetCursor &widgetCursor, Event &touchEvent); virtual bool hasOnKeyboard(); - virtual bool onKeyboard(uint8_t key, uint8_t mod); + virtual bool onKeyboard(const WidgetCursor &widgetCursor, uint8_t key, uint8_t mod); }; -//////////////////////////////////////////////////////////////////////////////// - -#define nextWidgetState(p) (WidgetState *)(((uint8_t *)p) + p->widgetStateSize) +#define WIDGET_STATE(A, B) \ + if (hasPreviousState) { \ + auto temp = B; \ + if (A != temp) { \ + hasPreviousState = false; \ + A = temp; \ + } \ + } else { \ + A = B; \ + } -void enumWidget(WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState); -void enumNoneWidget(WidgetCursor &widgetCursor, WidgetState *currentState, WidgetState *previousState); +//////////////////////////////////////////////////////////////////////////////// -typedef bool (*EnumWidgetsCallback)(WidgetState *widgetState); -void forEachWidget(AppContext* appContext, EnumWidgetsCallback callback); -WidgetState *getWidgetState(const WidgetCursor &widgetCursor); +void enumRootWidget(); +void enumWidget(WidgetCursor &widgetCursor); +void enumNoneWidget(WidgetCursor &widgetCursor); void freeWidgetStates(WidgetState *topWidgetState); -WidgetCursor findWidget(AppContext* appContext, int16_t x, int16_t y, bool clicked = true); +typedef void (*EnumWidgetsCallback)(const WidgetCursor &widgetCursor); +extern EnumWidgetsCallback g_findCallback; +void forEachWidget(EnumWidgetsCallback callback); + +WidgetCursor findWidget(int16_t x, int16_t y, bool clicked = true); OnTouchFunctionType getWidgetTouchFunction(const WidgetCursor &widgetCursor); diff --git a/src/eez/gui/widgets/bar_graph.cpp b/src/eez/gui/widgets/bar_graph.cpp index 1c4abd88c..92e807119 100644 --- a/src/eez/gui/widgets/bar_graph.cpp +++ b/src/eez/gui/widgets/bar_graph.cpp @@ -66,300 +66,311 @@ void drawLineInBarGraphWidget(const BarGraphWidget *barGraphWidget, int p, uint1 } } -void BarGraphWidgetState::refreshTextData(BarGraphWidgetState *previousState) { - if (previousState && textData != previousState->textData) { - auto widget = (const BarGraphWidget *)widgetCursor.widget; - uint32_t refreshRate = getTextRefreshRate(widgetCursor, widget->data); - if (refreshRate != 0) { - if (textDataRefreshLastTime - previousState->textDataRefreshLastTime < refreshRate) { - textData = previousState->textData; - textDataRefreshLastTime = previousState->textDataRefreshLastTime; - } +bool BarGraphWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const BarGraphWidget *)widgetCursor.widget; + const Style* style = getStyle(overrideStyleHook(widgetCursor, widget->style)); + + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(flags.blinking, g_isBlinkTime && isBlinking(widgetCursor, widget->data)); + WIDGET_STATE(data, get(widgetCursor, widget->data)); + WIDGET_STATE(color, getColor(widgetCursor, widget->data, style)); + WIDGET_STATE(backgroundColor, getBackgroundColor(widgetCursor, widget->data, style)); + WIDGET_STATE(activeColor, getActiveColor(widgetCursor, widget->data, style)); + WIDGET_STATE(activeBackgroundColor, getActiveBackgroundColor(widgetCursor, widget->data, style)); + WIDGET_STATE(line1Data, get(widgetCursor, widget->line1Data)); + WIDGET_STATE(line2Data, get(widgetCursor, widget->line2Data)); + + bool refreshTextData = true; + if (hasPreviousState && textData != data) { + uint32_t refreshRate = getTextRefreshRate(widgetCursor, widget->data); + if (refreshRate != 0 && millis() - textDataRefreshLastTime < refreshRate) { + refreshTextData = false; } } + if (refreshTextData) { + WIDGET_STATE(textData, data); + } + + return !hasPreviousState; } -void BarGraphWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (BarGraphWidgetState *)previousStateBase; - refreshTextData(previousState); - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const BarGraphWidget *)widgetCursor.widget; - const Style* style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - - int x = widgetCursor.x; - int y = widgetCursor.y; - const int w = widget->w; - const int h = widget->h; - - float min = getMin(widgetCursor, widget->data).getFloat(); - - float max; - Value displayValueRange = getDisplayValueRange(widgetCursor, widget->data); - if (displayValueRange.getType() == VALUE_TYPE_FLOAT) { - max = displayValueRange.getFloat(); - } else { - max = getMax(widgetCursor, widget->data).getFloat(); - } +void BarGraphWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const BarGraphWidget *)widgetCursor.widget; + const Style* style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - bool horizontal = - (widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_LEFT_RIGHT || - (widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_RIGHT_LEFT; + int x = widgetCursor.x; + int y = widgetCursor.y; + const int w = widget->w; + const int h = widget->h; - int d = horizontal ? w : h; + float min = getMin(widgetCursor, widget->data).getFloat(); - // calc bar position (monitored value) - int pValue = calcValuePosInBarGraphWidgetWithClamp(data, min, max, d); + float max; + Value displayValueRange = getDisplayValueRange(widgetCursor, widget->data); + if (displayValueRange.getType() == VALUE_TYPE_FLOAT) { + max = displayValueRange.getFloat(); + } else { + max = getMax(widgetCursor, widget->data).getFloat(); + } - // calc line 1 position (set value) - int pLine1 = calcValuePosInBarGraphWidget(line1Data, min, max, d); - bool drawLine1 = pLine1 >= 0 && pLine1 < d; + bool horizontal = + (widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_LEFT_RIGHT || + (widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_RIGHT_LEFT; - // calc line 2 position (limit value) - int pLine2 = calcValuePosInBarGraphWidget(line2Data, min, max, d); - bool drawLine2 = pLine2 >= 0 && pLine2 < d; + int d = horizontal ? w : h; - if (drawLine1 && drawLine2) { - // make sure line positions don't overlap - if (pLine1 == pLine2) { - pLine1 = pLine2 - 1; - } + // calc bar position (monitored value) + int pValue = calcValuePosInBarGraphWidgetWithClamp(data, min, max, d); - // make sure all lines are visible - if (pLine1 < 0) { - pLine2 -= pLine1; - pLine1 = 0; - } + // calc line 1 position (set value) + int pLine1 = calcValuePosInBarGraphWidget(line1Data, min, max, d); + bool drawLine1 = pLine1 >= 0 && pLine1 < d; + + // calc line 2 position (limit value) + int pLine2 = calcValuePosInBarGraphWidget(line2Data, min, max, d); + bool drawLine2 = pLine2 >= 0 && pLine2 < d; + + if (drawLine1 && drawLine2) { + // make sure line positions don't overlap + if (pLine1 == pLine2) { + pLine1 = pLine2 - 1; } - Style textStyle; - memcpy(&textStyle, widget->textStyle ? getStyle(widget->textStyle) : style, sizeof(Style)); - if (style->color != color) { - textStyle.color = flags.active || flags.blinking ? activeColor : color; + // make sure all lines are visible + if (pLine1 < 0) { + pLine2 -= pLine1; + pLine1 = 0; } + } - uint16_t fg = flags.active || flags.blinking ? activeColor : color; - uint16_t bg = flags.active || flags.blinking ? activeBackgroundColor : backgroundColor; + Style textStyle; + memcpy(&textStyle, widget->textStyle ? getStyle(widget->textStyle) : style, sizeof(Style)); + if (style->color != color) { + textStyle.color = flags.active || flags.blinking ? activeColor : color; + } - if (horizontal) { - // calc text position - char valueText[64]; - int pText = 0; - int wText = 0; - if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { - if (widget->textStyle) { - font::Font font = styleGetFont(&textStyle); + uint16_t fg = flags.active || flags.blinking ? activeColor : color; + uint16_t bg = flags.active || flags.blinking ? activeBackgroundColor : backgroundColor; - textData.toText(valueText, sizeof(valueText)); - wText = display::measureStr(valueText, -1, font, w); + if (horizontal) { + // calc text position + char valueText[64]; + int pText = 0; + int wText = 0; + if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { + if (widget->textStyle) { + font::Font font = styleGetFont(&textStyle); - int padding = textStyle.padding_left; - wText += padding; + textData.toText(valueText, sizeof(valueText)); + wText = display::measureStr(valueText, -1, font, w); - if (pValue + wText <= d) { - textStyle.background_color = bg; - pText = pValue; - } else { - textStyle.background_color = fg; - textStyle.color = textStyle.active_color; - wText += padding; - pText = MAX(pValue - wText, 0); - } + int padding = textStyle.padding_left; + wText += padding; + + if (pValue + wText <= d) { + textStyle.background_color = bg; + pText = pValue; + } else { + textStyle.background_color = fg; + textStyle.color = textStyle.active_color; + wText += padding; + pText = MAX(pValue - wText, 0); } - } else { - pText = pValue; } + } else { + pText = pValue; + } - if ((widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_LEFT_RIGHT) { - // draw bar - if (pText > 0) { - display::setColor(fg); - display::fillRect(x, y, x + pText - 1, y + h - 1); - } + if ((widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_LEFT_RIGHT) { + // draw bar + if (pText > 0) { + display::setColor(fg); + display::fillRect(x, y, x + pText - 1, y + h - 1); + } - if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { - drawText(valueText, -1, x + pText, y, wText, h, &textStyle, false, false, false, nullptr, nullptr, nullptr, nullptr); - } + if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { + drawText(valueText, -1, x + pText, y, wText, h, &textStyle, false, false, false, nullptr, nullptr, nullptr, nullptr); + } - // draw background, but do not draw over line 1 and line 2 - display::setColor(bg); + // draw background, but do not draw over line 1 and line 2 + display::setColor(bg); - int pBackground = pText + wText; + int pBackground = pText + wText; - if (drawLine1) { - if (pBackground <= pLine1) { - if (pBackground < pLine1) { - display::fillRect(x + pBackground, y, x + pLine1 - 1, y + h - 1); - } - pBackground = pLine1 + 1; + if (drawLine1) { + if (pBackground <= pLine1) { + if (pBackground < pLine1) { + display::fillRect(x + pBackground, y, x + pLine1 - 1, y + h - 1); } + pBackground = pLine1 + 1; } + } - if (drawLine2) { - if (pBackground <= pLine2) { - if (pBackground < pLine2) { - display::fillRect(x + pBackground, y, x + pLine2 - 1, y + h - 1); - } - pBackground = pLine2 + 1; + if (drawLine2) { + if (pBackground <= pLine2) { + if (pBackground < pLine2) { + display::fillRect(x + pBackground, y, x + pLine2 - 1, y + h - 1); } + pBackground = pLine2 + 1; } + } - if (pBackground < d) { - display::fillRect(x + pBackground, y, x + d - 1, y + h - 1); - } - } else { - x += w - 1; + if (pBackground < d) { + display::fillRect(x + pBackground, y, x + d - 1, y + h - 1); + } + } else { + x += w - 1; - // draw bar - if (pText > 0) { - display::setColor(fg); - display::fillRect(x - (pText - 1), y, x, y + h - 1); - } + // draw bar + if (pText > 0) { + display::setColor(fg); + display::fillRect(x - (pText - 1), y, x, y + h - 1); + } - if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { - drawText(valueText, -1, x - (pText + wText - 1), y, wText, h, &textStyle, false, false, false, nullptr, nullptr, nullptr, nullptr); - } + if (!(widget->orientation & BAR_GRAPH_DO_NOT_DISPLAY_VALUE)) { + drawText(valueText, -1, x - (pText + wText - 1), y, wText, h, &textStyle, false, false, false, nullptr, nullptr, nullptr, nullptr); + } - // draw background, but do not draw over line 1 and line 2 - display::setColor(bg); + // draw background, but do not draw over line 1 and line 2 + display::setColor(bg); - int pBackground = pText + wText; + int pBackground = pText + wText; - if (drawLine1) { - if (pBackground <= pLine1) { - if (pBackground < pLine1) { - display::fillRect(x - (pLine1 - 1), y, x - pBackground, y + h - 1); - } - pBackground = pLine1 + 1; + if (drawLine1) { + if (pBackground <= pLine1) { + if (pBackground < pLine1) { + display::fillRect(x - (pLine1 - 1), y, x - pBackground, y + h - 1); } + pBackground = pLine1 + 1; } + } - if (drawLine2) { - if (pBackground <= pLine2) { - if (pBackground < pLine2) { - display::fillRect(x - (pLine2 - 1), y, x - pBackground, y + h - 1); - } - pBackground = pLine2 + 1; + if (drawLine2) { + if (pBackground <= pLine2) { + if (pBackground < pLine2) { + display::fillRect(x - (pLine2 - 1), y, x - pBackground, y + h - 1); } - } - - if (pBackground < d) { - display::fillRect(x - (d - 1), y, x - pBackground, y + h - 1); + pBackground = pLine2 + 1; } } - if (drawLine1) { - drawLineInBarGraphWidget(widget, pLine1, widget->line1Style, x, y, w, h); + if (pBackground < d) { + display::fillRect(x - (d - 1), y, x - pBackground, y + h - 1); } - if (drawLine2) { - drawLineInBarGraphWidget(widget, pLine2, widget->line2Style, x, y, w, h); - } - } else { - // calc text position - char valueText[64]; - int pText = 0; - int hText = 0; - if (widget->textStyle) { - font::Font font = styleGetFont(&textStyle); + } - textData.toText(valueText, sizeof(valueText)); - hText = font.getHeight(); + if (drawLine1) { + drawLineInBarGraphWidget(widget, pLine1, widget->line1Style, x, y, w, h); + } + if (drawLine2) { + drawLineInBarGraphWidget(widget, pLine2, widget->line2Style, x, y, w, h); + } + } else { + // calc text position + char valueText[64]; + int pText = 0; + int hText = 0; + if (widget->textStyle) { + font::Font font = styleGetFont(&textStyle); - int padding = textStyle.padding_top; - hText += padding; + textData.toText(valueText, sizeof(valueText)); + hText = font.getHeight(); - if (pValue + hText <= d) { - textStyle.background_color = bg; - pText = pValue; - } else { - textStyle.background_color = fg; - textStyle.color = textStyle.active_color; - hText += padding; - pText = MAX(pValue - hText, 0); - } + int padding = textStyle.padding_top; + hText += padding; + + if (pValue + hText <= d) { + textStyle.background_color = bg; + pText = pValue; + } else { + textStyle.background_color = fg; + textStyle.color = textStyle.active_color; + hText += padding; + pText = MAX(pValue - hText, 0); } + } - if ((widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_TOP_BOTTOM) { - // draw bar - if (pText > 0) { - display::setColor(fg); - display::fillRect(x, y, x + w - 1, y + pText - 1); - } + if ((widget->orientation & BAR_GRAPH_ORIENTATION_MASK) == BAR_GRAPH_ORIENTATION_TOP_BOTTOM) { + // draw bar + if (pText > 0) { + display::setColor(fg); + display::fillRect(x, y, x + w - 1, y + pText - 1); + } - drawText(valueText, -1, x, y + pText, w, hText, &textStyle, false, false, false, nullptr, nullptr, nullptr, nullptr); + drawText(valueText, -1, x, y + pText, w, hText, &textStyle, false, false, false, nullptr, nullptr, nullptr, nullptr); - // draw background, but do not draw over line 1 and line 2 - display::setColor(bg); + // draw background, but do not draw over line 1 and line 2 + display::setColor(bg); - int pBackground = pText + hText; + int pBackground = pText + hText; - if (drawLine1) { - if (pBackground <= pLine1) { - if (pBackground < pLine1) { - display::fillRect(x, y + pBackground, x + w - 1, y + pLine1 - 1); - } - pBackground = pLine1 + 1; + if (drawLine1) { + if (pBackground <= pLine1) { + if (pBackground < pLine1) { + display::fillRect(x, y + pBackground, x + w - 1, y + pLine1 - 1); } + pBackground = pLine1 + 1; } + } - if (drawLine2) { - if (pBackground <= pLine2) { - if (pBackground < pLine2) { - display::fillRect(x, y + pBackground, x + w - 1, y + pLine2 - 1); - } - pBackground = pLine2 + 1; + if (drawLine2) { + if (pBackground <= pLine2) { + if (pBackground < pLine2) { + display::fillRect(x, y + pBackground, x + w - 1, y + pLine2 - 1); } + pBackground = pLine2 + 1; } + } - if (pBackground < d) { - display::fillRect(x, y + pBackground, x + w - 1, y + d - 1); - } - } else { - y += h - 1; + if (pBackground < d) { + display::fillRect(x, y + pBackground, x + w - 1, y + d - 1); + } + } else { + y += h - 1; - // draw bar - if (pText > 0) { - display::setColor(fg); - display::fillRect(x, y - (pText - 1), x + w - 1, y); - } + // draw bar + if (pText > 0) { + display::setColor(fg); + display::fillRect(x, y - (pText - 1), x + w - 1, y); + } - drawText(valueText, -1, x, y - (pText + hText - 1), w, hText, &textStyle, false, false, false, nullptr, nullptr, nullptr, nullptr); + drawText(valueText, -1, x, y - (pText + hText - 1), w, hText, &textStyle, false, false, false, nullptr, nullptr, nullptr, nullptr); - // draw background, but do not draw over line 1 and line 2 - display::setColor(bg); + // draw background, but do not draw over line 1 and line 2 + display::setColor(bg); - int pBackground = pText + hText; + int pBackground = pText + hText; - if (drawLine1) { - if (pBackground <= pLine1) { - if (pBackground < pLine1) { - display::fillRect(x, y - (pLine1 - 1), x + w - 1, y - pBackground); - } - pBackground = pLine1 + 1; + if (drawLine1) { + if (pBackground <= pLine1) { + if (pBackground < pLine1) { + display::fillRect(x, y - (pLine1 - 1), x + w - 1, y - pBackground); } + pBackground = pLine1 + 1; } + } - if (drawLine2) { - if (pBackground <= pLine2) { - if (pBackground < pLine2) { - display::fillRect(x, y - (pLine2 - 1), x + w - 1, y - (pBackground)); - } - pBackground = pLine2 + 1; + if (drawLine2) { + if (pBackground <= pLine2) { + if (pBackground < pLine2) { + display::fillRect(x, y - (pLine2 - 1), x + w - 1, y - (pBackground)); } - } - - if (pBackground < d) { - display::fillRect(x, y - (d - 1), x + w - 1, y - pBackground); + pBackground = pLine2 + 1; } } - if (drawLine1) { - drawLineInBarGraphWidget(widget, pLine1, widget->line1Style, x, y, w, h); - } - if (drawLine2) { - drawLineInBarGraphWidget(widget, pLine2, widget->line2Style, x, y, w, h); + if (pBackground < d) { + display::fillRect(x, y - (d - 1), x + w - 1, y - pBackground); } } + + if (drawLine1) { + drawLineInBarGraphWidget(widget, pLine1, widget->line1Style, x, y, w, h); + } + if (drawLine2) { + drawLineInBarGraphWidget(widget, pLine2, widget->line2Style, x, y, w, h); + } } } diff --git a/src/eez/gui/widgets/bar_graph.h b/src/eez/gui/widgets/bar_graph.h index 21c1ddcc4..7ea642f5d 100644 --- a/src/eez/gui/widgets/bar_graph.h +++ b/src/eez/gui/widgets/bar_graph.h @@ -31,6 +31,8 @@ struct BarGraphWidget : public Widget { }; struct BarGraphWidgetState : public WidgetState { + WidgetStateFlags flags; + Value data; uint16_t color; uint16_t backgroundColor; uint16_t activeColor; @@ -40,44 +42,8 @@ struct BarGraphWidgetState : public WidgetState { Value textData; uint32_t textDataRefreshLastTime; - BarGraphWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const BarGraphWidget *)widgetCursor.widget; - - const Style* style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - - flags.blinking = g_isBlinkTime && isBlinking(widgetCursor, widget->data); - data = get(widgetCursor, widget->data); - - color = getColor(widgetCursor, widget->data, style); - backgroundColor = getBackgroundColor(widgetCursor, widget->data, style); - activeColor = getActiveColor(widgetCursor, widget->data, style); - activeBackgroundColor = getActiveBackgroundColor(widgetCursor, widget->data, style); - - line1Data = get(widgetCursor, widget->line1Data); - - line2Data = get(widgetCursor, widget->line2Data); - - textData = data; - textDataRefreshLastTime = millis(); - } - - bool operator!=(const BarGraphWidgetState& previousState) { - return - flags.active != previousState.flags.active || - flags.blinking != previousState.flags.blinking || - data != previousState.data || - color != previousState.color || - backgroundColor != previousState.backgroundColor || - activeColor != previousState.activeColor || - activeBackgroundColor != previousState.activeBackgroundColor || - line1Data != previousState.line1Data || - line2Data != previousState.line2Data || - textData != previousState.textData; - } - - void refreshTextData(BarGraphWidgetState *previousState); - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/bitmap.cpp b/src/eez/gui/widgets/bitmap.cpp index 5ac309f0f..5b346e436 100644 --- a/src/eez/gui/widgets/bitmap.cpp +++ b/src/eez/gui/widgets/bitmap.cpp @@ -25,43 +25,49 @@ namespace eez { namespace gui { -void BitmapWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (BitmapWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const BitmapWidget *)widgetCursor.widget; - const Style* style = getStyle(widget->style); +bool BitmapWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const BitmapWidget *)widgetCursor.widget; + + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(data, widget->data ? getBitmapImage(widgetCursor, widget->data) : 0); - const Bitmap *bitmap = nullptr; + return !hasPreviousState; +} + +void BitmapWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const BitmapWidget *)widgetCursor.widget; + const Style* style = getStyle(widget->style); + + const Bitmap *bitmap = nullptr; - if (widget->data) { - if (data.getType() != VALUE_TYPE_UNDEFINED) { - drawRectangle(widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active, true, true); - auto image = (Image *)data.getVoidPointer(); - if (image) { - drawBitmap(image, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active); - } - return; - } else { - Value valueBitmapId; - DATA_OPERATION_FUNCTION(widget->data, DATA_OPERATION_GET, widgetCursor, valueBitmapId); - bitmap = getBitmap(valueBitmapId.getInt()); + if (widget->data) { + if (data.getType() != VALUE_TYPE_UNDEFINED) { + drawRectangle(widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active, true, true); + auto image = (Image *)data.getVoidPointer(); + if (image) { + drawBitmap(image, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active); } - } else if (widget->bitmap != 0) { - bitmap = getBitmap(widget->bitmap); + return; + } else { + Value valueBitmapId; + DATA_OPERATION_FUNCTION(widget->data, DATA_OPERATION_GET, widgetCursor, valueBitmapId); + bitmap = getBitmap(valueBitmapId.getInt()); } + } else if (widget->bitmap != 0) { + bitmap = getBitmap(widget->bitmap); + } - if (bitmap) { - Image image; + if (bitmap) { + Image image; - image.width = bitmap->w; - image.height = bitmap->h; - image.bpp = bitmap->bpp; - image.lineOffset = 0; - image.pixels = (uint8_t *)bitmap->pixels; + image.width = bitmap->w; + image.height = bitmap->h; + image.bpp = bitmap->bpp; + image.lineOffset = 0; + image.pixels = (uint8_t *)bitmap->pixels; - drawBitmap(&image, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active); - } + drawBitmap(&image, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active); } } diff --git a/src/eez/gui/widgets/bitmap.h b/src/eez/gui/widgets/bitmap.h index 219739219..3fd3e5992 100644 --- a/src/eez/gui/widgets/bitmap.h +++ b/src/eez/gui/widgets/bitmap.h @@ -26,19 +26,11 @@ struct BitmapWidget : public Widget { }; struct BitmapWidgetState : public WidgetState { - BitmapWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const BitmapWidget *)widgetCursor.widget; - - data = widget->data ? getBitmapImage(widgetCursor, widget->data) : 0; - } - - bool operator!=(const BitmapWidgetState& previousState) { - return - flags.active != previousState.flags.active || - data != previousState.data; - } - - void draw(WidgetState *previousState) override; + WidgetStateFlags flags; + Value data; + + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/button.cpp b/src/eez/gui/widgets/button.cpp index f96c36a5c..d1418cbf4 100644 --- a/src/eez/gui/widgets/button.cpp +++ b/src/eez/gui/widgets/button.cpp @@ -26,32 +26,45 @@ static const size_t MAX_TEXT_LEN = 128; namespace eez { namespace gui { -void ButtonWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (ButtonWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const ButtonWidget *)widgetCursor.widget; - const Style *style = getStyle(flags.enabled ? widget->style : widget->disabledStyle); - - if (widget->data) { - if (data.isString()) { - drawText(data.getString(), -1, widgetCursor.x, - widgetCursor.y, (int)widget->w, (int)widget->h, style, - flags.active, - flags.blinking, false, nullptr, nullptr, nullptr, nullptr); - } else { - char text[MAX_TEXT_LEN + 1]; - data.toText(text, sizeof(text)); - - drawText(text, -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - style, flags.active, - flags.blinking, false, nullptr, nullptr, nullptr, nullptr); - } +bool ButtonWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const ButtonWidget *)widgetCursor.widget; + const Style *style = getStyle(flags.enabled ? widget->style : widget->disabledStyle); + + WIDGET_STATE(flags.active, g_isActiveWidget); + + auto enabled = get(widgetCursor, widget->enabled); + WIDGET_STATE(flags.enabled, enabled.getType() == VALUE_TYPE_UNDEFINED || enabled.getInt() ? 1 : 0); + + WIDGET_STATE(flags.blinking, g_isBlinkTime && (isBlinking(widgetCursor, widget->data) || styleIsBlink(style))); + + WIDGET_STATE(data, widget->data ? get(widgetCursor, widget->data) : 0); + + return !hasPreviousState; +} + +void ButtonWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const ButtonWidget *)widgetCursor.widget; + const Style *style = getStyle(flags.enabled ? widget->style : widget->disabledStyle); + + if (widget->data) { + if (data.isString()) { + drawText(data.getString(), -1, widgetCursor.x, + widgetCursor.y, (int)widget->w, (int)widget->h, style, + flags.active, + flags.blinking, false, nullptr, nullptr, nullptr, nullptr); } else { - drawText(widget->text.ptr(widgetCursor.assets), -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - style, flags.active, - flags.blinking, false, nullptr, nullptr, nullptr, nullptr); + char text[MAX_TEXT_LEN + 1]; + data.toText(text, sizeof(text)); + + drawText(text, -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + style, flags.active, + flags.blinking, false, nullptr, nullptr, nullptr, nullptr); } + } else { + drawText(widget->text.ptr(widgetCursor.assets), -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + style, flags.active, + flags.blinking, false, nullptr, nullptr, nullptr, nullptr); } } diff --git a/src/eez/gui/widgets/button.h b/src/eez/gui/widgets/button.h index 95857bd91..229bd3038 100644 --- a/src/eez/gui/widgets/button.h +++ b/src/eez/gui/widgets/button.h @@ -28,27 +28,11 @@ struct ButtonWidget : public Widget { }; struct ButtonWidgetState : public WidgetState { - ButtonWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const ButtonWidget *)widgetCursor.widget; + WidgetStateFlags flags; + Value data; - auto enabled = get(widgetCursor, widget->enabled); - flags.enabled = enabled.getType() == VALUE_TYPE_UNDEFINED || get(widgetCursor, widget->enabled).getInt() ? 1 : 0; - - const Style *style = getStyle(flags.enabled ? widget->style : widget->disabledStyle); - flags.blinking = g_isBlinkTime && (isBlinking(widgetCursor, widget->data) || styleIsBlink(style)); - - data = widget->data ? get(widgetCursor, widget->data) : 0; - } - - bool operator!=(const ButtonWidgetState& previousState) { - return - flags.active != previousState.flags.active || - flags.enabled != previousState.flags.enabled || - flags.blinking != previousState.flags.blinking || - data != previousState.data; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/button_group.cpp b/src/eez/gui/widgets/button_group.cpp index 5dc7d8648..eeb66fde6 100644 --- a/src/eez/gui/widgets/button_group.cpp +++ b/src/eez/gui/widgets/button_group.cpp @@ -90,24 +90,30 @@ void drawButtons(const Widget *widget, int x, int y, const Style *style, const S } } -void ButtonGroupWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (ButtonGroupWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const ButtonGroupWidget *)widgetCursor.widget; +bool ButtonGroupWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const ButtonGroupWidget *)widgetCursor.widget; + + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(data, get(widgetCursor, widget->data)); + + return !hasPreviousState; +} - const Style* style = getStyle(widget->style); - const Style* selectedStyle = getStyle(widget->selectedStyle); +void ButtonGroupWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const ButtonGroupWidget *)widgetCursor.widget; - drawButtons(widget, widgetCursor.x, widgetCursor.y, style, selectedStyle, data.getInt(), count(widgetCursor, widget->data)); - } + const Style* style = getStyle(widget->style); + const Style* selectedStyle = getStyle(widget->selectedStyle); + + drawButtons(widget, widgetCursor.x, widgetCursor.y, style, selectedStyle, data.getInt(), count(widgetCursor, widget->data)); } bool ButtonGroupWidgetState::hasOnTouch() { return true; } -void ButtonGroupWidgetState::onTouch(Event &touchEvent) { +void ButtonGroupWidgetState::onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { if (touchEvent.type == EVENT_TYPE_TOUCH_DOWN) { const Widget *widget = widgetCursor.widget; diff --git a/src/eez/gui/widgets/button_group.h b/src/eez/gui/widgets/button_group.h index 736a7cd12..b96e0a1c7 100644 --- a/src/eez/gui/widgets/button_group.h +++ b/src/eez/gui/widgets/button_group.h @@ -26,20 +26,13 @@ struct ButtonGroupWidget : public Widget { }; struct ButtonGroupWidgetState : public WidgetState { - ButtonGroupWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const ButtonGroupWidget *)widgetCursor.widget; - data = get(widgetCursor, widget->data); - } - - bool operator!=(const ButtonGroupWidgetState& previousState) { - return - flags.active != previousState.flags.active || - data != previousState.data; - } - - void draw(WidgetState *previousState) override; + WidgetStateFlags flags; + Value data; + + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; bool hasOnTouch() override; - void onTouch(Event &touchEvent) override; + void onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/canvas.cpp b/src/eez/gui/widgets/canvas.cpp index f80758a73..7bd3079b1 100644 --- a/src/eez/gui/widgets/canvas.cpp +++ b/src/eez/gui/widgets/canvas.cpp @@ -24,17 +24,22 @@ namespace eez { namespace gui { -void CanvasWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (CanvasWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const CanvasWidget *)widgetCursor.widget; - - Value value; - DATA_OPERATION_FUNCTION(widget->data, DATA_OPERATION_GET_CANVAS_DRAW_FUNCTION, widgetCursor, value); - auto drawFunction = (void (*)(const WidgetCursor &widgetCursor))value.getVoidPointer(); - drawFunction(widgetCursor); - } +bool CanvasWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const CanvasWidget *)widgetCursor.widget; + + WIDGET_STATE(data, get(widgetCursor, widget->data)); + + return !hasPreviousState; +} + +void CanvasWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const CanvasWidget *)widgetCursor.widget; + + Value value; + DATA_OPERATION_FUNCTION(widget->data, DATA_OPERATION_GET_CANVAS_DRAW_FUNCTION, widgetCursor, value); + auto drawFunction = (void (*)(const WidgetCursor &widgetCursor))value.getVoidPointer(); + drawFunction(widgetCursor); } } // namespace gui diff --git a/src/eez/gui/widgets/canvas.h b/src/eez/gui/widgets/canvas.h index 1c3b97a35..d5fa66519 100644 --- a/src/eez/gui/widgets/canvas.h +++ b/src/eez/gui/widgets/canvas.h @@ -25,17 +25,10 @@ struct CanvasWidget : public Widget { }; struct CanvasWidgetState : public WidgetState { - CanvasWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const CanvasWidget *)widgetCursor.widget; + Value data; - data = get(widgetCursor, widget->data); - } - - bool operator!=(const CanvasWidgetState& previousState) { - return data != previousState.data; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/containers/app_view.cpp b/src/eez/gui/widgets/containers/app_view.cpp index e3dc83ac5..65dbd2f0f 100644 --- a/src/eez/gui/widgets/containers/app_view.cpp +++ b/src/eez/gui/widgets/containers/app_view.cpp @@ -24,8 +24,7 @@ namespace eez { namespace gui { -void AppViewWidgetState::draw(WidgetState *previousState) { - AppContext *appContext; +bool AppViewWidgetState::updateState(const WidgetCursor &widgetCursor) { if (widgetCursor.widget->data != DATA_ID_NONE) { Value appContextValue; DATA_OPERATION_FUNCTION(widgetCursor.widget->data, DATA_OPERATION_GET, widgetCursor, appContextValue); @@ -34,43 +33,31 @@ void AppViewWidgetState::draw(WidgetState *previousState) { appContext = widgetCursor.appContext; } + return false; +} + +void AppViewWidgetState::enumChildren(WidgetCursor &widgetCursor) { appContext->rect.x = widgetCursor.x; appContext->rect.y = widgetCursor.y; appContext->rect.w = widgetCursor.widget->w; appContext->rect.h = widgetCursor.widget->h; - WidgetState *childCurrentState = this; - WidgetState *childPreviousState = previousState; - WidgetCursor childWidgetCursor = getFirstChildWidgetCursor(widgetCursor, childCurrentState, childPreviousState); - - childWidgetCursor.appContext = appContext; + auto savedAppContext = widgetCursor.appContext; + widgetCursor.appContext = appContext; if (appContext->getActivePageId() != PAGE_ID_NONE) { - WidgetState *endOfContainerInPreviousState = 0; - if (previousState) { - endOfContainerInPreviousState = nextWidgetState(previousState); - } - for (int i = 0; i <= appContext->m_pageNavigationStackPointer; i++) { if (!appContext->isPageFullyCovered(i)) { - appContext->updatePage(i, childWidgetCursor, childCurrentState, childPreviousState); - - if (childPreviousState) { - childPreviousState = nextWidgetState(childPreviousState); - if (childPreviousState > endOfContainerInPreviousState) { - childPreviousState = 0; - } - } - childCurrentState = nextWidgetState(childCurrentState); + appContext->updatePage(i, widgetCursor); } else { appContext->m_pageNavigationStack[i].displayBufferIndex = -1; } } } else { - enumNoneWidget(childWidgetCursor, childCurrentState, childPreviousState); + enumNoneWidget(widgetCursor); } - widgetStateSize = (uint8_t *)childCurrentState - (uint8_t *)this; + widgetCursor.appContext = savedAppContext; } } // namespace gui diff --git a/src/eez/gui/widgets/containers/app_view.h b/src/eez/gui/widgets/containers/app_view.h index 0c8209d4a..5a141fb94 100644 --- a/src/eez/gui/widgets/containers/app_view.h +++ b/src/eez/gui/widgets/containers/app_view.h @@ -25,10 +25,10 @@ struct AppViewWidget : public Widget { }; struct AppViewWidgetState : public WidgetState { - AppViewWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } + AppContext *appContext; - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void enumChildren(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/containers/container.cpp b/src/eez/gui/widgets/containers/container.cpp index db0b2d79d..c1aec9384 100644 --- a/src/eez/gui/widgets/containers/container.cpp +++ b/src/eez/gui/widgets/containers/container.cpp @@ -25,109 +25,100 @@ namespace eez { namespace gui { -void ContainerWidgetState::draw(WidgetState *previousStateBase) { - Overlay *overlay = getOverlay(widgetCursor); - if (overlay) { - drawOverlay(previousStateBase, overlay); - return; - } +bool ContainerWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + WIDGET_STATE(flags.active, g_isActiveWidget); + + overlay = getOverlay(widgetCursor); + if (overlay) { + auto widget = (const ContainerWidget *)widgetCursor.widget; + + // update overlay data + auto containerWidget = (const ContainerWidget *)widget; + Value widgetCursorValue((void *)&widgetCursor, VALUE_TYPE_POINTER); + DATA_OPERATION_FUNCTION(containerWidget->overlay, DATA_OPERATION_UPDATE_OVERLAY_DATA, widgetCursor, widgetCursorValue); + + WIDGET_STATE(overlayState, overlay->state); + + if (overlayState == 0) { + displayBufferIndex = -1; + } else { + if (!hasPreviousState) { + displayBufferIndex = -1; + } + } + } - auto previousState = (ContainerWidgetState *)previousStateBase; - auto widget = (const ContainerWidget *)widgetCursor.widget; + return !hasPreviousState; +} - bool refresh = !previousState || previousState->flags.active != flags.active; +void ContainerWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const ContainerWidget *)widgetCursor.widget; - if (refresh) { - drawRectangle( - widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - getStyle(widget->style), flags.active, false, true - ); - } + if (overlay) { + if (overlayState == 0) { + return; + } + + if (displayBufferIndex == -1) { + displayBufferIndex = display::allocBuffer(); + } - WidgetState *childCurrentState = this; - WidgetState *childPreviousState = previousState; - WidgetCursor childWidgetCursor = getFirstChildWidgetCursor(widgetCursor, childCurrentState, childPreviousState); + display::selectBuffer(displayBufferIndex); + displayBufferSelected = true; + } - auto &widgets = widget->widgets; + drawRectangle( + widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + getStyle(widget->style), flags.active, false, true + ); +} - WidgetState *endOfContainerInPreviousState = 0; - if (previousState) { - endOfContainerInPreviousState = nextWidgetState(previousState); +void ContainerWidgetState::enumChildren(WidgetCursor &widgetCursor) { + if (overlay) { + renderOverlayChildren(widgetCursor); + return; } + auto savedWidget = widgetCursor.widget; + + auto widget = (const ContainerWidget *)widgetCursor.widget; + auto &widgets = widget->widgets; + auto widgetPtr = widgets.itemsPtr(widgetCursor.assets); for (uint32_t index = 0; index < widgets.count; ++index, ++widgetPtr) { - childWidgetCursor.widget = (const Widget *)widgetPtr->ptr(widgetCursor.assets); - - enumWidget(childWidgetCursor, childCurrentState, childPreviousState); + widgetCursor.widget = (const Widget *)widgetPtr->ptr(widgetCursor.assets); - if (childPreviousState) { - childPreviousState = nextWidgetState(childPreviousState); - if (childPreviousState > endOfContainerInPreviousState) { - childPreviousState = 0; - } - } - childCurrentState = nextWidgetState(childCurrentState); + enumWidget(widgetCursor); } - widgetStateSize = (uint8_t *)childCurrentState - (uint8_t *)this; - + widgetCursor.widget = savedWidget; } -void ContainerWidgetState::drawOverlay(WidgetState *previousStateBase, Overlay *overlay) { - auto previousState = (ContainerWidgetState *)previousStateBase; - auto widget = (const ContainerWidget *)widgetCursor.widget; - - bool refresh = - !previousState || - previousState->flags.active != flags.active; - - // update overlay data - auto containerWidget = (const ContainerWidget *)widget; - Value widgetCursorValue((void *)&widgetCursor, VALUE_TYPE_POINTER); - DATA_OPERATION_FUNCTION(containerWidget->overlay, DATA_OPERATION_UPDATE_OVERLAY_DATA, widgetCursor, widgetCursorValue); - - overlayState = overlay->state; - - if (overlayState == 0) { - displayBufferIndex = -1; +void ContainerWidgetState::renderOverlayChildren(WidgetCursor &widgetCursor) { + if (displayBufferIndex == -1) { return; } - if (previousState && overlayState != previousState->overlayState) { - refresh = true; - } - - if (refresh || previousState->displayBufferIndex == -1) { - displayBufferIndex = display::allocBuffer(); - refresh = true; - } else { - displayBufferIndex = previousState->displayBufferIndex; - } - - display::selectBuffer(displayBufferIndex); - - if (refresh) { - drawRectangle( - widgetCursor.x, widgetCursor.y, overlay->width, overlay->height, - getStyle(widget->style), flags.active, false, true - ); - } + if (g_findCallback == nullptr) { + if (!displayBufferSelected) { + display::selectBuffer(displayBufferIndex); + } else { + displayBufferSelected = false; + } + } - WidgetState *childCurrentState = this; - WidgetState *childPreviousState = previousState; - WidgetCursor childWidgetCursor = getFirstChildWidgetCursor(widgetCursor, childCurrentState, childPreviousState); + auto savedWidget = widgetCursor.widget; - if (previousState && previousState->overlayState != overlayState) { - childPreviousState = 0; - } + int xOffset = 0; + int yOffset = 0; + getOverlayOffset(widgetCursor, xOffset, yOffset); - auto &widgets = widget->widgets; + g_xOverlayOffset = xOffset; + g_yOverlayOffset = yOffset; - WidgetState *endOfContainerInPreviousState = 0; - if (previousState) { - endOfContainerInPreviousState = nextWidgetState(previousState); - } + auto widget = (const ContainerWidget *)widgetCursor.widget; + auto &widgets = widget->widgets; auto widgetOverrides = overlay->widgetOverrides; auto widgetPtr = widgets.itemsPtr(widgetCursor.assets); @@ -139,60 +130,58 @@ void ContainerWidgetState::drawOverlay(WidgetState *previousStateBase, Overlay * } } - childWidgetCursor.widget = (const Widget *)widgetPtr->ptr(widgetCursor.assets); + widgetCursor.widget = (const Widget *)widgetPtr->ptr(widgetCursor.assets); - int xSaved = childWidgetCursor.widget->x; - int ySaved = childWidgetCursor.widget->y; - int wSaved = childWidgetCursor.widget->w; - int hSaved = childWidgetCursor.widget->h; + int xSaved = 0; + int ySaved = 0; + int wSaved = 0; + int hSaved = 0; if (widgetOverrides) { - ((Widget*)childWidgetCursor.widget)->x = widgetOverrides->x; - ((Widget*)childWidgetCursor.widget)->y = widgetOverrides->y; - ((Widget*)childWidgetCursor.widget)->w = widgetOverrides->w; - ((Widget*)childWidgetCursor.widget)->h = widgetOverrides->h; + xSaved = widgetCursor.widget->x; + ySaved = widgetCursor.widget->y; + wSaved = widgetCursor.widget->w; + hSaved = widgetCursor.widget->h; + + ((Widget*)widgetCursor.widget)->x = widgetOverrides->x; + ((Widget*)widgetCursor.widget)->y = widgetOverrides->y; + ((Widget*)widgetCursor.widget)->w = widgetOverrides->w; + ((Widget*)widgetCursor.widget)->h = widgetOverrides->h; } - enumWidget(childWidgetCursor, childCurrentState, childPreviousState); + enumWidget(widgetCursor); if (widgetOverrides) { - ((Widget*)childWidgetCursor.widget)->x = xSaved; - ((Widget*)childWidgetCursor.widget)->y = ySaved; - ((Widget*)childWidgetCursor.widget)->w = wSaved; - ((Widget*)childWidgetCursor.widget)->h = hSaved; + ((Widget*)widgetCursor.widget)->x = xSaved; + ((Widget*)widgetCursor.widget)->y = ySaved; + ((Widget*)widgetCursor.widget)->w = wSaved; + ((Widget*)widgetCursor.widget)->h = hSaved; widgetOverrides++; } - - if (childPreviousState) { - childPreviousState = nextWidgetState(childPreviousState); - if (childPreviousState > endOfContainerInPreviousState) { - childPreviousState = 0; - } - } - childCurrentState = nextWidgetState(childCurrentState); } - widgetStateSize = (uint8_t *)childCurrentState - (uint8_t *)this; - - int xOffset = 0; - int yOffset = 0; - getOverlayOffset(widgetCursor, xOffset, yOffset); - - const Style *style = getStyle(widgetCursor.widget->style); - - display::setBufferBounds( - displayBufferIndex, - widgetCursor.x, - widgetCursor.y, - overlay->width, - overlay->height, - (widget->flags & SHADOW_FLAG) != 0, - style->opacity, - xOffset, - yOffset, - nullptr - ); + g_xOverlayOffset = 0; + g_yOverlayOffset = 0; + + if (g_findCallback == nullptr) { + const Style *style = getStyle(widgetCursor.widget->style); + + display::setBufferBounds( + displayBufferIndex, + widgetCursor.x, + widgetCursor.y, + overlay->width, + overlay->height, + (widget->flags & SHADOW_FLAG) != 0, + style->opacity, + xOffset, + yOffset, + nullptr + ); + } + + widgetCursor.widget = savedWidget; } } // namespace gui diff --git a/src/eez/gui/widgets/containers/container.h b/src/eez/gui/widgets/containers/container.h index 510e86a1f..f017ae71d 100644 --- a/src/eez/gui/widgets/containers/container.h +++ b/src/eez/gui/widgets/containers/container.h @@ -28,15 +28,16 @@ struct ContainerWidget : public Widget { }; struct ContainerWidgetState : public WidgetState { + WidgetStateFlags flags; + Overlay *overlay; int overlayState; int displayBufferIndex; + bool displayBufferSelected; - ContainerWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } - - void draw(WidgetState *previousState) override; - - void drawOverlay(WidgetState *previousState, Overlay *overlay); + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; + void enumChildren(WidgetCursor &widgetCursor) override; + void renderOverlayChildren(WidgetCursor &widgetCursor); }; } // namespace gui diff --git a/src/eez/gui/widgets/containers/grid.cpp b/src/eez/gui/widgets/containers/grid.cpp index b607582d8..f4d2b974b 100644 --- a/src/eez/gui/widgets/containers/grid.cpp +++ b/src/eez/gui/widgets/containers/grid.cpp @@ -25,32 +25,20 @@ namespace gui { #define GRID_FLOW_ROW 1 #define GRID_FLOW_COLUMN 2 -void GridWidgetState::draw(WidgetState *previousState) { +bool GridWidgetState::updateState(const WidgetCursor &widgetCursor) { auto widget = (const GridWidget *)widgetCursor.widget; + startPosition = ytDataGetPosition(widgetCursor, widget->data); + count = eez::gui::count(widgetCursor, widget->data); + return false; +} - int startPosition = ytDataGetPosition(widgetCursor, widget->data); - - // refresh when startPosition changes - data = startPosition; - - int count = eez::gui::count(widgetCursor, widget->data); - +void GridWidgetState::enumChildren(WidgetCursor &widgetCursor) { if (count > 0) { - WidgetState *childCurrentState = this; - WidgetState *childPreviousState = previousState; - WidgetCursor childWidgetCursor = getFirstChildWidgetCursor(widgetCursor, childCurrentState, childPreviousState); - - if (previousState && previousState->data != data) { - childPreviousState = 0; - } - - WidgetState *endOfContainerInPreviousState = 0; - if (previousState) { - endOfContainerInPreviousState = nextWidgetState(previousState); - } + auto widget = (const GridWidget *)widgetCursor.widget; const Widget *childWidget = widget->itemWidget.ptr(widgetCursor.assets); - childWidgetCursor.widget = childWidget; + auto savedWidget = widgetCursor.widget; + widgetCursor.widget = childWidget; auto savedX = widgetCursor.x; auto savedY = widgetCursor.y; @@ -61,22 +49,14 @@ void GridWidgetState::draw(WidgetState *previousState) { Value oldValue; for (int index = startPosition; index < count; ++index) { - select(childWidgetCursor, widget->data, index, oldValue); - - childWidgetCursor.x = savedX + xOffset; - childWidgetCursor.y = savedY + yOffset; + select(widgetCursor, widget->data, index, oldValue); - childWidgetCursor.pushIterator(index); - enumWidget(childWidgetCursor, childCurrentState, childPreviousState); - childWidgetCursor.popIterator(); + widgetCursor.x = savedX + xOffset; + widgetCursor.y = savedY + yOffset; - if (childPreviousState) { - childPreviousState = nextWidgetState(childPreviousState); - if (childPreviousState > endOfContainerInPreviousState) { - childPreviousState = 0; - } - } - childCurrentState = nextWidgetState(childCurrentState); + widgetCursor.pushIterator(index); + enumWidget(widgetCursor); + widgetCursor.popIterator(); if (widget->gridFlow == GRID_FLOW_ROW) { if (xOffset + childWidget->w < widget->w) { @@ -103,9 +83,12 @@ void GridWidgetState::draw(WidgetState *previousState) { } } - deselect(childWidgetCursor, widget->data, oldValue); - - widgetStateSize = (uint8_t *)childCurrentState - (uint8_t *)this; + deselect(widgetCursor, widget->data, oldValue); + + widgetCursor.widget = savedWidget; + + widgetCursor.x = savedX; + widgetCursor.y = savedY; } } diff --git a/src/eez/gui/widgets/containers/grid.h b/src/eez/gui/widgets/containers/grid.h index a24451d50..a554db2d7 100644 --- a/src/eez/gui/widgets/containers/grid.h +++ b/src/eez/gui/widgets/containers/grid.h @@ -27,10 +27,11 @@ struct GridWidget : public Widget { }; struct GridWidgetState : public WidgetState { - GridWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } + int startPosition; + int count; - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void enumChildren(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/containers/layout_view.cpp b/src/eez/gui/widgets/containers/layout_view.cpp index 1dcbe6cfd..77b573bfb 100644 --- a/src/eez/gui/widgets/containers/layout_view.cpp +++ b/src/eez/gui/widgets/containers/layout_view.cpp @@ -33,74 +33,72 @@ int getLayoutId(const WidgetCursor &widgetCursor) { return layoutView->layout; } -void LayoutViewWidgetState::draw(WidgetState *previousState) { - auto widget = (const LayoutViewWidget *)widgetCursor.widget; +bool LayoutViewWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const LayoutViewWidget *)widgetCursor.widget; Value oldContext; Value newContext; if (widget->context) { setContext((WidgetCursor &)widgetCursor, widget->context, oldContext, newContext); - context = newContext; + WIDGET_STATE(context, newContext); } else { - context = Value(); + WIDGET_STATE(context, Value()); } - data = getLayoutId(widgetCursor); - - bool refresh = - !previousState || - previousState->flags.active != flags.active || - previousState->data != data || - ((LayoutViewWidgetState *)previousState)->context != context; - - if (refresh) { - const Style* style = getStyle(widget->style); - drawRectangle(widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active, false, true); - } + WIDGET_STATE(flags.active, g_isActiveWidget); int layoutId = getLayoutId(widgetCursor); - auto layout = getPageAsset(layoutId, widgetCursor); + auto layout = getPageAsset(layoutId); + if (layout) { + WIDGET_STATE(data, layoutId); + } else { + WIDGET_STATE(data, 0); + } - if (layout) { - WidgetState *childCurrentState = this; - WidgetState *childPreviousState = previousState; - WidgetCursor childWidgetCursor = getFirstChildWidgetCursor(widgetCursor, childCurrentState, childPreviousState); - - if ( - previousState && - ( - previousState->data != data || - ((LayoutViewWidgetState *)previousState)->context != context - ) - ) { - childPreviousState = 0; - } + return !hasPreviousState; +} - auto layoutView = (PageAsset *)layout; +void LayoutViewWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const LayoutViewWidget *)widgetCursor.widget; + const Style* style = getStyle(widget->style); + drawRectangle(widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active, false, true); + repainted = true; +} - auto &widgets = layoutView->widgets; +void LayoutViewWidgetState::enumChildren(WidgetCursor &widgetCursor) { + if (repainted) { + repainted = false; + if (widgetCursor.hasPreviousState) { + freeWidgetStates(widgetCursor.currentState); + widgetCursor.hasPreviousState = false; + } + } - WidgetState *endOfContainerInPreviousState = 0; - if (previousState) { - endOfContainerInPreviousState = nextWidgetState(previousState); - } + if (g_findCallback != nullptr) { + auto widget = (const LayoutViewWidget *)widgetCursor.widget; + if (widget->context) { + Value oldContext; + Value newContext; + setContext((WidgetCursor &)widgetCursor, widget->context, oldContext, newContext); + } + } + auto layoutId = data.getInt(); + if (layoutId) { + auto layout = getPageAsset(layoutId, widgetCursor); + + auto savedWidget = widgetCursor.widget; + + auto &widgets = layout->widgets; auto widgetPtr = widgets.itemsPtr(widgetCursor.assets); for (uint32_t index = 0; index < widgets.count; ++index, ++widgetPtr) { - childWidgetCursor.widget = (const Widget *)widgetPtr->ptr(widgetCursor.assets); - - enumWidget(childWidgetCursor, childCurrentState, childPreviousState); + widgetCursor.widget = (const Widget *)widgetPtr->ptr(widgetCursor.assets); - if (childPreviousState) { - childPreviousState = nextWidgetState(childPreviousState); - if (childPreviousState > endOfContainerInPreviousState) { - childPreviousState = 0; - } - } - childCurrentState = nextWidgetState(childCurrentState); + enumWidget(widgetCursor); } - widgetStateSize = (uint8_t *)childCurrentState - (uint8_t *)this; + widgetCursor.widget = savedWidget; } } diff --git a/src/eez/gui/widgets/containers/layout_view.h b/src/eez/gui/widgets/containers/layout_view.h index 5a59c9c33..0fd6b853e 100644 --- a/src/eez/gui/widgets/containers/layout_view.h +++ b/src/eez/gui/widgets/containers/layout_view.h @@ -28,12 +28,14 @@ struct LayoutViewWidget : public Widget { }; struct LayoutViewWidgetState : public WidgetState { + WidgetStateFlags flags; + Value data; Value context; + bool repainted; - LayoutViewWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; + void enumChildren(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/containers/list.cpp b/src/eez/gui/widgets/containers/list.cpp index 3f35624a5..8e3386e6b 100644 --- a/src/eez/gui/widgets/containers/list.cpp +++ b/src/eez/gui/widgets/containers/list.cpp @@ -25,32 +25,20 @@ namespace gui { #define LIST_TYPE_VERTICAL 1 #define LIST_TYPE_HORIZONTAL 2 -void ListWidgetState::draw(WidgetState *previousState) { +bool ListWidgetState::updateState(const WidgetCursor &widgetCursor) { auto widget = (const ListWidget *)widgetCursor.widget; + startPosition = ytDataGetPosition(widgetCursor, widget->data); + count = eez::gui::count(widgetCursor, widget->data); + return false; +} - int startPosition = ytDataGetPosition(widgetCursor, widget->data); - - // refresh when startPosition changes - data = startPosition; - - int count = eez::gui::count(widgetCursor, widget->data); - +void ListWidgetState::enumChildren(WidgetCursor &widgetCursor) { if (count > 0) { - WidgetState *childCurrentState = this; - WidgetState *childPreviousState = previousState; - WidgetCursor childWidgetCursor = getFirstChildWidgetCursor(widgetCursor, childCurrentState, childPreviousState); - - if (previousState && previousState->data != data) { - childPreviousState = 0; - } - - WidgetState *endOfContainerInPreviousState = 0; - if (previousState) { - endOfContainerInPreviousState = nextWidgetState(previousState); - } + auto widget = (const ListWidget *)widgetCursor.widget; - const Widget *childWidget = widget->itemWidget.ptr(widgetCursor.assets); - childWidgetCursor.widget = childWidget; + const Widget *childWidget = widget->itemWidget.ptr(widgetCursor.assets); + auto savedWidget = widgetCursor.widget; + widgetCursor.widget = childWidget; auto savedX = widgetCursor.x; auto savedY = widgetCursor.y; @@ -60,42 +48,37 @@ void ListWidgetState::draw(WidgetState *previousState) { Value oldValue; for (int index = startPosition; index < count; ++index) { - select(childWidgetCursor, widget->data, index, oldValue); + select(widgetCursor, widget->data, index, oldValue); if (widget->listType == LIST_TYPE_VERTICAL) { if (offset < widget->h) { - childWidgetCursor.y = savedY + offset; - childWidgetCursor.pushIterator(index); - enumWidget(childWidgetCursor, childCurrentState, childPreviousState); - childWidgetCursor.popIterator(); + widgetCursor.y = savedY + offset; + widgetCursor.pushIterator(index); + enumWidget(widgetCursor); + widgetCursor.popIterator(); offset += childWidget->h + widget->gap; } else { break; } } else { if (offset < widget->w) { - childWidgetCursor.x = savedX + offset; - childWidgetCursor.pushIterator(index); - enumWidget(childWidgetCursor, childCurrentState, childPreviousState); - childWidgetCursor.popIterator(); + widgetCursor.x = savedX + offset; + widgetCursor.pushIterator(index); + enumWidget(widgetCursor); + widgetCursor.popIterator(); offset += childWidget->w + widget->gap; } else { break; } } - - if (childPreviousState) { - childPreviousState = nextWidgetState(childPreviousState); - if (childPreviousState > endOfContainerInPreviousState) { - childPreviousState = 0; - } - } - childCurrentState = nextWidgetState(childCurrentState); } - deselect(childWidgetCursor, widget->data, oldValue); - - widgetStateSize = (uint8_t *)childCurrentState - (uint8_t *)this; + deselect(widgetCursor, widget->data, oldValue); + + widgetCursor.widget = savedWidget; + + widgetCursor.x = savedX; + widgetCursor.y = savedY; } } diff --git a/src/eez/gui/widgets/containers/list.h b/src/eez/gui/widgets/containers/list.h index e90cb550d..2ceaa0107 100644 --- a/src/eez/gui/widgets/containers/list.h +++ b/src/eez/gui/widgets/containers/list.h @@ -28,10 +28,11 @@ struct ListWidget : public Widget { }; struct ListWidgetState : public WidgetState { - ListWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } + int startPosition; + int count; - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void enumChildren(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/containers/select.cpp b/src/eez/gui/widgets/containers/select.cpp index 1ff2044b8..c9c42943f 100644 --- a/src/eez/gui/widgets/containers/select.cpp +++ b/src/eez/gui/widgets/containers/select.cpp @@ -22,35 +22,47 @@ namespace eez { namespace gui { -void SelectWidgetState::draw(WidgetState *previousState) { - Value indexValue = get(widgetCursor, widgetCursor.widget->data); - data = indexValue; - - auto selectWidget = (const SelectWidget *)widgetCursor.widget; - if (selectWidget->widgets.count > 0) { - int err; +bool SelectWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const SelectWidget *)widgetCursor.widget; + if (widget->widgets.count > 0) { + Value indexValue = get(widgetCursor, widgetCursor.widget->data); + int err; int index = indexValue.toInt32(&err); - if (err) { - index = indexValue.getInt(); - } + if (err) { + index = indexValue.getInt(); + } + WIDGET_STATE(widgetIndex, index < 0 || index >= (int)widget->widgets.count ? 0 : index); + } else { + WIDGET_STATE(widgetIndex, -1); + } - auto widgetIndex = index < 0 || index >= (int)selectWidget->widgets.count ? 0 : index; + return !hasPreviousState; +} - WidgetState *childCurrentState = this; - WidgetState *childPreviousState = previousState; - WidgetCursor childWidgetCursor = getFirstChildWidgetCursor(widgetCursor, childCurrentState, childPreviousState); +void SelectWidgetState::render(WidgetCursor &widgetCursor) { + repainted = true; +} - childWidgetCursor.widget = selectWidget->widgets.item(widgetCursor.assets, widgetIndex); +void SelectWidgetState::enumChildren(WidgetCursor &widgetCursor) { + if (repainted) { + repainted = false; + if (widgetCursor.hasPreviousState) { + freeWidgetStates(widgetCursor.currentState); + widgetCursor.hasPreviousState = false; + } + } + + if (widgetIndex != -1) { + auto widget = (const SelectWidget *)widgetCursor.widget; - if (previousState && previousState->data != data) { - childPreviousState = 0; - } + auto savedWidget = widgetCursor.widget; + widgetCursor.widget = widget->widgets.item(widgetCursor.assets, widgetIndex); - enumWidget(childWidgetCursor, childCurrentState, childPreviousState); + enumWidget(widgetCursor); - childCurrentState = nextWidgetState(childCurrentState); - widgetStateSize = (uint8_t *)childCurrentState - (uint8_t *)this; - } + widgetCursor.widget = savedWidget; + } } } // namespace gui diff --git a/src/eez/gui/widgets/containers/select.h b/src/eez/gui/widgets/containers/select.h index 653e4e721..0f06e5cbd 100644 --- a/src/eez/gui/widgets/containers/select.h +++ b/src/eez/gui/widgets/containers/select.h @@ -26,10 +26,12 @@ struct SelectWidget : public Widget { }; struct SelectWidgetState : public WidgetState { - SelectWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } + int widgetIndex; + bool repainted; - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; + void enumChildren(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/display_data.cpp b/src/eez/gui/widgets/display_data.cpp index 185ca7dd4..f5d86e723 100644 --- a/src/eez/gui/widgets/display_data.cpp +++ b/src/eez/gui/widgets/display_data.cpp @@ -48,87 +48,103 @@ int findStartOfUnit(char *text, int i) { return i; } -void DisplayDataWidgetState::refreshTextData(DisplayDataWidgetState *previousState) { - if (previousState && data != previousState->data) { - auto widget = (const DisplayDataWidget *)widgetCursor.widget; +bool DisplayDataWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const DisplayDataWidget *)widgetCursor.widget; + const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); + + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(flags.focused, isFocusWidget(widgetCursor)); + WIDGET_STATE(flags.blinking, g_isBlinkTime && isBlinking(widgetCursor, widget->data)); + + bool refreshData = true; + auto newData = get(widgetCursor, widget->data); + if (hasPreviousState && data != newData) { uint32_t refreshRate = getTextRefreshRate(widgetCursor, widget->data); - if (refreshRate != 0) { - if (dataRefreshLastTime - previousState->dataRefreshLastTime < refreshRate) { - data = previousState->data; - dataRefreshLastTime = previousState->dataRefreshLastTime; - } + if (refreshRate != 0 && millis() - dataRefreshLastTime < refreshRate) { + refreshData = false; } } + if (refreshData) { + WIDGET_STATE(data, newData); + } + + WIDGET_STATE(color, flags.focused ? style->focus_color : getColor(widgetCursor, widget->data, style)); + WIDGET_STATE(backgroundColor, flags.focused ? style->focus_background_color : getBackgroundColor(widgetCursor, widget->data, style)); + WIDGET_STATE(activeColor, flags.focused ? style->focus_background_color : getActiveColor(widgetCursor, widget->data, style)); + WIDGET_STATE(activeBackgroundColor, flags.focused ? style->focus_color : getActiveBackgroundColor(widgetCursor, widget->data, style)); + + bool cursorVisible = millis() % (2 * CONF_GUI_TEXT_CURSOR_BLINK_TIME_MS) < CONF_GUI_TEXT_CURSOR_BLINK_TIME_MS; + WIDGET_STATE(cursorPosition, cursorVisible ? getTextCursorPosition(widgetCursor, widget->data) : -1); + + WIDGET_STATE(xScroll, getXScroll(widgetCursor)); + + return !hasPreviousState; } -void DisplayDataWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (DisplayDataWidgetState *)previousStateBase; - refreshTextData(previousState); - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const DisplayDataWidget *)widgetCursor.widget; - const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - - char text[64]; - data.toText(text, sizeof(text)); - - char *start = text; - - int length = -1; - - if (widget->displayOption != DISPLAY_OPTION_ALL) { - if (data.getType() == VALUE_TYPE_FLOAT) { - if (widget->displayOption == DISPLAY_OPTION_INTEGER) { - int i = findStartOfFraction(text); - text[i] = 0; - } else if (widget->displayOption == DISPLAY_OPTION_FRACTION) { - int i = findStartOfFraction(text); - start = text + i; - } else if (widget->displayOption == DISPLAY_OPTION_FRACTION_AND_UNIT) { - int i = findStartOfFraction(text); - int k = findStartOfUnit(text, i); - if (i < k) { - start = text + i; - text[k] = 0; - } - else { - stringCopy(text, sizeof(text), ".0"); - } - } else if (widget->displayOption == DISPLAY_OPTION_UNIT) { - int i = findStartOfUnit(text, 0); - start = text + i; - } else if (widget->displayOption == DISPLAY_OPTION_INTEGER_AND_FRACTION) { - int i = findStartOfUnit(text, 0); - text[i] = 0; - } - - // trim left - while (*start && *start == ' ') { - start++; - } - - // trim right - length = strlen(start); - if (length > 0 && start[length - 1] == ' ') { - length--; - } - } else { - if ( - widget->displayOption != DISPLAY_OPTION_INTEGER && - widget->displayOption != DISPLAY_OPTION_INTEGER_AND_FRACTION - ) { - *text = 0; - } - } - } +void DisplayDataWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const DisplayDataWidget *)widgetCursor.widget; + const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); + + char text[64]; + data.toText(text, sizeof(text)); - drawText(start, length, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - style, flags.active, - flags.blinking, false, - &color, &backgroundColor, &activeColor, &activeBackgroundColor, - data.getType() == VALUE_TYPE_FLOAT || widget->data == EEZ_CONF_DATA_ID_EDIT_UNIT, - cursorPosition, xScroll); + char *start = text; + + int length = -1; + + if (widget->displayOption != DISPLAY_OPTION_ALL) { + if (data.getType() == VALUE_TYPE_FLOAT) { + if (widget->displayOption == DISPLAY_OPTION_INTEGER) { + int i = findStartOfFraction(text); + text[i] = 0; + } else if (widget->displayOption == DISPLAY_OPTION_FRACTION) { + int i = findStartOfFraction(text); + start = text + i; + } else if (widget->displayOption == DISPLAY_OPTION_FRACTION_AND_UNIT) { + int i = findStartOfFraction(text); + int k = findStartOfUnit(text, i); + if (i < k) { + start = text + i; + text[k] = 0; + } + else { + stringCopy(text, sizeof(text), ".0"); + } + } else if (widget->displayOption == DISPLAY_OPTION_UNIT) { + int i = findStartOfUnit(text, 0); + start = text + i; + } else if (widget->displayOption == DISPLAY_OPTION_INTEGER_AND_FRACTION) { + int i = findStartOfUnit(text, 0); + text[i] = 0; + } + + // trim left + while (*start && *start == ' ') { + start++; + } + + // trim right + length = strlen(start); + if (length > 0 && start[length - 1] == ' ') { + length--; + } + } else { + if ( + widget->displayOption != DISPLAY_OPTION_INTEGER && + widget->displayOption != DISPLAY_OPTION_INTEGER_AND_FRACTION + ) { + *text = 0; + } + } } + + drawText(start, length, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + style, flags.active, + flags.blinking, false, + &color, &backgroundColor, &activeColor, &activeBackgroundColor, + data.getType() == VALUE_TYPE_FLOAT || widget->data == EEZ_CONF_DATA_ID_EDIT_UNIT, + cursorPosition, xScroll); } int DISPLAY_DATA_getCharIndexAtPosition(int xPos, const WidgetCursor &widgetCursor) { diff --git a/src/eez/gui/widgets/display_data.h b/src/eez/gui/widgets/display_data.h index 463ea2180..fee10ec72 100644 --- a/src/eez/gui/widgets/display_data.h +++ b/src/eez/gui/widgets/display_data.h @@ -28,6 +28,8 @@ struct DisplayDataWidget : public Widget { }; struct DisplayDataWidgetState : public WidgetState { + WidgetStateFlags flags; + Value data; uint16_t color; uint16_t backgroundColor; uint16_t activeColor; @@ -36,46 +38,8 @@ struct DisplayDataWidgetState : public WidgetState { int16_t cursorPosition; uint8_t xScroll; - DisplayDataWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const DisplayDataWidget *)widgetCursor.widget; - - flags.focused = isFocusWidget(widgetCursor); - - const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - - flags.blinking = g_isBlinkTime && isBlinking(widgetCursor, widget->data); - - data = get(widgetCursor, widget->data); - dataRefreshLastTime = millis(); - - color = flags.focused ? style->focus_color : getColor(widgetCursor, widget->data, style); - backgroundColor = flags.focused ? style->focus_background_color : getBackgroundColor(widgetCursor, widget->data, style); - activeColor = flags.focused ? style->focus_background_color : getActiveColor(widgetCursor, widget->data, style); - activeBackgroundColor = flags.focused ? style->focus_color : getActiveBackgroundColor(widgetCursor, widget->data, style); - - bool cursorVisible = millis() % (2 * CONF_GUI_TEXT_CURSOR_BLINK_TIME_MS) < CONF_GUI_TEXT_CURSOR_BLINK_TIME_MS; - cursorPosition = cursorVisible ? getTextCursorPosition(widgetCursor, widget->data) : -1; - - xScroll = getXScroll(widgetCursor); - } - - bool operator!=(const DisplayDataWidgetState& previousState) { - return - flags.active != previousState.flags.active || - data != previousState.data || - flags.focused != previousState.flags.focused || - flags.blinking != previousState.flags.blinking || - color != previousState.color || - backgroundColor != previousState.backgroundColor || - activeColor != previousState.activeColor || - activeBackgroundColor != previousState.activeBackgroundColor || - cursorPosition != previousState.cursorPosition || - xScroll != previousState.xScroll; - } - - void refreshTextData(DisplayDataWidgetState *previousState); - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; int DISPLAY_DATA_getCharIndexAtPosition(int xPos, const WidgetCursor &widgetCursor); diff --git a/src/eez/gui/widgets/gauge.cpp b/src/eez/gui/widgets/gauge.cpp index 364503c98..a23d67cc3 100644 --- a/src/eez/gui/widgets/gauge.cpp +++ b/src/eez/gui/widgets/gauge.cpp @@ -85,276 +85,282 @@ float firstTick(float n) { //////////////////////////////////////////////////////////////////////////////// -void GaugeWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (GaugeWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const GaugeWidget*)widgetCursor.widget; - - using namespace display; - - float min = get(widgetCursor, widget->min).toFloat(); - float max = get(widgetCursor, widget->max).toFloat(); - float value = data.toFloat(); - float threshold = get(widgetCursor, widget->threshold).toFloat(); - - auto unit = get(widgetCursor, widget->unit).toString(0xa9ddede3).getString(); - - if (isNaN(min) || isNaN(max) || isNaN(value) || isinf(min) || isinf(max) || isinf(value) || min >= max) { - min = 0.0; - max = 1.0f; - value = 0.0f; - } else { - if (value < min) { - value = min; - } else if (value > max) { - value = max; - } - } +bool GaugeWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const GaugeWidget *)widgetCursor.widget; + + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(data, get(widgetCursor, widget->data)); - const Style* style = getStyle(widget->style); - const Style* barStyle = getStyle(widget->barStyle); - const Style* valueStyle = getStyle(widget->valueStyle); - const Style* ticksStyle = getStyle(widget->ticksStyle); - const Style* thresholdStyle = getStyle(widget->thresholdStyle); - - auto isActive = flags.active; - - // auto colorBackground = getColor16FromIndex(style->background_color); - auto colorBorder = getColor16FromIndex(isActive ? style->active_color : style->color); - auto colorBar = getColor16FromIndex(isActive ? barStyle->active_color : barStyle->color); - - auto xCenter = widget->w / 2; - auto yCenter = widget->h - 8; - - // clear background - setColor(isActive ? style->active_background_color : style->background_color); - fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w - 1, widgetCursor.y + widget->h - 1, 0); - - // init AGG - agg::rendering_buffer rbuf; - rbuf.attach((uint8_t *)getBufferPointer(), getDisplayWidth(), getDisplayHeight(), getDisplayWidth() * DISPLAY_BPP / 8); - Agg2D graphics; - graphics.attach(rbuf.buf(), rbuf.width(), rbuf.height(), rbuf.stride()); - graphics.clipBox(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w, widgetCursor.y + widget->h); - graphics.translate(widgetCursor.x, widgetCursor.y); - - // draw frame - if (style->border_size_left > 0) { - graphics.lineWidth(style->border_size_left); - graphics.lineColor(COLOR_TO_R(colorBorder), COLOR_TO_G(colorBorder), COLOR_TO_B(colorBorder)); - graphics.noFill(); - graphics.roundedRect( - style->border_size_left / 2.0, - style->border_size_left / 2.0, - widget->w - style->border_size_left, - widget->h - style->border_size_left, - style->border_radius - ); + return !hasPreviousState; +} + +void GaugeWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const GaugeWidget*)widgetCursor.widget; + + using namespace display; + + float min = get(widgetCursor, widget->min).toFloat(); + float max = get(widgetCursor, widget->max).toFloat(); + float value = data.toFloat(); + float threshold = get(widgetCursor, widget->threshold).toFloat(); + + auto unit = get(widgetCursor, widget->unit).toString(0xa9ddede3).getString(); + + if (isNaN(min) || isNaN(max) || isNaN(value) || isinf(min) || isinf(max) || isinf(value) || min >= max) { + min = 0.0; + max = 1.0f; + value = 0.0f; + } else { + if (value < min) { + value = min; + } else if (value > max) { + value = max; } + } - static const int PADDING_HORZ = 56; - static const int TICK_LINE_LENGTH = 5; - static const int TICK_LINE_WIDTH = 1; - static const int TICK_TEXT_GAP = 1; - static const int THRESHOLD_LINE_WIDTH = 2; + const Style* style = getStyle(widget->style); + const Style* barStyle = getStyle(widget->barStyle); + const Style* valueStyle = getStyle(widget->valueStyle); + const Style* ticksStyle = getStyle(widget->ticksStyle); + const Style* thresholdStyle = getStyle(widget->thresholdStyle); - // draw border - auto radBorderOuter = (widget->w - PADDING_HORZ) / 2; + auto isActive = flags.active; - auto BORDER_WIDTH = radBorderOuter / 3; - auto BAR_WIDTH = BORDER_WIDTH / 2; + // auto colorBackground = getColor16FromIndex(style->background_color); + auto colorBorder = getColor16FromIndex(isActive ? style->active_color : style->color); + auto colorBar = getColor16FromIndex(isActive ? barStyle->active_color : barStyle->color); - auto radBorderInner = radBorderOuter - BORDER_WIDTH; - graphics.resetPath(); - graphics.noFill(); + auto xCenter = widget->w / 2; + auto yCenter = widget->h - 8; + + // clear background + setColor(isActive ? style->active_background_color : style->background_color); + fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w - 1, widgetCursor.y + widget->h - 1, 0); + + // init AGG + agg::rendering_buffer rbuf; + rbuf.attach((uint8_t *)getBufferPointer(), getDisplayWidth(), getDisplayHeight(), getDisplayWidth() * DISPLAY_BPP / 8); + Agg2D graphics; + graphics.attach(rbuf.buf(), rbuf.width(), rbuf.height(), rbuf.stride()); + graphics.clipBox(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w, widgetCursor.y + widget->h); + graphics.translate(widgetCursor.x, widgetCursor.y); + + // draw frame + if (style->border_size_left > 0) { + graphics.lineWidth(style->border_size_left); graphics.lineColor(COLOR_TO_R(colorBorder), COLOR_TO_G(colorBorder), COLOR_TO_B(colorBorder)); - graphics.lineWidth(1.5); - arcBar(graphics, xCenter, yCenter, radBorderOuter, radBorderInner, 0); - graphics.drawPath(); + graphics.noFill(); + graphics.roundedRect( + style->border_size_left / 2.0, + style->border_size_left / 2.0, + widget->w - style->border_size_left, + widget->h - style->border_size_left, + style->border_radius + ); + } + + static const int PADDING_HORZ = 56; + static const int TICK_LINE_LENGTH = 5; + static const int TICK_LINE_WIDTH = 1; + static const int TICK_TEXT_GAP = 1; + static const int THRESHOLD_LINE_WIDTH = 2; + + // draw border + auto radBorderOuter = (widget->w - PADDING_HORZ) / 2; + + auto BORDER_WIDTH = radBorderOuter / 3; + auto BAR_WIDTH = BORDER_WIDTH / 2; + + auto radBorderInner = radBorderOuter - BORDER_WIDTH; + graphics.resetPath(); + graphics.noFill(); + graphics.lineColor(COLOR_TO_R(colorBorder), COLOR_TO_G(colorBorder), COLOR_TO_B(colorBorder)); + graphics.lineWidth(1.5); + arcBar(graphics, xCenter, yCenter, radBorderOuter, radBorderInner, 0); + graphics.drawPath(); + + // draw bar + auto radBarOuter = (widget->w - PADDING_HORZ) / 2 - (BORDER_WIDTH - BAR_WIDTH) / 2; + auto radBarInner = radBarOuter - BAR_WIDTH; + auto angle = remap(value, min, 180.0f, max, 0.0f); + graphics.resetPath(); + graphics.noLine(); + graphics.fillColor(COLOR_TO_R(colorBar), COLOR_TO_G(colorBar), COLOR_TO_B(colorBar)); + graphics.lineWidth(1.5); + arcBar(graphics, xCenter, yCenter, radBarOuter, radBarInner, angle); + graphics.drawPath(); + + // draw threshold + auto thresholdAngleDeg = remap(threshold, min, 180.0f, max, 0); + if (thresholdAngleDeg >= 0 && thresholdAngleDeg <= 180.0f) { + auto thresholdAngle = Agg2D::deg2Rad(thresholdAngleDeg); + float acos = cosf(thresholdAngle); + float asin = sinf(thresholdAngle); + int x1 = floorf(xCenter + radBarInner * acos); + int y1 = floorf(yCenter - radBarInner * asin); + int x2 = floorf(xCenter + radBarOuter * acos); + int y2 = floorf(yCenter - radBarOuter * asin); - // draw bar - auto radBarOuter = (widget->w - PADDING_HORZ) / 2 - (BORDER_WIDTH - BAR_WIDTH) / 2; - auto radBarInner = radBarOuter - BAR_WIDTH; - auto angle = remap(value, min, 180.0f, max, 0.0f); graphics.resetPath(); - graphics.noLine(); - graphics.fillColor(COLOR_TO_R(colorBar), COLOR_TO_G(colorBar), COLOR_TO_B(colorBar)); - graphics.lineWidth(1.5); - arcBar(graphics, xCenter, yCenter, radBarOuter, radBarInner, angle); + graphics.noFill(); + auto thresholdColor = getColor16FromIndex(isActive ? thresholdStyle->active_color : thresholdStyle->color); + graphics.lineColor(COLOR_TO_R(thresholdColor), COLOR_TO_G(thresholdColor), COLOR_TO_B(thresholdColor)); + graphics.lineWidth(THRESHOLD_LINE_WIDTH); + graphics.moveTo(x1, y1); + graphics.lineTo(x2, y2); graphics.drawPath(); + } - // draw threshold - auto thresholdAngleDeg = remap(threshold, min, 180.0f, max, 0); - if (thresholdAngleDeg >= 0 && thresholdAngleDeg <= 180.0f) { - auto thresholdAngle = Agg2D::deg2Rad(thresholdAngleDeg); - float acos = cosf(thresholdAngle); - float asin = sinf(thresholdAngle); - int x1 = floorf(xCenter + radBarInner * acos); - int y1 = floorf(yCenter - radBarInner * asin); - int x2 = floorf(xCenter + radBarOuter * acos); - int y2 = floorf(yCenter - radBarOuter * asin); + // draw ticks + font::Font ticksFont = styleGetFont(ticksStyle); + auto ft = firstTick(max - min); + auto ticksRad = radBorderOuter + 1; + for (auto tickValue = min; tickValue <= max; tickValue += ft) { + auto tickAngleDeg = remap(tickValue, min, 180.0f, max, 0); + if (tickAngleDeg <= 180.0) { + auto tickAngle = Agg2D::deg2Rad(tickAngleDeg); + float acos = cosf(tickAngle); + float asin = sinf(tickAngle); + int x1 = floorf(xCenter + ticksRad * acos); + int y1 = floorf(yCenter - ticksRad * asin); + int x2 = floorf(xCenter + (ticksRad + TICK_LINE_LENGTH) * acos); + int y2 = floorf(yCenter - (ticksRad + TICK_LINE_LENGTH) * asin); graphics.resetPath(); graphics.noFill(); - auto thresholdColor = getColor16FromIndex(isActive ? thresholdStyle->active_color : thresholdStyle->color); - graphics.lineColor(COLOR_TO_R(thresholdColor), COLOR_TO_G(thresholdColor), COLOR_TO_B(thresholdColor)); - graphics.lineWidth(THRESHOLD_LINE_WIDTH); + auto tickColor = getColor16FromIndex(isActive ? ticksStyle->active_color : ticksStyle->color); + graphics.lineColor(COLOR_TO_R(tickColor), COLOR_TO_G(tickColor), COLOR_TO_B(tickColor)); + graphics.lineWidth(TICK_LINE_WIDTH); graphics.moveTo(x1, y1); graphics.lineTo(x2, y2); graphics.drawPath(); - } - // draw ticks - font::Font ticksFont = styleGetFont(ticksStyle); - auto ft = firstTick(max - min); - auto ticksRad = radBorderOuter + 1; - for (auto tickValue = min; tickValue <= max; tickValue += ft) { - auto tickAngleDeg = remap(tickValue, min, 180.0f, max, 0); - if (tickAngleDeg <= 180.0) { - auto tickAngle = Agg2D::deg2Rad(tickAngleDeg); - float acos = cosf(tickAngle); - float asin = sinf(tickAngle); - int x1 = floorf(xCenter + ticksRad * acos); - int y1 = floorf(yCenter - ticksRad * asin); - int x2 = floorf(xCenter + (ticksRad + TICK_LINE_LENGTH) * acos); - int y2 = floorf(yCenter - (ticksRad + TICK_LINE_LENGTH) * asin); - - graphics.resetPath(); - graphics.noFill(); - auto tickColor = getColor16FromIndex(isActive ? ticksStyle->active_color : ticksStyle->color); - graphics.lineColor(COLOR_TO_R(tickColor), COLOR_TO_G(tickColor), COLOR_TO_B(tickColor)); - graphics.lineWidth(TICK_LINE_WIDTH); - graphics.moveTo(x1, y1); - graphics.lineTo(x2, y2); - graphics.drawPath(); - - char tickText[50]; - snprintf(tickText, sizeof(tickText), "%g", tickValue); - if (unit && *unit) { - stringAppendString(tickText, sizeof(tickText), " "); - stringAppendString(tickText, sizeof(tickText), unit); - } - - auto tickTextWidth = display::measureStr(tickText, -1, ticksFont); - if (tickAngleDeg == 180.0) { - drawText( - tickText, - -1, - widgetCursor.x + xCenter - - radBorderOuter - - TICK_TEXT_GAP - - tickTextWidth, - widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), - tickTextWidth, - ticksFont.getAscent(), - ticksStyle, - isActive, - false, - false, - nullptr, - nullptr, - nullptr, - nullptr - ); - } else if (tickAngleDeg > 90.0) { - drawText( - tickText, - -1, - widgetCursor.x + x2 - TICK_TEXT_GAP - tickTextWidth, - widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), - tickTextWidth, - ticksFont.getAscent(), - ticksStyle, - isActive, - false, - false, - nullptr, - nullptr, - nullptr, - nullptr - ); - } else if (tickAngleDeg == 90.0) { - drawText( - tickText, - -1, - widgetCursor.x + x2 - tickTextWidth / 2, - widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), - tickTextWidth, - ticksFont.getAscent(), - ticksStyle, - isActive, - false, - false, - nullptr, - nullptr, - nullptr, - nullptr - ); - } else if (tickAngleDeg > 0) { - drawText( - tickText, - -1, - widgetCursor.x + x2 + TICK_TEXT_GAP, - widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), - tickTextWidth, - ticksFont.getAscent(), - ticksStyle, - isActive, - false, - false, - nullptr, - nullptr, - nullptr, - nullptr - ); - } else { - drawText( - tickText, - -1, - widgetCursor.x + xCenter + radBorderOuter + TICK_TEXT_GAP, - widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), + char tickText[50]; + snprintf(tickText, sizeof(tickText), "%g", tickValue); + if (unit && *unit) { + stringAppendString(tickText, sizeof(tickText), " "); + stringAppendString(tickText, sizeof(tickText), unit); + } + + auto tickTextWidth = display::measureStr(tickText, -1, ticksFont); + if (tickAngleDeg == 180.0) { + drawText( + tickText, + -1, + widgetCursor.x + xCenter - + radBorderOuter - + TICK_TEXT_GAP - tickTextWidth, - ticksFont.getAscent(), - ticksStyle, - isActive, - false, - false, - nullptr, - nullptr, - nullptr, - nullptr - ); - } + widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), + tickTextWidth, + ticksFont.getAscent(), + ticksStyle, + isActive, + false, + false, + nullptr, + nullptr, + nullptr, + nullptr + ); + } else if (tickAngleDeg > 90.0) { + drawText( + tickText, + -1, + widgetCursor.x + x2 - TICK_TEXT_GAP - tickTextWidth, + widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), + tickTextWidth, + ticksFont.getAscent(), + ticksStyle, + isActive, + false, + false, + nullptr, + nullptr, + nullptr, + nullptr + ); + } else if (tickAngleDeg == 90.0) { + drawText( + tickText, + -1, + widgetCursor.x + x2 - tickTextWidth / 2, + widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), + tickTextWidth, + ticksFont.getAscent(), + ticksStyle, + isActive, + false, + false, + nullptr, + nullptr, + nullptr, + nullptr + ); + } else if (tickAngleDeg > 0) { + drawText( + tickText, + -1, + widgetCursor.x + x2 + TICK_TEXT_GAP, + widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), + tickTextWidth, + ticksFont.getAscent(), + ticksStyle, + isActive, + false, + false, + nullptr, + nullptr, + nullptr, + nullptr + ); + } else { + drawText( + tickText, + -1, + widgetCursor.x + xCenter + radBorderOuter + TICK_TEXT_GAP, + widgetCursor.y + y2 - TICK_TEXT_GAP - ticksFont.getAscent(), + tickTextWidth, + ticksFont.getAscent(), + ticksStyle, + isActive, + false, + false, + nullptr, + nullptr, + nullptr, + nullptr + ); } } + } - // draw value - font::Font valueFont = styleGetFont(valueStyle); - char valueText[50]; - snprintf(valueText, sizeof(valueText), "%g", value); - if (unit && *unit) { - stringAppendString(valueText, sizeof(valueText), " "); - stringAppendString(valueText, sizeof(valueText), unit); - } - auto valueTextWidth = display::measureStr(valueText, -1, valueFont); - drawText( - valueText, - -1, - widgetCursor.x + xCenter - valueTextWidth / 2, - widgetCursor.y + yCenter - valueFont.getHeight(), - valueTextWidth, - valueFont.getHeight(), - valueStyle, - isActive, - false, - false, - nullptr, - nullptr, - nullptr, - nullptr - ); - } + // draw value + font::Font valueFont = styleGetFont(valueStyle); + char valueText[50]; + snprintf(valueText, sizeof(valueText), "%g", value); + if (unit && *unit) { + stringAppendString(valueText, sizeof(valueText), " "); + stringAppendString(valueText, sizeof(valueText), unit); + } + auto valueTextWidth = display::measureStr(valueText, -1, valueFont); + drawText( + valueText, + -1, + widgetCursor.x + xCenter - valueTextWidth / 2, + widgetCursor.y + yCenter - valueFont.getHeight(), + valueTextWidth, + valueFont.getHeight(), + valueStyle, + isActive, + false, + false, + nullptr, + nullptr, + nullptr, + nullptr + ); } } // namespace gui diff --git a/src/eez/gui/widgets/gauge.h b/src/eez/gui/widgets/gauge.h index 6fe6bad9d..f25e72916 100644 --- a/src/eez/gui/widgets/gauge.h +++ b/src/eez/gui/widgets/gauge.h @@ -33,19 +33,11 @@ struct GaugeWidget : public Widget { }; struct GaugeWidgetState : public WidgetState { - GaugeWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const GaugeWidget *)widgetCursor.widget; - - data = get(widgetCursor, widget->data); - } - - bool operator!=(const GaugeWidgetState& previousState) { - return - flags.active != previousState.flags.active || - data != previousState.data; - } - - void draw(WidgetState *previousState) override; + WidgetStateFlags flags; + Value data; + + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/input.cpp b/src/eez/gui/widgets/input.cpp index b6524d7e4..2a1319935 100644 --- a/src/eez/gui/widgets/input.cpp +++ b/src/eez/gui/widgets/input.cpp @@ -141,44 +141,53 @@ Value getInputWidgetData(const gui::WidgetCursor &widgetCursor, const Value &dat } } -void InputWidgetState::draw(WidgetState *previousStateBase ) { - auto previousState = (InputWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const InputWidget*)widgetCursor.widget; - - if (widgetCursor.flowState) { - auto inputWidgetExecutionState = (InputWidgetExecutionState *)widgetCursor.flowState->componenentExecutionStates[widget->componentIndex]; - if (!inputWidgetExecutionState) { - inputWidgetExecutionState = ObjectAllocator::allocate(0xa570ccad); - widgetCursor.flowState->componenentExecutionStates[widget->componentIndex] = inputWidgetExecutionState; - } - - getInputWidgetParams( - widgetCursor, - inputWidgetExecutionState->min, - inputWidgetExecutionState->max, - inputWidgetExecutionState->precision, - inputWidgetExecutionState->unit - ); +bool InputWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const InputWidget*)widgetCursor.widget; + const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); + + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(flags.focused, isFocusWidget(widgetCursor)); + WIDGET_STATE(flags.blinking, g_isBlinkTime && styleIsBlink(style)); + WIDGET_STATE(data, get(widgetCursor, widget->data)); + + return !hasPreviousState; +} + +void InputWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const InputWidget*)widgetCursor.widget; + + if (widgetCursor.flowState) { + auto inputWidgetExecutionState = (InputWidgetExecutionState *)widgetCursor.flowState->componenentExecutionStates[widget->componentIndex]; + if (!inputWidgetExecutionState) { + inputWidgetExecutionState = ObjectAllocator::allocate(0xa570ccad); + widgetCursor.flowState->componenentExecutionStates[widget->componentIndex] = inputWidgetExecutionState; } - const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); + getInputWidgetParams( + widgetCursor, + inputWidgetExecutionState->min, + inputWidgetExecutionState->max, + inputWidgetExecutionState->precision, + inputWidgetExecutionState->unit + ); + } + + const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - uint16_t overrideColor = flags.focused ? style->focus_color : overrideStyleColorHook(widgetCursor, style); - uint16_t overrideBackgroundColor = flags.focused ? style->focus_background_color : style->background_color; - uint16_t overrideActiveColor = flags.focused ? style->focus_background_color : overrideActiveStyleColorHook(widgetCursor, style); - uint16_t overrideActiveBackgroundColor = flags.focused ? style->focus_color : style->active_background_color; + uint16_t overrideColor = flags.focused ? style->focus_color : overrideStyleColorHook(widgetCursor, style); + uint16_t overrideBackgroundColor = flags.focused ? style->focus_background_color : style->background_color; + uint16_t overrideActiveColor = flags.focused ? style->focus_background_color : overrideActiveStyleColorHook(widgetCursor, style); + uint16_t overrideActiveBackgroundColor = flags.focused ? style->focus_color : style->active_background_color; - char text[MAX_TEXT_LEN + 1]; - data.toText(text, sizeof(text)); + char text[MAX_TEXT_LEN + 1]; + data.toText(text, sizeof(text)); - drawText(text, -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - style, flags.active, - flags.blinking, - false, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor, - false); - } + drawText(text, -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + style, flags.active, + flags.blinking, + false, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor, + false); } } // namespace gui diff --git a/src/eez/gui/widgets/input.h b/src/eez/gui/widgets/input.h index d8c6831f2..99878ebf1 100644 --- a/src/eez/gui/widgets/input.h +++ b/src/eez/gui/widgets/input.h @@ -33,24 +33,11 @@ struct InputWidget : public Widget { }; struct InputWidgetState : public WidgetState { - InputWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const InputWidget*)widgetCursor.widget; - const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); + WidgetStateFlags flags; + Value data; - flags.focused = isFocusWidget(widgetCursor); - flags.blinking = g_isBlinkTime && styleIsBlink(style); - data = get(widgetCursor, widget->data); - } - - bool operator!=(const InputWidgetState& previousState) { - return - flags.focused != previousState.flags.focused || - flags.active != previousState.flags.active || - flags.blinking != previousState.flags.blinking || - data != previousState.data; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; struct InputWidgetExecutionState : public flow::ComponenentExecutionState { diff --git a/src/eez/gui/widgets/list_graph.cpp b/src/eez/gui/widgets/list_graph.cpp index 683f22ae0..b81834277 100644 --- a/src/eez/gui/widgets/list_graph.cpp +++ b/src/eez/gui/widgets/list_graph.cpp @@ -27,114 +27,120 @@ namespace eez { namespace gui { -void ListGraphWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (ListGraphWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const ListGraphWidget *)widgetCursor.widget; +bool ListGraphWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const ListGraphWidget *)widgetCursor.widget; + + WIDGET_STATE(data, get(widgetCursor, widget->data)); + WIDGET_STATE(cursorData, get(widgetCursor, widget->cursorData)); + + return !hasPreviousState; +} - const Style* style = getStyle(widget->style); - const Style* y1Style = getStyle(widget->y1Style); - const Style* y2Style = getStyle(widget->y2Style); - const Style* cursorStyle = getStyle(widget->cursorStyle); +void ListGraphWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const ListGraphWidget *)widgetCursor.widget; - int iCursor = cursorData.getInt(); - int iRow = iCursor / 3; + const Style* style = getStyle(widget->style); + const Style* y1Style = getStyle(widget->y1Style); + const Style* y2Style = getStyle(widget->y2Style); + const Style* cursorStyle = getStyle(widget->cursorStyle); - // draw background - display::setColor(style->background_color); - display::fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + (int)widget->w - 1, - widgetCursor.y + (int)widget->h - 1); + int iCursor = cursorData.getInt(); + int iRow = iCursor / 3; - int dwellListLength = getFloatListLength(widgetCursor, widget->dwellData); - if (dwellListLength > 0) { - float *dwellList = getFloatList(widgetCursor, widget->dwellData); + // draw background + display::setColor(style->background_color); + display::fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + (int)widget->w - 1, + widgetCursor.y + (int)widget->h - 1); - const Style *styles[2] = { y1Style, y2Style }; + int dwellListLength = getFloatListLength(widgetCursor, widget->dwellData); + if (dwellListLength > 0) { + float *dwellList = getFloatList(widgetCursor, widget->dwellData); - int listLength[2] = { getFloatListLength(widgetCursor, widget->y1Data), - getFloatListLength(widgetCursor, widget->y2Data) }; + const Style *styles[2] = { y1Style, y2Style }; - float *list[2] = { getFloatList(widgetCursor, widget->y1Data), - getFloatList(widgetCursor, widget->y2Data) }; + int listLength[2] = { getFloatListLength(widgetCursor, widget->y1Data), + getFloatListLength(widgetCursor, widget->y2Data) }; - float min[2] = { - getMin(widgetCursor, widget->y1Data).getFloat(), - getMin(widgetCursor, widget->y2Data).getFloat() - }; + float *list[2] = { getFloatList(widgetCursor, widget->y1Data), + getFloatList(widgetCursor, widget->y2Data) }; - float max[2] = { - getMax(widgetCursor, widget->y1Data).getFloat(), - getMax(widgetCursor, widget->y2Data).getFloat() - }; + float min[2] = { + getMin(widgetCursor, widget->y1Data).getFloat(), + getMin(widgetCursor, widget->y2Data).getFloat() + }; - int maxListLength = getFloatListLength(widgetCursor, widget->data); + float max[2] = { + getMax(widgetCursor, widget->y1Data).getFloat(), + getMax(widgetCursor, widget->y2Data).getFloat() + }; - float dwellSum = 0; - for (int i = 0; i < maxListLength; ++i) { - if (i < dwellListLength) { - dwellSum += dwellList[i]; - } else { - dwellSum += dwellList[dwellListLength - 1]; - } - } + int maxListLength = getFloatListLength(widgetCursor, widget->data); - float currentDwellSum = 0; - int xPrev = widgetCursor.x; - int yPrev[2]; - for (int i = 0; i < maxListLength; ++i) { - currentDwellSum += - i < dwellListLength ? dwellList[i] : dwellList[dwellListLength - 1]; - int x1 = xPrev; - int x2; - if (i == maxListLength - 1) { - x2 = widgetCursor.x + (int)widget->w - 1; - } else { - x2 = widgetCursor.x + int(currentDwellSum * (int)widget->w / dwellSum); - } - if (x2 < x1) - x2 = x1; - if (x2 >= widgetCursor.x + (int)widget->w) - x2 = widgetCursor.x + (int)widget->w - 1; + float dwellSum = 0; + for (int i = 0; i < maxListLength; ++i) { + if (i < dwellListLength) { + dwellSum += dwellList[i]; + } else { + dwellSum += dwellList[dwellListLength - 1]; + } + } - if (i == iRow) { - display::setColor(cursorStyle->background_color); - display::fillRect(x1, widgetCursor.y, x2 - 1, - widgetCursor.y + (int)widget->h - 1); - } + float currentDwellSum = 0; + int xPrev = widgetCursor.x; + int yPrev[2]; + for (int i = 0; i < maxListLength; ++i) { + currentDwellSum += + i < dwellListLength ? dwellList[i] : dwellList[dwellListLength - 1]; + int x1 = xPrev; + int x2; + if (i == maxListLength - 1) { + x2 = widgetCursor.x + (int)widget->w - 1; + } else { + x2 = widgetCursor.x + int(currentDwellSum * (int)widget->w / dwellSum); + } + if (x2 < x1) + x2 = x1; + if (x2 >= widgetCursor.x + (int)widget->w) + x2 = widgetCursor.x + (int)widget->w - 1; + + if (i == iRow) { + display::setColor(cursorStyle->background_color); + display::fillRect(x1, widgetCursor.y, x2 - 1, + widgetCursor.y + (int)widget->h - 1); + } - for (int k = 0; k < 2; ++k) { - int j = iCursor % 3 == 2 ? k : 1 - k; + for (int k = 0; k < 2; ++k) { + int j = iCursor % 3 == 2 ? k : 1 - k; - if (listLength[j] > 0) { - display::setColor(styles[j]->color); + if (listLength[j] > 0) { + display::setColor(styles[j]->color); - float value = i < listLength[j] ? list[j][i] : list[j][listLength[j] - 1]; - int y = int((value - min[j]) * widget->h / (max[j] - min[j])); - if (y < 0) - y = 0; - if (y >= (int)widget->h) - y = (int)widget->h - 1; + float value = i < listLength[j] ? list[j][i] : list[j][listLength[j] - 1]; + int y = int((value - min[j]) * widget->h / (max[j] - min[j])); + if (y < 0) + y = 0; + if (y >= (int)widget->h) + y = (int)widget->h - 1; - y = widgetCursor.y + ((int)widget->h - 1) - y; + y = widgetCursor.y + ((int)widget->h - 1) - y; - if (i > 0 && abs(yPrev[j] - y) > 1) { - if (yPrev[j] < y) { - display::drawVLine(x1, yPrev[j] + 1, y - yPrev[j] - 1); - } else { - display::drawVLine(x1, y, yPrev[j] - y - 1); - } + if (i > 0 && abs(yPrev[j] - y) > 1) { + if (yPrev[j] < y) { + display::drawVLine(x1, yPrev[j] + 1, y - yPrev[j] - 1); + } else { + display::drawVLine(x1, y, yPrev[j] - y - 1); } + } - yPrev[j] = y; + yPrev[j] = y; - display::drawHLine(x1, y, x2 - x1); - } + display::drawHLine(x1, y, x2 - x1); } - - xPrev = x2; } + + xPrev = x2; } } } @@ -143,7 +149,7 @@ bool ListGraphWidgetState::hasOnTouch() { return true; } -void ListGraphWidgetState::onTouch(Event &touchEvent) { +void ListGraphWidgetState::onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { if (touchEvent.type == EVENT_TYPE_TOUCH_DOWN || touchEvent.type == EVENT_TYPE_TOUCH_MOVE) { auto widget = (const ListGraphWidget *)widgetCursor.widget; diff --git a/src/eez/gui/widgets/list_graph.h b/src/eez/gui/widgets/list_graph.h index ddba26ea3..90a304715 100644 --- a/src/eez/gui/widgets/list_graph.h +++ b/src/eez/gui/widgets/list_graph.h @@ -32,23 +32,13 @@ struct ListGraphWidget : public Widget { }; struct ListGraphWidgetState : public WidgetState { + Value data; Value cursorData; - ListGraphWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const ListGraphWidget *)widgetCursor.widget; - data = get(widgetCursor, widget->data); - cursorData = get(widgetCursor, widget->cursorData); - } - - bool operator!=(const ListGraphWidgetState& previousState) { - return - data != previousState.data || - cursorData != previousState.cursorData; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; bool hasOnTouch() override; - void onTouch(Event &touchEvent) override; + void onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/multiline_text.cpp b/src/eez/gui/widgets/multiline_text.cpp index 8ceacf83b..363a6a7ec 100644 --- a/src/eez/gui/widgets/multiline_text.cpp +++ b/src/eez/gui/widgets/multiline_text.cpp @@ -24,34 +24,40 @@ namespace eez { namespace gui { -void MultilineTextWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (MultilineTextWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const MultilineTextWidget *)widgetCursor.widget; - const Style* style = getStyle(widget->style); - - if (widget->data) { - if (data.isString()) { - drawMultilineText(data.getString(), widgetCursor.x, - widgetCursor.y, (int)widget->w, (int)widget->h, style, - flags.active, - widget->firstLineIndent, widget->hangingIndent); - } else { - char text[64]; - data.toText(text, sizeof(text)); - drawMultilineText(text, widgetCursor.x, widgetCursor.y, (int)widget->w, - (int)widget->h, style, - flags.active, - widget->firstLineIndent, widget->hangingIndent); - } +bool MultilineTextWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const MultilineTextWidget *)widgetCursor.widget; + + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(data, widget->data ? get(widgetCursor, widget->data) : 0); + + return !hasPreviousState; +} + +void MultilineTextWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const MultilineTextWidget *)widgetCursor.widget; + const Style* style = getStyle(widget->style); + + if (widget->data) { + if (data.isString()) { + drawMultilineText(data.getString(), widgetCursor.x, + widgetCursor.y, (int)widget->w, (int)widget->h, style, + flags.active, + widget->firstLineIndent, widget->hangingIndent); } else { - drawMultilineText( - widget->text.ptr(widgetCursor.assets), - widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - style, flags.active, + char text[64]; + data.toText(text, sizeof(text)); + drawMultilineText(text, widgetCursor.x, widgetCursor.y, (int)widget->w, + (int)widget->h, style, + flags.active, widget->firstLineIndent, widget->hangingIndent); } + } else { + drawMultilineText( + widget->text.ptr(widgetCursor.assets), + widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + style, flags.active, + widget->firstLineIndent, widget->hangingIndent); } }; diff --git a/src/eez/gui/widgets/multiline_text.h b/src/eez/gui/widgets/multiline_text.h index fefe0a7fb..e6362c181 100644 --- a/src/eez/gui/widgets/multiline_text.h +++ b/src/eez/gui/widgets/multiline_text.h @@ -28,19 +28,11 @@ struct MultilineTextWidget : public Widget { }; struct MultilineTextWidgetState : public WidgetState { - MultilineTextWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const MultilineTextWidget *)widgetCursor.widget; + WidgetStateFlags flags; + Value data; - data = widget->data ? get(widgetCursor, widget->data) : 0; - } - - bool operator!=(const MultilineTextWidgetState& previousState) { - return - flags.active != previousState.flags.active || - data != previousState.data; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/progress.cpp b/src/eez/gui/widgets/progress.cpp index c003d9ba6..c8f037b42 100644 --- a/src/eez/gui/widgets/progress.cpp +++ b/src/eez/gui/widgets/progress.cpp @@ -24,41 +24,46 @@ namespace eez { namespace gui { -void ProgressWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (ProgressWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const ProgressWidget *)widgetCursor.widget; - const Style* style = getStyle(widget->style); +bool ProgressWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const ProgressWidget *)widgetCursor.widget; + + WIDGET_STATE(data, get(widgetCursor, widget->data)); - drawRectangle(widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, false, false, true); + return !hasPreviousState; +} + +void ProgressWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const ProgressWidget *)widgetCursor.widget; + const Style* style = getStyle(widget->style); - int percentFrom; - int percentTo; - if (data.getType() == VALUE_TYPE_RANGE) { - percentFrom = data.getRangeFrom(); - percentTo = data.getRangeTo(); - } else { - percentFrom = 0; - percentTo = data.getInt(); - } + drawRectangle(widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, false, false, true); - percentFrom = clamp(percentFrom, 0, 100.0f); - percentTo = clamp(percentTo, 0, 100.0f); - if (percentFrom > percentTo) { - percentFrom = percentTo; - } + int percentFrom; + int percentTo; + if (data.getType() == VALUE_TYPE_RANGE) { + percentFrom = data.getRangeFrom(); + percentTo = data.getRangeTo(); + } else { + percentFrom = 0; + percentTo = data.getInt(); + } + + percentFrom = clamp(percentFrom, 0, 100.0f); + percentTo = clamp(percentTo, 0, 100.0f); + if (percentFrom > percentTo) { + percentFrom = percentTo; + } - auto isHorizontal = widget->w > widget->h; - if (isHorizontal) { - auto xFrom = percentFrom * widget->w / 100; - auto xTo = percentTo * widget->w / 100; - drawRectangle(widgetCursor.x + xFrom, widgetCursor.y, xTo - xFrom, (int)widget->h, style, true, false, true); - } else { - auto yFrom = percentFrom * widget->h / 100; - auto yTo = percentTo * widget->h / 100; - drawRectangle(widgetCursor.x, widgetCursor.y - yFrom, yTo - yFrom, (int)widget->h, getStyle(widget->style), true, false, true); - } + auto isHorizontal = widget->w > widget->h; + if (isHorizontal) { + auto xFrom = percentFrom * widget->w / 100; + auto xTo = percentTo * widget->w / 100; + drawRectangle(widgetCursor.x + xFrom, widgetCursor.y, xTo - xFrom, (int)widget->h, style, true, false, true); + } else { + auto yFrom = percentFrom * widget->h / 100; + auto yTo = percentTo * widget->h / 100; + drawRectangle(widgetCursor.x, widgetCursor.y - yFrom, yTo - yFrom, (int)widget->h, getStyle(widget->style), true, false, true); } } diff --git a/src/eez/gui/widgets/progress.h b/src/eez/gui/widgets/progress.h index 23143e7fc..0ffedc529 100644 --- a/src/eez/gui/widgets/progress.h +++ b/src/eez/gui/widgets/progress.h @@ -25,16 +25,10 @@ struct ProgressWidget : public Widget { }; struct ProgressWidgetState : public WidgetState { - ProgressWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const ProgressWidget *)widgetCursor.widget; - data = get(widgetCursor, widget->data); - } + Value data; - bool operator!=(const ProgressWidgetState& previousState) { - return data != previousState.data; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/rectangle.cpp b/src/eez/gui/widgets/rectangle.cpp index 82d7fb9b6..a3d7371fa 100644 --- a/src/eez/gui/widgets/rectangle.cpp +++ b/src/eez/gui/widgets/rectangle.cpp @@ -24,19 +24,22 @@ namespace eez { namespace gui { -void RectangleWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (RectangleWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const RectangleWidget *)widgetCursor.widget; - const Style* style = getStyle(widget->style); - drawRectangle( - widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - style, - flags.active, - widget->flags.ignoreLuminosity, - widget->flags.invertColors); - } +bool RectangleWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + WIDGET_STATE(flags.active, g_isActiveWidget); + + return !hasPreviousState; +} + +void RectangleWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const RectangleWidget *)widgetCursor.widget; + const Style* style = getStyle(widget->style); + drawRectangle( + widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + style, + flags.active, + widget->flags.ignoreLuminosity, + widget->flags.invertColors); } } // namespace gui diff --git a/src/eez/gui/widgets/rectangle.h b/src/eez/gui/widgets/rectangle.h index ed696f318..a972a057d 100644 --- a/src/eez/gui/widgets/rectangle.h +++ b/src/eez/gui/widgets/rectangle.h @@ -31,14 +31,10 @@ struct RectangleWidget : public Widget { }; struct RectangleWidgetState : public WidgetState { - RectangleWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - } + WidgetStateFlags flags; - bool operator!=(const RectangleWidgetState& previousState) { - return flags.active != previousState.flags.active; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/scroll_bar.cpp b/src/eez/gui/widgets/scroll_bar.cpp index 9d7acbd19..f8ed989c7 100644 --- a/src/eez/gui/widgets/scroll_bar.cpp +++ b/src/eez/gui/widgets/scroll_bar.cpp @@ -66,91 +66,90 @@ void getThumbGeometry(int size, int position, int pageSize, int xTrack, int wTra xThumb = xTrack + (int)round(remap(position, 0, 0, size - pageSize, wTrack - widthThumb)); } -ScrollBarWidgetState::ScrollBarWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - flags.active = g_selectedWidget == widgetCursor; - flags.focused = isFocusWidget(widgetCursor); - - size = getSize(widgetCursor); - position = getPosition(widgetCursor); - pageSize = getPageSize(widgetCursor); - segment = g_segment; +bool ScrollBarWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + + WIDGET_STATE(flags.active, g_selectedWidget == widgetCursor); + WIDGET_STATE(flags.focused, isFocusWidget(widgetCursor)); + WIDGET_STATE(size, getSize(widgetCursor)); + WIDGET_STATE(position, getPosition(widgetCursor)); + WIDGET_STATE(pageSize, getPageSize(widgetCursor)); + WIDGET_STATE(segment, g_segment); + + return !hasPreviousState; } -void ScrollBarWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (ScrollBarWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const ScrollBarWidget *)widgetCursor.widget; - if (pageSize < size) { - const Style *buttonsStyle = getStyle(widget->buttonsStyle); - auto isHorizontal = widget->w > widget->h; - - int buttonSize = isHorizontal ? widget->h : widget->w; - - // draw left button - drawText(widget->leftButtonText.ptr(widgetCursor.assets), -1, - widgetCursor.x, - widgetCursor.y, - isHorizontal ? buttonSize : (int)widget->w, - isHorizontal ? (int)widget->h : buttonSize, buttonsStyle, - segment == SCROLL_BAR_WIDGET_SEGMENT_LEFT_BUTTON, false, false, nullptr, nullptr, nullptr, nullptr); - - // draw track - int xTrack; - int yTrack; - int wTrack; - int hTrack; - - if (isHorizontal) { - xTrack = widgetCursor.x + buttonSize; - yTrack = widgetCursor.y; - wTrack = widget->w - 2 * buttonSize; - hTrack = widget->h; - } else { - xTrack = widgetCursor.x; - yTrack = widgetCursor.y + buttonSize; - wTrack = widget->w; - hTrack = widget->h - 2 * buttonSize; - } +void ScrollBarWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const ScrollBarWidget *)widgetCursor.widget; + if (pageSize < size) { + const Style *buttonsStyle = getStyle(widget->buttonsStyle); + auto isHorizontal = widget->w > widget->h; - const Style *trackStyle = getStyle(widget->style); - display::setColor(trackStyle->color); - display::fillRect(xTrack, yTrack, xTrack + wTrack - 1, yTrack + hTrack - 1, 0); + int buttonSize = isHorizontal ? widget->h : widget->w; - // draw thumb - const Style *thumbStyle = getStyle(widget->thumbStyle); - display::setColor(thumbStyle->color); - if (isHorizontal) { - int xThumb, wThumb; - getThumbGeometry(size, position, pageSize, xTrack, wTrack, buttonSize, xThumb, wThumb); - display::fillRect(xThumb, yTrack, xThumb + wThumb - 1, yTrack + hTrack - 1); - } else { - int yThumb, hThumb; - getThumbGeometry(size, position, pageSize, yTrack, hTrack, buttonSize, yThumb, hThumb); - display::fillRect(xTrack, yThumb, xTrack + wTrack - 1, yThumb + hThumb - 1); - } + // draw left button + drawText(widget->leftButtonText.ptr(widgetCursor.assets), -1, + widgetCursor.x, + widgetCursor.y, + isHorizontal ? buttonSize : (int)widget->w, + isHorizontal ? (int)widget->h : buttonSize, buttonsStyle, + segment == SCROLL_BAR_WIDGET_SEGMENT_LEFT_BUTTON, false, false, nullptr, nullptr, nullptr, nullptr); - // draw right button - drawText(widget->rightButtonText.ptr(widgetCursor.assets), -1, - isHorizontal ? widgetCursor.x + widget->w - buttonSize : widgetCursor.x, - isHorizontal ? widgetCursor.y : widgetCursor.y + widget->h - buttonSize, - isHorizontal ? buttonSize : (int)widget->w, - isHorizontal ? (int)widget->h : buttonSize, buttonsStyle, - segment == SCROLL_BAR_WIDGET_SEGMENT_RIGHT_BUTTON, false, false, nullptr, nullptr, nullptr, nullptr); - - auto action = getWidgetAction(widgetCursor); - if (flags.focused && action == EEZ_CONF_ACTION_ID_SCROLL) { - const Style *style = getStyle(widgetCursor.widget->style); - display::setColor(style->focus_color); - display::drawRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w - 1, widgetCursor.y + widget->h - 1); - display::drawRect(widgetCursor.x + 1, widgetCursor.y + 1, widgetCursor.x + widget->w - 2, widgetCursor.y + widget->h - 2); - } + // draw track + int xTrack; + int yTrack; + int wTrack; + int hTrack; + + if (isHorizontal) { + xTrack = widgetCursor.x + buttonSize; + yTrack = widgetCursor.y; + wTrack = widget->w - 2 * buttonSize; + hTrack = widget->h; } else { - // scroll bar is hidden - const Style *trackStyle = getStyle(widget->style); - display::setColor(trackStyle->color); - display::fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w - 1, widgetCursor.y + widget->h - 1, 0); + xTrack = widgetCursor.x; + yTrack = widgetCursor.y + buttonSize; + wTrack = widget->w; + hTrack = widget->h - 2 * buttonSize; + } + + const Style *trackStyle = getStyle(widget->style); + display::setColor(trackStyle->color); + display::fillRect(xTrack, yTrack, xTrack + wTrack - 1, yTrack + hTrack - 1, 0); + + // draw thumb + const Style *thumbStyle = getStyle(widget->thumbStyle); + display::setColor(thumbStyle->color); + if (isHorizontal) { + int xThumb, wThumb; + getThumbGeometry(size, position, pageSize, xTrack, wTrack, buttonSize, xThumb, wThumb); + display::fillRect(xThumb, yTrack, xThumb + wThumb - 1, yTrack + hTrack - 1); + } else { + int yThumb, hThumb; + getThumbGeometry(size, position, pageSize, yTrack, hTrack, buttonSize, yThumb, hThumb); + display::fillRect(xTrack, yThumb, xTrack + wTrack - 1, yThumb + hThumb - 1); + } + + // draw right button + drawText(widget->rightButtonText.ptr(widgetCursor.assets), -1, + isHorizontal ? widgetCursor.x + widget->w - buttonSize : widgetCursor.x, + isHorizontal ? widgetCursor.y : widgetCursor.y + widget->h - buttonSize, + isHorizontal ? buttonSize : (int)widget->w, + isHorizontal ? (int)widget->h : buttonSize, buttonsStyle, + segment == SCROLL_BAR_WIDGET_SEGMENT_RIGHT_BUTTON, false, false, nullptr, nullptr, nullptr, nullptr); + + auto action = getWidgetAction(widgetCursor); + if (flags.focused && action == EEZ_CONF_ACTION_ID_SCROLL) { + const Style *style = getStyle(widgetCursor.widget->style); + display::setColor(style->focus_color); + display::drawRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w - 1, widgetCursor.y + widget->h - 1); + display::drawRect(widgetCursor.x + 1, widgetCursor.y + 1, widgetCursor.x + widget->w - 2, widgetCursor.y + widget->h - 2); } + } else { + // scroll bar is hidden + const Style *trackStyle = getStyle(widget->style); + display::setColor(trackStyle->color); + display::fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + widget->w - 1, widgetCursor.y + widget->h - 1, 0); } } @@ -158,7 +157,7 @@ bool ScrollBarWidgetState::hasOnTouch() { return true; } -void ScrollBarWidgetState::onTouch(Event &touchEvent) { +void ScrollBarWidgetState::onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { int size = getSize(widgetCursor); int pageSize = getPageSize(widgetCursor); @@ -254,7 +253,7 @@ bool ScrollBarWidgetState::hasOnKeyboard() { #endif } -bool ScrollBarWidgetState::onKeyboard(uint8_t key, uint8_t mod) { +bool ScrollBarWidgetState::onKeyboard(const WidgetCursor &widgetCursor, uint8_t key, uint8_t mod) { #if OPTION_KEYBOARD if (mod == 0) { int position = getPosition(widgetCursor); diff --git a/src/eez/gui/widgets/scroll_bar.h b/src/eez/gui/widgets/scroll_bar.h index cbf3bbba6..75d73b75a 100644 --- a/src/eez/gui/widgets/scroll_bar.h +++ b/src/eez/gui/widgets/scroll_bar.h @@ -38,28 +38,18 @@ enum ScrollBarWidgetSegment { }; struct ScrollBarWidgetState : public WidgetState { + WidgetStateFlags flags; int size; int position; int pageSize; ScrollBarWidgetSegment segment; - ScrollBarWidgetState(const WidgetCursor &widgetCursor); - - bool operator!=(const ScrollBarWidgetState& previousState) { - return - flags.active != previousState.flags.active || - flags.focused != previousState.flags.focused || - size != previousState.size || - position != previousState.position || - pageSize != previousState.pageSize || - segment != previousState.segment; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; bool hasOnTouch() override; - void onTouch(Event &touchEvent) override; + void onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) override; bool hasOnKeyboard() override; - bool onKeyboard(uint8_t key, uint8_t mod) override; + bool onKeyboard(const WidgetCursor &widgetCursor, uint8_t key, uint8_t mod) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/text.cpp b/src/eez/gui/widgets/text.cpp index fc9acfe35..ff55bd321 100644 --- a/src/eez/gui/widgets/text.cpp +++ b/src/eez/gui/widgets/text.cpp @@ -37,93 +37,105 @@ void TextWidget_autoSize(Assets *assets, TextWidget& widget) { widget.h = style->border_size_top + style->padding_top + font.getHeight() + style->border_size_bottom + style->padding_bottom; } -void TextWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (TextWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const TextWidget *)widgetCursor.widget; - const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - const char *text = widget->text.ptr(widgetCursor.assets); - - uint16_t overrideColor = flags.focused ? style->focus_color : overrideStyleColorHook(widgetCursor, style); - uint16_t overrideBackgroundColor = flags.focused ? style->focus_background_color : style->background_color; - uint16_t overrideActiveColor = flags.focused ? style->focus_background_color : overrideActiveStyleColorHook(widgetCursor, style); - uint16_t overrideActiveBackgroundColor = flags.focused ? style->focus_color : style->active_background_color; - - bool ignoreLuminosity = (widget->flags & IGNORE_LUMINOSITY_FLAG) != 0; - if (text && text[0]) { - drawText(text, -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - style, flags.active, - flags.blinking, - ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor); - } else if (widget->data) { - if (data.isString()) { - if (data.getOptions() & STRING_OPTIONS_FILE_ELLIPSIS) { - const char *fullText = data.getString(); - int fullTextLength = strlen(fullText); - font::Font font = styleGetFont(style); - int fullTextWidth = display::measureStr(fullText, fullTextLength, font); - if (fullTextWidth <= widget->w) { - drawText(fullText, fullTextLength, widgetCursor.x, - widgetCursor.y, (int)widget->w, (int)widget->h, style, - flags.active, - flags.blinking, - ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor); - - } else { - char text[MAX_TEXT_LEN + 1]; - int ellipsisWidth = display::measureStr("...", 3, font); - int width = ellipsisWidth; - int textLength = 3; - int iLeft = 0; - int iRight = strlen(fullText) - 1; - while (iLeft < iRight && textLength < (int)MAX_TEXT_LEN) { - int widthLeft = display::measureGlyph(fullText[iLeft], font); - if (width + widthLeft > widget->w) { - break; - } - width += widthLeft; - iLeft++; - textLength++; - - int widthRight = display::measureGlyph(fullText[iRight], font); - if (width + widthRight > widget->w) { - break; - } - width += widthRight; - iRight--; - textLength++; - } +bool TextWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const TextWidget *)widgetCursor.widget; + const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - memcpy(text, fullText, iLeft); - text[iLeft] = 0; - stringAppendString(text, sizeof(text), "..."); - stringAppendString(text, sizeof(text), fullText + iRight + 1); + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(flags.focused, isFocusWidget(widgetCursor)); - drawText(text, textLength, widgetCursor.x, - widgetCursor.y, (int)widget->w, (int)widget->h, style, - flags.active, - flags.blinking, - ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor); - } + WIDGET_STATE(flags.blinking, g_isBlinkTime && styleIsBlink(style)); + + const char *text = widget->text.ptr(widgetCursor.assets); + WIDGET_STATE(data, !(text && text[0]) && widget->data ? get(widgetCursor, widget->data) : 0); + + return !hasPreviousState; +} + +void TextWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const TextWidget *)widgetCursor.widget; + const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); + const char *text = widget->text.ptr(widgetCursor.assets); + + uint16_t overrideColor = flags.focused ? style->focus_color : overrideStyleColorHook(widgetCursor, style); + uint16_t overrideBackgroundColor = flags.focused ? style->focus_background_color : style->background_color; + uint16_t overrideActiveColor = flags.focused ? style->focus_background_color : overrideActiveStyleColorHook(widgetCursor, style); + uint16_t overrideActiveBackgroundColor = flags.focused ? style->focus_color : style->active_background_color; + + bool ignoreLuminosity = (widget->flags & IGNORE_LUMINOSITY_FLAG) != 0; + if (text && text[0]) { + drawText(text, -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + style, flags.active, + flags.blinking, + ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor); + } else if (widget->data) { + if (data.isString()) { + if (data.getOptions() & STRING_OPTIONS_FILE_ELLIPSIS) { + const char *fullText = data.getString(); + int fullTextLength = strlen(fullText); + font::Font font = styleGetFont(style); + int fullTextWidth = display::measureStr(fullText, fullTextLength, font); + if (fullTextWidth <= widget->w) { + drawText(fullText, fullTextLength, widgetCursor.x, + widgetCursor.y, (int)widget->w, (int)widget->h, style, + flags.active, + flags.blinking, + ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor); } else { - const char *str = data.getString(); - drawText(str ? str : "", -1, widgetCursor.x, + char text[MAX_TEXT_LEN + 1]; + int ellipsisWidth = display::measureStr("...", 3, font); + int width = ellipsisWidth; + int textLength = 3; + int iLeft = 0; + int iRight = strlen(fullText) - 1; + while (iLeft < iRight && textLength < (int)MAX_TEXT_LEN) { + int widthLeft = display::measureGlyph(fullText[iLeft], font); + if (width + widthLeft > widget->w) { + break; + } + width += widthLeft; + iLeft++; + textLength++; + + int widthRight = display::measureGlyph(fullText[iRight], font); + if (width + widthRight > widget->w) { + break; + } + width += widthRight; + iRight--; + textLength++; + } + + memcpy(text, fullText, iLeft); + text[iLeft] = 0; + stringAppendString(text, sizeof(text), "..."); + stringAppendString(text, sizeof(text), fullText + iRight + 1); + + drawText(text, textLength, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, flags.active, flags.blinking, ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor); } + } else { - char text[MAX_TEXT_LEN + 1]; - data.toText(text, sizeof(text)); - drawText(text, -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, - style, flags.active, + const char *str = data.getString(); + drawText(str ? str : "", -1, widgetCursor.x, + widgetCursor.y, (int)widget->w, (int)widget->h, style, + flags.active, flags.blinking, - ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor, - data.getType() == VALUE_TYPE_FLOAT); + ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor); } + } else { + char text[MAX_TEXT_LEN + 1]; + data.toText(text, sizeof(text)); + drawText(text, -1, widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, + style, flags.active, + flags.blinking, + ignoreLuminosity, &overrideColor, &overrideBackgroundColor, &overrideActiveColor, &overrideActiveBackgroundColor, + data.getType() == VALUE_TYPE_FLOAT); } } } diff --git a/src/eez/gui/widgets/text.h b/src/eez/gui/widgets/text.h index b93e2377b..0c659bf58 100644 --- a/src/eez/gui/widgets/text.h +++ b/src/eez/gui/widgets/text.h @@ -27,27 +27,11 @@ struct TextWidget : public Widget { }; struct TextWidgetState : public WidgetState { - TextWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const TextWidget *)widgetCursor.widget; - - flags.focused = isFocusWidget(widgetCursor); - - const Style *style = getStyle(overrideStyleHook(widgetCursor, widget->style)); - flags.blinking = g_isBlinkTime && styleIsBlink(style); - - const char *text = widget->text.ptr(widgetCursor.assets); - data = !(text && text[0]) && widget->data ? get(widgetCursor, widget->data) : 0; - } - - bool operator!=(const TextWidgetState& previousState) { - return - flags.focused != previousState.flags.focused || - flags.active != previousState.flags.active || - flags.blinking != previousState.flags.blinking || - data != previousState.data; - } - - void draw(WidgetState *previousState) override; + WidgetStateFlags flags; + Value data; + + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; void TextWidget_autoSize(Assets *assets, TextWidget& widget); diff --git a/src/eez/gui/widgets/toggle_button.cpp b/src/eez/gui/widgets/toggle_button.cpp index 1764c5ab4..92254cf5e 100644 --- a/src/eez/gui/widgets/toggle_button.cpp +++ b/src/eez/gui/widgets/toggle_button.cpp @@ -24,20 +24,26 @@ namespace eez { namespace gui { -void ToggleButtonWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (ToggleButtonWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const ToggleButtonWidget *)widgetCursor.widget; - const Style* style = getStyle(widget->style); - drawText( - flags.enabled ? - widget->text2.ptr(widgetCursor.assets): - widget->text1.ptr(widgetCursor.assets), - -1, - widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, - flags.active, false, false, nullptr, nullptr, nullptr, nullptr); - } +bool ToggleButtonWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const ToggleButtonWidget *)widgetCursor.widget; + + WIDGET_STATE(flags.active, g_isActiveWidget); + WIDGET_STATE(flags.enabled, get(widgetCursor, widget->data).getInt() ? 1 : 0); + + return !hasPreviousState; +} + +void ToggleButtonWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const ToggleButtonWidget *)widgetCursor.widget; + const Style* style = getStyle(widget->style); + drawText( + flags.enabled ? + widget->text2.ptr(widgetCursor.assets): + widget->text1.ptr(widgetCursor.assets), + -1, + widgetCursor.x, widgetCursor.y, (int)widget->w, (int)widget->h, style, + flags.active, false, false, nullptr, nullptr, nullptr, nullptr); } } // namespace gui diff --git a/src/eez/gui/widgets/toggle_button.h b/src/eez/gui/widgets/toggle_button.h index cecb2c6f9..319730d3a 100644 --- a/src/eez/gui/widgets/toggle_button.h +++ b/src/eez/gui/widgets/toggle_button.h @@ -27,18 +27,10 @@ struct ToggleButtonWidget : public Widget { }; struct ToggleButtonWidgetState : public WidgetState { - ToggleButtonWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const ToggleButtonWidget *)widgetCursor.widget; - flags.enabled = get(widgetCursor, widget->data).getInt() ? 1 : 0; - } - - bool operator!=(const ToggleButtonWidgetState& previousState) { - return - flags.active != previousState.flags.active || - flags.enabled != previousState.flags.enabled; - } - - void draw(WidgetState *previousState) override; + WidgetStateFlags flags; + + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/up_down.cpp b/src/eez/gui/widgets/up_down.cpp index ffaa6570c..a566fd8ad 100644 --- a/src/eez/gui/widgets/up_down.cpp +++ b/src/eez/gui/widgets/up_down.cpp @@ -39,41 +39,40 @@ enum UpDownWidgetSegment { static UpDownWidgetSegment g_segment; static WidgetCursor g_selectedWidget; -UpDownWidgetState::UpDownWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { +bool UpDownWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; auto widget = (const UpDownWidget *)widgetCursor.widget; - flags.active = g_selectedWidget == widgetCursor; - data = get(widgetCursor, widget->data); + WIDGET_STATE(flags.active, g_selectedWidget == widgetCursor); + WIDGET_STATE(data, get(widgetCursor, widget->data)); + + return !hasPreviousState; } -void UpDownWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (UpDownWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const UpDownWidget *)widgetCursor.widget; - const Style *buttonsStyle = getStyle(widget->buttonsStyle); - - font::Font buttonsFont = styleGetFont(buttonsStyle); - int buttonWidth = buttonsFont.getHeight(); - - drawText(widget->downButtonText.ptr(widgetCursor.assets), -1, widgetCursor.x, widgetCursor.y, buttonWidth, (int)widget->h, - buttonsStyle, - flags.active && - g_segment == UP_DOWN_WIDGET_SEGMENT_DOWN_BUTTON, - false, false, nullptr, nullptr, nullptr, nullptr); - - char text[64]; - data.toText(text, sizeof(text)); - const Style *style = getStyle(widget->style); - drawText(text, -1, widgetCursor.x + buttonWidth, widgetCursor.y, - (int)(widget->w - 2 * buttonWidth), (int)widget->h, style, false, false, - false, nullptr, nullptr, nullptr, nullptr); - - drawText(widget->upButtonText.ptr(widgetCursor.assets), -1, widgetCursor.x + widget->w - buttonWidth, widgetCursor.y, - buttonWidth, (int)widget->h, buttonsStyle, - flags.active && g_segment == UP_DOWN_WIDGET_SEGMENT_UP_BUTTON, - false, false, nullptr, nullptr, nullptr, nullptr); - } +void UpDownWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const UpDownWidget *)widgetCursor.widget; + const Style *buttonsStyle = getStyle(widget->buttonsStyle); + + font::Font buttonsFont = styleGetFont(buttonsStyle); + int buttonWidth = buttonsFont.getHeight(); + + drawText(widget->downButtonText.ptr(widgetCursor.assets), -1, widgetCursor.x, widgetCursor.y, buttonWidth, (int)widget->h, + buttonsStyle, + flags.active && + g_segment == UP_DOWN_WIDGET_SEGMENT_DOWN_BUTTON, + false, false, nullptr, nullptr, nullptr, nullptr); + + char text[64]; + data.toText(text, sizeof(text)); + const Style *style = getStyle(widget->style); + drawText(text, -1, widgetCursor.x + buttonWidth, widgetCursor.y, + (int)(widget->w - 2 * buttonWidth), (int)widget->h, style, false, false, + false, nullptr, nullptr, nullptr, nullptr); + + drawText(widget->upButtonText.ptr(widgetCursor.assets), -1, widgetCursor.x + widget->w - buttonWidth, widgetCursor.y, + buttonWidth, (int)widget->h, buttonsStyle, + flags.active && g_segment == UP_DOWN_WIDGET_SEGMENT_UP_BUTTON, + false, false, nullptr, nullptr, nullptr, nullptr); } void upDown(const WidgetCursor &widgetCursor, UpDownWidgetSegment segment) { @@ -110,7 +109,7 @@ bool UpDownWidgetState::hasOnTouch() { return true; } -void UpDownWidgetState::onTouch(Event &touchEvent) { +void UpDownWidgetState::onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { const Widget *widget = widgetCursor.widget; if (touchEvent.type == EVENT_TYPE_TOUCH_DOWN || touchEvent.type == EVENT_TYPE_AUTO_REPEAT) { @@ -138,7 +137,7 @@ bool UpDownWidgetState::hasOnKeyboard() { #endif } -bool UpDownWidgetState::onKeyboard(uint8_t key, uint8_t mod) { +bool UpDownWidgetState::onKeyboard(const WidgetCursor &widgetCursor, uint8_t key, uint8_t mod) { #if OPTION_KEYBOARD if (mod == 0) { if (key == KEY_LEFTARROW || key == KEY_DOWNARROW) { diff --git a/src/eez/gui/widgets/up_down.h b/src/eez/gui/widgets/up_down.h index c52db39a8..695ba7ebf 100644 --- a/src/eez/gui/widgets/up_down.h +++ b/src/eez/gui/widgets/up_down.h @@ -28,19 +28,15 @@ struct UpDownWidget : public Widget { }; struct UpDownWidgetState : public WidgetState { - UpDownWidgetState(const WidgetCursor &widgetCursor); + WidgetStateFlags flags; + Value data; - bool operator!=(const UpDownWidgetState& previousState) { - return - flags.active != previousState.flags.active || - data != previousState.data; - } - - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; bool hasOnTouch() override; - void onTouch(Event &touchEvent) override; + void onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) override; bool hasOnKeyboard() override; - bool onKeyboard(uint8_t key, uint8_t mod) override; + bool onKeyboard(const WidgetCursor &widgetCursor, uint8_t key, uint8_t mod) override; }; } // namespace gui diff --git a/src/eez/gui/widgets/yt_graph.cpp b/src/eez/gui/widgets/yt_graph.cpp index 8cddbf39d..605a4c7ac 100644 --- a/src/eez/gui/widgets/yt_graph.cpp +++ b/src/eez/gui/widgets/yt_graph.cpp @@ -201,7 +201,7 @@ struct YTGraphDrawHelper { // used for YT_GRAPH_UPDATE_METHOD_STATIC struct YTGraphStaticDrawHelper { - YTGraphWidgetState *currentState; + YTGraphWidgetState *widgetState; const WidgetCursor &widgetCursor; const Widget *widget; @@ -232,8 +232,8 @@ struct YTGraphStaticDrawHelper { int xLabels[MAX_NUM_OF_Y_VALUES]; int yLabels[MAX_NUM_OF_Y_VALUES]; - YTGraphStaticDrawHelper(YTGraphWidgetState *currentState_, const WidgetCursor &widgetCursor_) - : currentState(currentState_), widgetCursor(widgetCursor_), widget(widgetCursor.widget) + YTGraphStaticDrawHelper(YTGraphWidgetState *widgetState_, const WidgetCursor &widgetCursor_) + : widgetState(widgetState_), widgetCursor(widgetCursor_), widget(widgetCursor.widget) { ytDataGetValue = ytDataGetGetValueFunc(widgetCursor, widget->data); } @@ -338,8 +338,8 @@ struct YTGraphStaticDrawHelper { if (ytDataDataValueIsVisible(widgetCursor, widget->data, m_valueIndex)) { position = currentHistoryValuePosition; - scale = (widget->h - 1) / currentState->valueDiv[m_valueIndex] / vertDivisions; - offset = currentState->valueOffset[m_valueIndex]; + scale = (widget->h - 1) / widgetState->valueDiv[m_valueIndex] / vertDivisions; + offset = widgetState->valueOffset[m_valueIndex]; const Style* style = ytDataGetStyle(widgetCursor, widget->data, m_valueIndex); dataColor16 = display::getColor16FromIndex(style->color); @@ -454,7 +454,7 @@ struct YTGraphStaticDrawHelper { drawText(text, -1, xCursorText, yCursorText, cursorTextWidth, cursorTextHeight, - style, currentState->flags.focused, false, false, nullptr, nullptr, nullptr, nullptr + style, widgetState->flags.focused, false, false, nullptr, nullptr, nullptr, nullptr ); } @@ -481,68 +481,91 @@ struct YTGraphStaticDrawHelper { //////////////////////////////////////////////////////////////////////////////// -void YTGraphWidgetState::draw(WidgetState *previousStateBase) { - auto previousState = (YTGraphWidgetState *)previousStateBase; - bool refresh = !previousState || *this != *previousState; - if (refresh) { - auto widget = (const YTGraphWidget *)widgetCursor.widget; - - uint16_t graphWidth = (uint16_t)widget->w; - - uint32_t previousHistoryValuePosition; - if ( - previousState && - ( - previousState->iChannel == iChannel && - previousState->ytGraphUpdateMethod == ytGraphUpdateMethod && - previousState->refreshCounter == refreshCounter - ) - ) { - previousHistoryValuePosition = previousState->historyValuePosition; - } else { - previousHistoryValuePosition = historyValuePosition - graphWidth; +bool YTGraphWidgetState::updateState(const WidgetCursor &widgetCursor) { + bool hasPreviousState = widgetCursor.hasPreviousState; + auto widget = (const YTGraphWidget *)widgetCursor.widget; + + WIDGET_STATE(flags.focused, isFocusWidget(widgetCursor)); + + WIDGET_STATE(refreshCounter, ytDataGetRefreshCounter(widgetCursor, widget->data)); + WIDGET_STATE(iChannel, widgetCursor.cursor); + WIDGET_STATE(ytGraphUpdateMethod, ytDataGetGraphUpdateMethod(widgetCursor, widget->data)); + WIDGET_STATE(numHistoryValues, ytDataGetSize(widgetCursor, widget->data)); + WIDGET_STATE(bookmarks, ytDataGetBookmarks(widgetCursor, widget->data)); + WIDGET_STATE(showLabels, ytDataGetShowLabels(widgetCursor, widget->data)); + WIDGET_STATE(selectedValueIndex, ytDataGetSelectedValueIndex(widgetCursor, widget->data)); + + if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_STATIC) { + for (int valueIndex = 0; valueIndex < MAX_NUM_OF_Y_VALUES; valueIndex++) { + WIDGET_STATE(valueIsVisible[valueIndex], ytDataDataValueIsVisible(widgetCursor, widget->data, valueIndex)); + WIDGET_STATE(valueDiv[valueIndex], ytDataGetDiv(widgetCursor, widget->data, valueIndex)); + WIDGET_STATE(valueOffset[valueIndex], ytDataGetOffset(widgetCursor, widget->data, valueIndex)); } + } - if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_STATIC) { - YTGraphStaticDrawHelper drawHelper(this, widgetCursor); + WIDGET_STATE(historyValuePosition, ytDataGetPosition(widgetCursor, widget->data)); + WIDGET_STATE(cursorPosition, historyValuePosition + ytDataGetCursorOffset(widgetCursor, widget->data)); - drawHelper.cursorPosition = cursorPosition; - drawHelper.bookmarks = bookmarks; - drawHelper.drawStatic(previousHistoryValuePosition, historyValuePosition, numHistoryValues, graphWidth, showLabels, selectedValueIndex); - } else { - const Style* style = getStyle(widget->style); + // if (hasPreviousState && ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_SCAN_LINE) { + // previousHistoryValuePosition = historyValuePosition; + // refreshBackground = false; + // } else { + // hasPreviousState = false; + // uint16_t graphWidth = (uint16_t)widget->w; + // previousHistoryValuePosition = new_historyValuePosition - graphWidth; + // refreshBackground = true; + // } - if (!previousState) { - display::setColor(style->background_color); - display::fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + (int)widget->w - 1, widgetCursor.y + (int)widget->h - 1); - } + uint16_t graphWidth = (uint16_t)widget->w; + previousHistoryValuePosition = historyValuePosition - graphWidth; - YTGraphDrawHelper drawHelper(widgetCursor); - drawHelper.color16 = display::getColor16FromIndex(flags.active ? style->color : style->background_color); - if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_SCAN_LINE) { - drawHelper.drawScanLine(previousHistoryValuePosition, historyValuePosition, graphWidth); + return !hasPreviousState; +} - int x = widgetCursor.x; +void YTGraphWidgetState::render(WidgetCursor &widgetCursor) { + auto widget = (const YTGraphWidget *)widgetCursor.widget; - // draw cursor - display::setColor(style->color); - display::drawVLine(x + historyValuePosition % graphWidth, widgetCursor.y, (int)widget->h - 1); - display::drawVLine(x + (historyValuePosition + 1) % graphWidth, widgetCursor.y, (int)widget->h - 1); + uint16_t graphWidth = (uint16_t)widget->w; - // draw blank lines - int x1 = x + (historyValuePosition + 2) % graphWidth; - int x2 = x + (historyValuePosition + CONF_GUI_YT_GRAPH_BLANK_PIXELS_AFTER_CURSOR) % graphWidth; + if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_STATIC) { + YTGraphStaticDrawHelper drawHelper(this, widgetCursor); - display::setColor(style->background_color); - if (x1 < x2) { - display::fillRect(x1, widgetCursor.y, x2, widgetCursor.y + (int)widget->h - 1); - } else { - display::fillRect(x1, widgetCursor.y, x + graphWidth - 1, widgetCursor.y + (int)widget->h - 1); - display::fillRect(x, widgetCursor.y, x2, widgetCursor.y + (int)widget->h - 1); - } - } else if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_SCROLL) { - drawHelper.drawScrolling(previousHistoryValuePosition, historyValuePosition, numHistoryValues, graphWidth); + drawHelper.cursorPosition = cursorPosition; + drawHelper.bookmarks = bookmarks; + drawHelper.drawStatic(previousHistoryValuePosition, historyValuePosition, numHistoryValues, graphWidth, showLabels, selectedValueIndex); + } else { + const Style* style = getStyle(widget->style); + + if (!refreshBackground) { + display::setColor(style->background_color); + display::fillRect(widgetCursor.x, widgetCursor.y, widgetCursor.x + (int)widget->w - 1, widgetCursor.y + (int)widget->h - 1); + } + + YTGraphDrawHelper drawHelper(widgetCursor); + drawHelper.color16 = display::getColor16FromIndex(flags.active ? style->color : style->background_color); + if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_SCAN_LINE) { + drawHelper.drawScanLine(previousHistoryValuePosition, historyValuePosition, graphWidth); + + int x = widgetCursor.x; + + // draw cursor + display::setColor(style->color); + display::drawVLine(x + historyValuePosition % graphWidth, widgetCursor.y, (int)widget->h - 1); + display::drawVLine(x + (historyValuePosition + 1) % graphWidth, widgetCursor.y, (int)widget->h - 1); + + // draw blank lines + int x1 = x + (historyValuePosition + 2) % graphWidth; + int x2 = x + (historyValuePosition + CONF_GUI_YT_GRAPH_BLANK_PIXELS_AFTER_CURSOR) % graphWidth; + + display::setColor(style->background_color); + if (x1 < x2) { + display::fillRect(x1, widgetCursor.y, x2, widgetCursor.y + (int)widget->h - 1); + } else { + display::fillRect(x1, widgetCursor.y, x + graphWidth - 1, widgetCursor.y + (int)widget->h - 1); + display::fillRect(x, widgetCursor.y, x2, widgetCursor.y + (int)widget->h - 1); } + } else if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_SCROLL) { + drawHelper.drawScrolling(previousHistoryValuePosition, historyValuePosition, numHistoryValues, graphWidth); } } } @@ -551,7 +574,7 @@ bool YTGraphWidgetState::hasOnTouch() { return true; } -void YTGraphWidgetState::onTouch(Event &touchEvent) { +void YTGraphWidgetState::onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { if (ytDataGetGraphUpdateMethod(widgetCursor, widgetCursor.widget->data) == YT_GRAPH_UPDATE_METHOD_STATIC) { if (touchEvent.type == EVENT_TYPE_TOUCH_DOWN || touchEvent.type == EVENT_TYPE_TOUCH_MOVE) { TouchDrag touchDrag = { diff --git a/src/eez/gui/widgets/yt_graph.h b/src/eez/gui/widgets/yt_graph.h index a29d71ded..ffab9cb7f 100644 --- a/src/eez/gui/widgets/yt_graph.h +++ b/src/eez/gui/widgets/yt_graph.h @@ -32,80 +32,28 @@ struct YTGraphWidget : public Widget { struct YTGraphWidgetState : public WidgetState { + WidgetStateFlags flags; + Value data; uint32_t refreshCounter; uint8_t iChannel; + uint8_t ytGraphUpdateMethod; uint32_t numHistoryValues; uint32_t historyValuePosition; - uint8_t ytGraphUpdateMethod; uint32_t cursorPosition; uint8_t *bookmarks; bool showLabels; int8_t selectedValueIndex; bool valueIsVisible[MAX_NUM_OF_Y_VALUES]; float valueDiv[MAX_NUM_OF_Y_VALUES]; - float valueOffset[MAX_NUM_OF_Y_VALUES]; - - YTGraphWidgetState(const WidgetCursor &widgetCursor) : WidgetState(widgetCursor) { - auto widget = (const YTGraphWidget *)widgetCursor.widget; - - flags.focused = isFocusWidget(widgetCursor); - data = get(widgetCursor, widget->data); - - refreshCounter = ytDataGetRefreshCounter(widgetCursor, widget->data); - iChannel = widgetCursor.cursor; - numHistoryValues = ytDataGetSize(widgetCursor, widget->data); - historyValuePosition = ytDataGetPosition(widgetCursor, widget->data); - ytGraphUpdateMethod = ytDataGetGraphUpdateMethod(widgetCursor, widget->data); - cursorPosition = historyValuePosition + ytDataGetCursorOffset(widgetCursor, widget->data); - bookmarks = ytDataGetBookmarks(widgetCursor, widget->data); - showLabels = ytDataGetShowLabels(widgetCursor, widget->data); - selectedValueIndex = ytDataGetSelectedValueIndex(widgetCursor, widget->data); - - if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_STATIC) { - for (int valueIndex = 0; valueIndex < MAX_NUM_OF_Y_VALUES; valueIndex++) { - valueIsVisible[valueIndex] = ytDataDataValueIsVisible(widgetCursor, widget->data, valueIndex); - valueDiv[valueIndex] = ytDataGetDiv(widgetCursor, widget->data, valueIndex); - valueOffset[valueIndex] = ytDataGetOffset(widgetCursor, widget->data, valueIndex); - } - } - } - - bool operator!=(const YTGraphWidgetState& previousState) { - if ( - flags.focused != previousState.flags.focused || - refreshCounter != previousState.refreshCounter || - iChannel != previousState.iChannel || - numHistoryValues != previousState.numHistoryValues || - historyValuePosition != previousState.historyValuePosition || - ytGraphUpdateMethod != previousState.ytGraphUpdateMethod || - cursorPosition != previousState.cursorPosition || - bookmarks != previousState.bookmarks || - showLabels != previousState.showLabels || - selectedValueIndex != previousState.selectedValueIndex - ) { - return true; - } - - if (ytGraphUpdateMethod == YT_GRAPH_UPDATE_METHOD_STATIC) { - for (int valueIndex = 0; valueIndex < MAX_NUM_OF_Y_VALUES; valueIndex++) { - if ( - valueIsVisible[valueIndex] != previousState.valueIsVisible[valueIndex] || - valueDiv[valueIndex] != previousState.valueDiv[valueIndex] || - valueOffset[valueIndex] != previousState.valueOffset[valueIndex] - ) { - return true; - } - } - } - - return false; - } + float valueOffset[MAX_NUM_OF_Y_VALUES]; - uint32_t getHistoryValuePosition(); + uint32_t previousHistoryValuePosition; + bool refreshBackground; - void draw(WidgetState *previousState) override; + bool updateState(const WidgetCursor &widgetCursor) override; + void render(WidgetCursor &widgetCursor) override; bool hasOnTouch() override; - void onTouch(Event &touchEvent) override; + void onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) override; }; } // gui diff --git a/src/eez/memory.h b/src/eez/memory.h index 8875d4089..29fcceaab 100644 --- a/src/eez/memory.h +++ b/src/eez/memory.h @@ -62,10 +62,10 @@ static uint8_t * const FLOW_TO_DEBUGGER_MESSAGE_BUFFER = ALLOC_BUFFER + ALLOC_BU static const uint32_t FLOW_TO_DEBUGGER_MESSAGE_BUFFER_SIZE = 32 * 1024; #if defined(EEZ_PLATFORM_STM32) -static const uint32_t GUI_STATE_BUFFER_SIZE = 64 * 1024; +static const uint32_t GUI_STATE_BUFFER_SIZE = 32 * 1024; #endif #if defined(EEZ_PLATFORM_SIMULATOR) -static const uint32_t GUI_STATE_BUFFER_SIZE = 128 * 1024; +static const uint32_t GUI_STATE_BUFFER_SIZE = 64 * 1024; #endif static uint8_t * const SOUND_TUNES_MEMORY = FLOW_TO_DEBUGGER_MESSAGE_BUFFER + FLOW_TO_DEBUGGER_MESSAGE_BUFFER_SIZE; diff --git a/src/third_party/stm32_cubeide/.cproject b/src/third_party/stm32_cubeide/.cproject index 486157b59..da0e96d7f 100644 --- a/src/third_party/stm32_cubeide/.cproject +++ b/src/third_party/stm32_cubeide/.cproject @@ -529,7 +529,7 @@ - @@ -551,7 +551,7 @@ - @@ -563,7 +563,7 @@ - @@ -596,7 +596,7 @@ - @@ -618,7 +618,7 @@ -