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.
 
 
 
 
 
 

306 lines
8.2 KiB

/*
* EEZ Modular 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/>.
*/
#pragma once
#include <eez/gui/geometry.h>
#include <eez/core/memory.h>
namespace eez {
namespace flow {
struct FlowState;
}
namespace gui {
#define WIDGET_TYPES \
WIDGET_TYPE(None, NONE, 0) \
WIDGET_TYPE(Container, CONTAINER, 1) \
WIDGET_TYPE(List, LIST, 2) \
WIDGET_TYPE(Grid, GRID, 3) \
WIDGET_TYPE(Select, SELECT, 4) \
WIDGET_TYPE(DisplayData, DISPLAY_DATA, 5) \
WIDGET_TYPE(Text, TEXT, 6) \
WIDGET_TYPE(MultilineText, MULTILINE_TEXT, 7) \
WIDGET_TYPE(Rectangle, RECTANGLE, 8) \
WIDGET_TYPE(Bitmap, BITMAP, 9) \
WIDGET_TYPE(Button, BUTTON, 10) \
WIDGET_TYPE(ToggleButton, TOGGLE_BUTTON, 11) \
WIDGET_TYPE(ButtonGroup, BUTTON_GROUP, 12) \
WIDGET_TYPE(Reserved, RESERVED, 13) \
WIDGET_TYPE(BarGraph, BAR_GRAPH, 14) \
WIDGET_TYPE(LayoutView, LAYOUT_VIEW, 15) \
WIDGET_TYPE(YTGraph, YT_GRAPH, 16) \
WIDGET_TYPE(UpDown, UP_DOWN, 17) \
WIDGET_TYPE(ListGraph, LIST_GRAPH, 18) \
WIDGET_TYPE(AppView, APP_VIEW, 19) \
WIDGET_TYPE(ScrollBar, SCROLL_BAR, 20) \
WIDGET_TYPE(Progress, PROGRESS, 21) \
WIDGET_TYPE(Canvas, CANVAS, 22) \
WIDGET_TYPE(Gauge, GAUGE, 23) \
WIDGET_TYPE(Input, INPUT, 24) \
WIDGET_TYPE(Roller, ROLLER, 25) \
WIDGET_TYPE(Switch, SWITCH, 26) \
WIDGET_TYPE(Slider, SLIDER, 27) \
WIDGET_TYPE(DropDownList, DROP_DOWN_LIST, 28) \
#define WIDGET_TYPE(NAME_PASCAL_CASE, NAME, ID) WIDGET_TYPE_##NAME = ID,
enum WidgetTypes {
WIDGET_TYPES
};
#undef WIDGET_TYPE
struct Widget;
struct Assets;
////////////////////////////////////////////////////////////////////////////////
struct WidgetState;
class AppContext;
typedef int Cursor;
static const size_t MAX_ITERATORS = 4;
struct BackgroundStyle {
int x;
int y;
const Style *style;
bool active;
};
static const size_t BACKGROUND_STYLE_STACK_SIZE = 10;
struct WidgetCursor {
Assets *assets;
AppContext *appContext;
const Widget *widget;
Cursor cursor;
int32_t iterators[MAX_ITERATORS];
flow::FlowState *flowState;
int16_t x;
int16_t y;
int16_t w;
int16_t h;
uint8_t opacity;
WidgetState *currentState;
bool refreshed;
bool hasPreviousState;
BackgroundStyle backgroundStyleStack[BACKGROUND_STYLE_STACK_SIZE];
size_t backgroundStyleStackPointer;
WidgetCursor()
: assets(nullptr)
, appContext(nullptr)
, widget(nullptr)
, cursor(-1)
, flowState(nullptr)
, x(0)
, y(0)
, opacity(255)
, currentState(nullptr)
, refreshed(true)
, hasPreviousState(false)
, backgroundStyleStackPointer(0)
{
iterators[0] = -1; iterators[1] = -1; iterators[2] = -1; iterators[3] = -1;
}
WidgetCursor(
Assets *assets_,
AppContext *appContext_,
const Widget *widget_,
int16_t x_,
int16_t y_,
WidgetState *currentState_,
bool refreshed_,
bool hasPreviousState_
)
: assets(assets_)
, appContext(appContext_)
, widget(widget_)
, cursor(-1)
, flowState(nullptr)
, x(x_)
, y(y_)
, opacity(255)
, currentState(currentState_)
, refreshed(refreshed_)
, hasPreviousState(hasPreviousState_)
, backgroundStyleStackPointer(0)
{
iterators[0] = -1; iterators[1] = -1; iterators[2] = -1; iterators[3] = -1;
}
WidgetCursor(Cursor cursor_)
: assets(nullptr)
, appContext(nullptr)
, widget(nullptr)
, cursor(cursor_)
, flowState(nullptr)
, x(0)
, y(0)
, opacity(255)
, currentState(nullptr)
, refreshed(true)
, hasPreviousState(false)
, backgroundStyleStackPointer(0)
{
iterators[0] = -1; iterators[1] = -1; iterators[2] = -1; iterators[3] = -1;
}
bool operator!=(const WidgetCursor &rhs) const {
if (widget != rhs.widget || cursor != rhs.cursor) {
return true;
}
if (iterators[0] != rhs.iterators[0] || iterators[1] != rhs.iterators[1] || iterators[2] != rhs.iterators[2] || iterators[3] != rhs.iterators[3]) {
return true;
}
return false;
}
bool operator==(const WidgetCursor &rhs) const {
return !(*this != rhs);
}
explicit operator bool() const {
return widget != nullptr;
}
void pushIterator(int32_t it) {
iterators[3] = iterators[2]; iterators[2] = iterators[1]; iterators[1] = iterators[0]; iterators[0] = it;
}
void popIterator() {
iterators[0] = iterators[1]; iterators[1] = iterators[2]; iterators[2] = iterators[3]; iterators[3] = -1;
}
bool isPage() const;
void pushBackground(int x, int y, const Style *style, bool active);
void popBackground();
};
struct WidgetStateFlags {
unsigned active : 1;
unsigned focused : 1;
unsigned blinking : 1;
unsigned enabled : 1;
};
struct WidgetState {
uint16_t type;
int x;
int y;
int w;
int h;
Value isVisible;
virtual ~WidgetState() {}
virtual bool updateState();
virtual void render();
virtual void enumChildren();
virtual bool hasOnTouch();
virtual void onTouch(const WidgetCursor &widgetCursor, Event &touchEvent);
virtual bool hasOnKeyboard();
virtual bool onKeyboard(const WidgetCursor &widgetCursor, uint8_t key, uint8_t mod);
};
#define WIDGET_STATE_START(WidgetClass) \
const WidgetCursor &widgetCursor = g_widgetCursor; \
auto widget = (const WidgetClass *)widgetCursor.widget; \
bool hasPreviousState = widgetCursor.hasPreviousState; \
if (widget->visible) { \
WIDGET_STATE(isVisible, get(widgetCursor, widget->visible)); \
} \
if (x != widgetCursor.x || y != widgetCursor.y || w != widgetCursor.w || h != widgetCursor.h) { \
x = widgetCursor.x; \
y = widgetCursor.y; \
w = widgetCursor.w; \
h = widgetCursor.h; \
hasPreviousState = false; \
}
#define WIDGET_STATE(A, B) \
if (hasPreviousState) { \
auto temp = B; \
if (A != temp) { \
hasPreviousState = false; \
A = temp; \
} \
} else { \
A = B; \
}
#define WIDGET_STATE_END() \
return !hasPreviousState;
////////////////////////////////////////////////////////////////////////////////
extern bool g_isActiveWidget;
extern bool g_isRTL;
void enumRootWidget();
void enumWidget();
void enumNoneWidget();
extern bool g_foundWidgetAtDownInvalid;
void freeWidgetStates(WidgetState *topWidgetState);
typedef void (*EnumWidgetsCallback)();
extern EnumWidgetsCallback g_findCallback;
void forEachWidget(EnumWidgetsCallback callback);
WidgetCursor findWidget(int16_t x, int16_t y, bool clicked = true);
typedef void (*OnTouchFunctionType)(const WidgetCursor &widgetCursor, Event &touchEvent);
OnTouchFunctionType getWidgetTouchFunction(const WidgetCursor &widgetCursor);
void resizeWidget(
const Widget *widget,
Rect &widgetRect,
int containerOriginalWidth,
int containerOriginalHeight,
int containerWidth,
int containerHeight
);
void applyTimeline(
WidgetCursor& widgetCursor,
Rect &widgetRect
);
template<typename T>
struct ListOfAssetsPtr;
void doStaticLayout(
WidgetCursor& widgetCursor,
const ListOfAssetsPtr<Widget> &widgets,
int containerOriginalWidth,
int containerOriginalHeight,
int containerWidth,
int containerHeight
);
} // namespace gui
} // namespace eez