You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
647 lines
20 KiB
647 lines
20 KiB
/* |
|
* EEZ Generic Firmware |
|
* Copyright (C) 2015-present, Envox d.o.o. |
|
* |
|
* This program is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
|
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
|
|
* You should have received a copy of the GNU General Public License |
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
*/ |
|
|
|
#include <assert.h> |
|
#include <cstddef> |
|
#include <limits.h> |
|
|
|
#include <eez/core/debug.h> |
|
#include <eez/core/os.h> |
|
#include <eez/core/util.h> |
|
|
|
#include <eez/gui/gui.h> |
|
#include <eez/gui/assets.h> |
|
|
|
#include <eez/gui/widgets/containers/app_view.h> |
|
#include <eez/gui/widgets/containers/container.h> |
|
#include <eez/gui/widgets/containers/grid.h> |
|
#include <eez/gui/widgets/containers/layout_view.h> |
|
#include <eez/gui/widgets/containers/list.h> |
|
#include <eez/gui/widgets/containers/select.h> |
|
|
|
#include <eez/gui/widgets/bar_graph.h> |
|
#include <eez/gui/widgets/bitmap.h> |
|
#include <eez/gui/widgets/button_group.h> |
|
#include <eez/gui/widgets/button.h> |
|
#include <eez/gui/widgets/canvas.h> |
|
#include <eez/gui/widgets/display_data.h> |
|
#include <eez/gui/widgets/drop_down_list.h> |
|
#include <eez/gui/widgets/gauge.h> |
|
#include <eez/gui/widgets/input.h> |
|
#include <eez/gui/widgets/list_graph.h> |
|
#include <eez/gui/widgets/multiline_text.h> |
|
#include <eez/gui/widgets/progress.h> |
|
#include <eez/gui/widgets/rectangle.h> |
|
#include <eez/gui/widgets/roller.h> |
|
#include <eez/gui/widgets/scroll_bar.h> |
|
#include <eez/gui/widgets/slider.h> |
|
#include <eez/gui/widgets/switch.h> |
|
#include <eez/gui/widgets/text.h> |
|
#include <eez/gui/widgets/toggle_button.h> |
|
#include <eez/gui/widgets/up_down.h> |
|
#include <eez/gui/widgets/yt_graph.h> |
|
|
|
namespace eez { |
|
namespace gui { |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
bool g_isActiveWidget; |
|
EnumWidgetsCallback g_findCallback; |
|
bool g_foundWidgetAtDownInvalid; |
|
|
|
bool g_isRTL = false; |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
struct NoneWidgetState : public WidgetState { |
|
bool updateState() { |
|
WIDGET_STATE_START(Widget); |
|
WIDGET_STATE_END() |
|
} |
|
}; |
|
|
|
static Widget g_noneWidget = { WIDGET_TYPE_NONE }; |
|
|
|
struct ReservedWidgetState : public WidgetState {}; |
|
|
|
// widget placementNew functions |
|
#define WIDGET_TYPE(NAME_PASCAL_CASE, NAME, ID) \ |
|
void NAME##_placementNew(void *ptr) { new (ptr) NAME_PASCAL_CASE##WidgetState(); } |
|
WIDGET_TYPES |
|
#undef WIDGET_TYPE |
|
|
|
typedef void (*WidgetStatePlacementNewFunctionType)(void *ptr); |
|
|
|
#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_widgetStateSizes[] = { |
|
WIDGET_TYPES |
|
}; |
|
#undef WIDGET_TYPE |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
bool WidgetState::updateState() { |
|
return false; |
|
} |
|
|
|
void WidgetState::render() { |
|
} |
|
|
|
void WidgetState::enumChildren() { |
|
} |
|
|
|
bool WidgetState::hasOnTouch() { |
|
return false; |
|
} |
|
|
|
void WidgetState::onTouch(const WidgetCursor &widgetCursor, Event &touchEvent) { |
|
} |
|
|
|
bool WidgetState::hasOnKeyboard() { |
|
return false; |
|
} |
|
|
|
bool WidgetState::onKeyboard(const WidgetCursor &widgetCursor, uint8_t key, uint8_t mod) { |
|
return false; |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
bool WidgetCursor::isPage() const { |
|
return widget->type == WIDGET_TYPE_CONTAINER && ((((ContainerWidget *)widget)->flags & PAGE_CONTAINER) != 0); |
|
} |
|
|
|
void WidgetCursor::pushBackground(int x, int y, const Style *style, bool active) { |
|
if (backgroundStyleStackPointer == BACKGROUND_STYLE_STACK_SIZE) { |
|
// make space: remove item at the bottom of stack |
|
for (size_t i = 1; i < BACKGROUND_STYLE_STACK_SIZE; i++) { |
|
backgroundStyleStack[i - 1] = backgroundStyleStack[i]; |
|
} |
|
backgroundStyleStackPointer--; |
|
} |
|
|
|
backgroundStyleStack[backgroundStyleStackPointer].x = x; |
|
backgroundStyleStack[backgroundStyleStackPointer].y = y; |
|
backgroundStyleStack[backgroundStyleStackPointer].style = style; |
|
backgroundStyleStack[backgroundStyleStackPointer].active = active; |
|
backgroundStyleStackPointer++; |
|
} |
|
|
|
void WidgetCursor::popBackground() { |
|
if (backgroundStyleStackPointer > 0) { |
|
backgroundStyleStackPointer--; |
|
} |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
#define RENDER_WIDGET() \ |
|
if ((!widget->visible || widgetState->isVisible.toBool()) && widgetCursor.opacity > 0) { \ |
|
auto savedOpacity = display::setOpacity(widgetCursor.opacity); \ |
|
widgetState->render(); \ |
|
display::setOpacity(savedOpacity); \ |
|
} |
|
|
|
void enumWidget() { |
|
WidgetCursor &widgetCursor = g_widgetCursor; |
|
const Widget *widget = widgetCursor.widget; |
|
|
|
auto widgetState = widgetCursor.currentState; |
|
|
|
bool savedIsActiveWidget = g_isActiveWidget; |
|
g_isActiveWidget = g_isActiveWidget || widgetCursor == g_activeWidget; |
|
|
|
if (g_findCallback) { |
|
if (!widget->visible || widgetState->isVisible.toBool()) { |
|
g_findCallback(); |
|
} |
|
} else { |
|
if (widgetCursor.hasPreviousState && widget->type == widgetState->type) { |
|
// reuse existing widget state |
|
bool refresh = widgetState->updateState(); |
|
if (refresh || widgetCursor.refreshed) { |
|
RENDER_WIDGET(); |
|
} |
|
} else { |
|
if (widgetCursor.hasPreviousState) { |
|
// clear old state from current state |
|
freeWidgetStates(widgetState); |
|
widgetCursor.hasPreviousState = false; |
|
} |
|
|
|
// create new widget state |
|
g_widgetStatePlacementNewFunctions[widget->type](widgetState); |
|
widgetState->type = widget->type; |
|
|
|
widgetState->updateState(); |
|
|
|
RENDER_WIDGET(); |
|
|
|
if (g_foundWidgetAtDownInvalid) { |
|
// find new cursor for g_foundWidgetAtDown |
|
auto &foundWidgetAtDown = getFoundWidgetAtDown(); |
|
if (foundWidgetAtDown == widgetCursor) { |
|
foundWidgetAtDown = widgetCursor; |
|
g_foundWidgetAtDownInvalid = false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
widgetCursor.currentState = (WidgetState *)((uint8_t *)widgetCursor.currentState + g_widgetStateSizes[widget->type]); |
|
|
|
uint32_t stateSize = (uint8_t *)widgetCursor.currentState - (uint8_t *)g_widgetStateStart; |
|
if (stateSize > GUI_STATE_BUFFER_SIZE) { |
|
return; |
|
} |
|
|
|
widgetState->enumChildren(); |
|
|
|
g_isActiveWidget = savedIsActiveWidget; |
|
} |
|
|
|
void enumNoneWidget() { |
|
WidgetCursor &widgetCursor = g_widgetCursor; |
|
auto savedWidget = widgetCursor.widget; |
|
widgetCursor.widget = &g_noneWidget; |
|
auto savedX = g_widgetCursor.x; |
|
auto savedY = g_widgetCursor.y; |
|
g_widgetCursor.x += g_noneWidget.x; |
|
g_widgetCursor.y += g_noneWidget.y; |
|
g_widgetCursor.w = g_noneWidget.width; |
|
g_widgetCursor.h = g_noneWidget.height; |
|
enumWidget(); |
|
g_widgetCursor.x = savedX; |
|
g_widgetCursor.y = savedY; |
|
widgetCursor.widget = savedWidget; |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
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; |
|
} |
|
|
|
// invalidate g_foundWidgetAtDown if it was among freed widgets |
|
auto &widgetCursor = getFoundWidgetAtDown(); |
|
if (widgetCursor.currentState >= widgetStateStart) { |
|
g_foundWidgetAtDownInvalid = true; |
|
} |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
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; |
|
|
|
int g_xOverlayOffset = 0; |
|
int g_yOverlayOffset = 0; |
|
|
|
static AppContext *g_popPageAppContext; |
|
|
|
static void findWidgetStep() { |
|
if (g_found) { |
|
return; |
|
} |
|
|
|
WidgetCursor &widgetCursor = g_widgetCursor; |
|
|
|
if (widgetCursor.appContext->isActivePageInternal()) { |
|
auto internalPage = (InternalPage *)widgetCursor.appContext->getActivePage(); |
|
|
|
WidgetCursor foundWidget = internalPage->findWidgetInternalPage(g_findWidgetAtX, g_findWidgetAtY, g_clicked); |
|
if (foundWidget) { |
|
g_foundWidget = foundWidget; |
|
g_found = true; |
|
return; |
|
} |
|
|
|
if (g_clicked) { |
|
if (internalPage->closeIfTouchedOutside()) { |
|
// clicked outside internal page, close internal page (if not toast) |
|
g_popPageAppContext = widgetCursor.appContext; |
|
} |
|
} |
|
|
|
bool passThrough = internalPage->canClickPassThrough(); |
|
if (!passThrough) { |
|
g_foundWidget = 0; |
|
g_found = true; |
|
return; |
|
} |
|
} |
|
|
|
if (widgetCursor.isPage()) { |
|
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); |
|
} |
|
|
|
int x = widgetCursor.x + g_xOverlayOffset; |
|
int y = widgetCursor.y + g_yOverlayOffset; |
|
|
|
if (overlay) { |
|
g_xOverlayOffset = 0; |
|
g_yOverlayOffset = 0; |
|
} |
|
|
|
static const int MIN_SIZE = 50; |
|
|
|
int w = overlay ? overlay->width : widgetCursor.w; |
|
if (w < MIN_SIZE) { |
|
x = x - (MIN_SIZE - w) / 2; |
|
w = MIN_SIZE; |
|
} |
|
|
|
int h = overlay ? overlay->height : widgetCursor.h; |
|
if (h < MIN_SIZE) { |
|
y = y - (MIN_SIZE - h) / 2; |
|
h = MIN_SIZE; |
|
} |
|
|
|
bool inside = |
|
g_findWidgetAtX >= x && g_findWidgetAtX < x + w && |
|
g_findWidgetAtY >= y && g_findWidgetAtY < y + h; |
|
|
|
if (inside && (widget->type == WIDGET_TYPE_APP_VIEW || getWidgetTouchFunction(widgetCursor))) { |
|
int dx = g_findWidgetAtX - (x + w / 2); |
|
int dy = g_findWidgetAtY - (y + h / 2); |
|
int distance = dx * dx + dy * dy; |
|
|
|
auto action = getWidgetAction(widgetCursor); |
|
if (action == ACTION_ID_DRAG_OVERLAY) { |
|
if (overlay && !overlay->state) { |
|
return; |
|
} |
|
g_foundWidget = widgetCursor; |
|
g_distanceToFoundWidget = INT_MAX; |
|
} else { |
|
if ( |
|
!g_foundWidget || |
|
distance <= g_distanceToFoundWidget || |
|
g_foundWidget.widget->type == WIDGET_TYPE_APP_VIEW || |
|
g_foundWidget.widget->type == WIDGET_TYPE_LIST || |
|
g_foundWidget.widget->type == WIDGET_TYPE_GRID |
|
) { |
|
g_foundWidget = widgetCursor; |
|
g_distanceToFoundWidget = distance; |
|
|
|
// if found widget is AppView, make sure we set right AppContext |
|
if (widget->type == WIDGET_TYPE_APP_VIEW) { |
|
if (widget->data != DATA_ID_NONE) { |
|
Value appContextValue = get(widgetCursor, widget->data); |
|
g_foundWidget.appContext = appContextValue.getAppContext(); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
WidgetCursor findWidget(int16_t x, int16_t y, bool clicked) { |
|
g_found = false; |
|
g_foundWidget = 0; |
|
g_clicked = clicked; |
|
|
|
g_findWidgetAtX = x; |
|
g_findWidgetAtY = y; |
|
|
|
g_xOverlayOffset = 0; |
|
g_yOverlayOffset = 0; |
|
|
|
g_popPageAppContext = nullptr; |
|
|
|
forEachWidget(findWidgetStep); |
|
|
|
if (g_popPageAppContext) { |
|
g_popPageAppContext->popPage(); |
|
g_popPageAppContext = nullptr; |
|
} |
|
|
|
return g_foundWidget; |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
void resizeWidget( |
|
const Widget *widget, |
|
Rect &widgetRect, |
|
int containerOriginalWidth, |
|
int containerOriginalHeight, |
|
int containerWidth, |
|
int containerHeight |
|
) { |
|
auto flags = widget->flags; |
|
|
|
auto pinToLeft = flags & WIDGET_FLAG_PIN_TO_LEFT; |
|
auto pinToRight = flags & WIDGET_FLAG_PIN_TO_RIGHT; |
|
auto pinToTop = flags & WIDGET_FLAG_PIN_TO_TOP; |
|
auto pinToBottom = flags & WIDGET_FLAG_PIN_TO_BOTTOM; |
|
|
|
auto fixWidth = flags & WIDGET_FLAG_FIX_WIDTH; |
|
auto fixHeight = flags & WIDGET_FLAG_FIX_HEIGHT; |
|
|
|
auto left = widgetRect.x; |
|
auto right = widgetRect.x + widgetRect.w; |
|
|
|
if (pinToLeft) { |
|
// left = left; |
|
} else { |
|
if (!fixWidth) { |
|
left = |
|
(widgetRect.x * containerWidth) / |
|
containerOriginalWidth; |
|
} |
|
} |
|
|
|
if (pinToRight) { |
|
right = containerWidth - (containerOriginalWidth - right); |
|
} else { |
|
if (!fixWidth) { |
|
right = (right * containerWidth) / containerOriginalWidth; |
|
} |
|
} |
|
|
|
if (fixWidth) { |
|
if (pinToLeft && !pinToRight) { |
|
right = left + widgetRect.w; |
|
} else if (pinToRight && !pinToLeft) { |
|
left = right - widgetRect.w; |
|
} else if (!pinToLeft && !pinToRight) { |
|
auto center = |
|
((widgetRect.x + widgetRect.w / 2) * |
|
containerWidth) / |
|
containerOriginalWidth; |
|
left = center - widgetRect.w / 2; |
|
right = left + widgetRect.w; |
|
} |
|
} |
|
|
|
auto top = widgetRect.y; |
|
auto bottom = widgetRect.y + widgetRect.h; |
|
|
|
if (pinToTop) { |
|
//top = top; |
|
} else { |
|
if (!fixHeight) { |
|
top = |
|
(widgetRect.y * containerHeight) / |
|
containerOriginalHeight; |
|
} |
|
} |
|
|
|
if (pinToBottom) { |
|
bottom = containerHeight - (containerOriginalHeight - bottom); |
|
} else { |
|
if (!fixHeight) { |
|
bottom = |
|
(bottom * containerHeight) / containerOriginalHeight; |
|
} |
|
} |
|
|
|
if (fixHeight) { |
|
if (pinToTop && !pinToBottom) { |
|
bottom = top + widgetRect.h; |
|
} else if (pinToBottom && !pinToTop) { |
|
top = bottom - widgetRect.h; |
|
} else if (!pinToTop && !pinToBottom) { |
|
auto center = |
|
((widgetRect.y + widgetRect.h / 2) * |
|
containerHeight) / |
|
containerOriginalHeight; |
|
top = center - widgetRect.h / 2; |
|
bottom = top + widgetRect.h; |
|
} |
|
} |
|
|
|
|
|
widgetRect.x = left; |
|
widgetRect.y = top; |
|
widgetRect.w = right - left; |
|
widgetRect.h = bottom - top; |
|
} |
|
|
|
void applyTimeline(WidgetCursor& widgetCursor, Rect &widgetRect) { |
|
if (widgetCursor.widget->timeline.count > 0) { |
|
auto x = widgetCursor.widget->x; |
|
auto y = widgetCursor.widget->y; |
|
auto w = widgetCursor.widget->width; |
|
auto h = widgetCursor.widget->height; |
|
float opacity = 1.0f; |
|
|
|
auto timelinePosition = widgetCursor.flowState->timelinePosition; |
|
for (uint32_t i = 0; i < widgetCursor.widget->timeline.count; i++) { |
|
auto keyframe = widgetCursor.widget->timeline[i]; |
|
|
|
if (timelinePosition < keyframe->start) { |
|
continue; |
|
} |
|
|
|
if ( |
|
timelinePosition >= keyframe->start && |
|
timelinePosition <= keyframe->end |
|
) { |
|
auto t = |
|
keyframe->start == keyframe->end |
|
? 1 |
|
: (timelinePosition - keyframe->start) / |
|
(keyframe->end - keyframe->start); |
|
|
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_X) { |
|
auto savedX = x; |
|
x += g_easingFuncs[keyframe->xEasingFunc](t) * (keyframe->x - x); |
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_WIDTH) { |
|
auto right = savedX + w; |
|
right += g_easingFuncs[keyframe->widthEasingFunc](t) * ((keyframe->x + keyframe->width) - right); |
|
w = right - x; |
|
} |
|
} else if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_WIDTH) { |
|
w += g_easingFuncs[keyframe->widthEasingFunc](t) * (keyframe->width - w); |
|
} |
|
|
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_Y) { |
|
auto savedY = y; |
|
y += g_easingFuncs[keyframe->yEasingFunc](t) * (keyframe->y - y); |
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_HEIGHT) { |
|
auto bottom = savedY + h; |
|
bottom += g_easingFuncs[keyframe->heightEasingFunc](t) * ((keyframe->y + keyframe->height) - bottom); |
|
h = bottom - y; |
|
} |
|
} else if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_HEIGHT) { |
|
h += g_easingFuncs[keyframe->heightEasingFunc](t) * (keyframe->height - h); |
|
} |
|
|
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_OPACITY) { |
|
opacity += g_easingFuncs[keyframe->opacityEasingFunc](t) * (keyframe->opacity - opacity); |
|
} |
|
|
|
break; |
|
} |
|
|
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_X) { |
|
x = keyframe->x; |
|
} |
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_Y) { |
|
y = keyframe->y; |
|
} |
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_WIDTH) { |
|
w = keyframe->width; |
|
} |
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_HEIGHT) { |
|
h = keyframe->height; |
|
} |
|
|
|
if (keyframe->enabledProperties & WIDGET_TIMELINE_PROPERTY_OPACITY) { |
|
opacity = keyframe->opacity; |
|
} |
|
} |
|
|
|
widgetRect.x = x; |
|
widgetRect.y = y; |
|
|
|
widgetRect.w = w; |
|
widgetRect.h = h; |
|
|
|
widgetCursor.opacity = (uint8_t)roundf(255.0f * opacity); |
|
} else { |
|
widgetRect.x = widgetCursor.widget->x; |
|
widgetRect.y = widgetCursor.widget->y; |
|
|
|
widgetRect.w = widgetCursor.widget->width; |
|
widgetRect.h = widgetCursor.widget->height; |
|
} |
|
} |
|
|
|
void doStaticLayout( |
|
WidgetCursor& widgetCursor, |
|
const ListOfAssetsPtr<Widget> &widgets, |
|
int containerOriginalWidth, |
|
int containerOriginalHeight, |
|
int containerWidth, |
|
int containerHeight |
|
) { |
|
bool callResizeWidget = containerOriginalWidth != containerWidth || containerOriginalHeight != containerHeight; |
|
|
|
for (uint32_t index = 0; index < widgets.count; ++index) { |
|
widgetCursor.widget = widgets[index]; |
|
|
|
auto savedX = widgetCursor.x; |
|
auto savedY = widgetCursor.y; |
|
auto savedOpacity = widgetCursor.opacity; |
|
|
|
Rect widgetRect; |
|
|
|
applyTimeline(widgetCursor, widgetRect); |
|
|
|
if (callResizeWidget) { |
|
resizeWidget(widgetCursor.widget, widgetRect, containerOriginalWidth, containerOriginalHeight, containerWidth, containerHeight); |
|
} |
|
|
|
widgetCursor.x += widgetRect.x; |
|
widgetCursor.y += widgetRect.y; |
|
|
|
widgetCursor.w = widgetRect.w; |
|
widgetCursor.h = widgetRect.h; |
|
|
|
if (g_isRTL) { |
|
widgetCursor.x = savedX + containerWidth - ((widgetCursor.x - savedX) + widgetCursor.w); |
|
} |
|
|
|
enumWidget(); |
|
|
|
widgetCursor.x = savedX; |
|
widgetCursor.y = savedY; |
|
widgetCursor.opacity = savedOpacity; |
|
} |
|
} |
|
|
|
} // namespace gui |
|
} // namespace eez
|
|
|