From 227b1179cc10d9f0fda78e3e010cb6168c5d5dd9 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Thu, 26 Mar 2026 16:11:01 -0500 Subject: [PATCH] Task Manager now it's own library. --- Makefile | 8 +- apps/notepad/notepad.c | 16 +-- apps/progman/progman.c | 5 +- config/taskmgr.dep | 5 + core/dvxApp.c | 50 +++---- core/dvxWidget.h | 227 +++++++++++++++++++++++------- core/widgetCore.c | 8 +- core/widgetEvent.c | 38 ++--- core/widgetLayout.c | 18 +-- core/widgetOps.c | 30 ++-- shell/Makefile | 3 +- shell/shellApp.c | 3 + shell/shellApp.h | 8 ++ shell/shellMain.c | 5 +- taskmgr/Makefile | 41 ++++++ {shell => taskmgr}/shellTaskMgr.c | 23 ++- {shell => taskmgr}/shellTaskMgr.h | 0 texthelp/textHelp.c | 6 +- widgets/widgetAnsiTerm.c | 27 ++-- widgets/widgetBox.c | 42 ++---- widgets/widgetButton.c | 27 ++-- widgets/widgetCanvas.c | 20 ++- widgets/widgetCheckbox.c | 23 +-- widgets/widgetComboBox.c | 32 +++-- widgets/widgetDropdown.c | 27 ++-- widgets/widgetImage.c | 18 ++- widgets/widgetImageButton.c | 25 ++-- widgets/widgetLabel.c | 19 ++- widgets/widgetListBox.c | 23 ++- widgets/widgetListView.c | 44 ++++-- widgets/widgetProgressBar.c | 17 +-- widgets/widgetRadio.c | 38 +++-- widgets/widgetScrollPane.c | 28 ++-- widgets/widgetSeparator.c | 17 +-- widgets/widgetSlider.c | 21 ++- widgets/widgetSpacer.c | 15 +- widgets/widgetSpinner.c | 21 +-- widgets/widgetSplitter.c | 31 ++-- widgets/widgetStatusBar.c | 17 +-- widgets/widgetTabControl.c | 42 +++--- widgets/widgetTextInput.c | 50 +++---- widgets/widgetTimer.c | 16 +-- widgets/widgetToolbar.c | 17 +-- widgets/widgetTreeView.c | 43 +++--- 44 files changed, 657 insertions(+), 537 deletions(-) create mode 100644 config/taskmgr.dep create mode 100644 taskmgr/Makefile rename {shell => taskmgr}/shellTaskMgr.c (93%) rename {shell => taskmgr}/shellTaskMgr.h (100%) diff --git a/Makefile b/Makefile index 2504117..3533398 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,9 @@ # Builds the full DVX stack: core library, task switcher, # bootstrap loader, text help library, widgets, shell, and apps. -.PHONY: all clean core tasks loader texthelp listhelp widgets shell apps +.PHONY: all clean core tasks loader texthelp listhelp widgets shell taskmgr apps -all: core tasks loader texthelp listhelp widgets shell apps +all: core tasks loader texthelp listhelp widgets shell taskmgr apps core: $(MAKE) -C core @@ -28,6 +28,9 @@ widgets: core tasks texthelp listhelp shell: core tasks $(MAKE) -C shell +taskmgr: shell + $(MAKE) -C taskmgr + apps: core tasks shell $(MAKE) -C apps @@ -39,6 +42,7 @@ clean: $(MAKE) -C listhelp clean $(MAKE) -C widgets clean $(MAKE) -C shell clean + $(MAKE) -C taskmgr clean $(MAKE) -C apps clean -rmdir obj 2>/dev/null -rm -rf bin/config bin/widgets bin/libs diff --git a/apps/notepad/notepad.c b/apps/notepad/notepad.c index 7049eac..b325c67 100644 --- a/apps/notepad/notepad.c +++ b/apps/notepad/notepad.c @@ -313,26 +313,26 @@ static void onMenu(WindowT *win, int32_t menuId) { break; case CMD_CUT: - if (sTextArea && sTextArea->wclass && sTextArea->wclass->onKey) { - sTextArea->wclass->onKey(sTextArea, 24, 0); // Ctrl+X + if (sTextArea) { + wclsOnKey(sTextArea, 24, 0); // Ctrl+X } break; case CMD_COPY: - if (sTextArea && sTextArea->wclass && sTextArea->wclass->onKey) { - sTextArea->wclass->onKey(sTextArea, 3, 0); // Ctrl+C + if (sTextArea) { + wclsOnKey(sTextArea, 3, 0); // Ctrl+C } break; case CMD_PASTE: - if (sTextArea && sTextArea->wclass && sTextArea->wclass->onKey) { - sTextArea->wclass->onKey(sTextArea, 22, 0); // Ctrl+V + if (sTextArea) { + wclsOnKey(sTextArea, 22, 0); // Ctrl+V } break; case CMD_SELALL: - if (sTextArea && sTextArea->wclass && sTextArea->wclass->onKey) { - sTextArea->wclass->onKey(sTextArea, 1, 0); // Ctrl+A + if (sTextArea) { + wclsOnKey(sTextArea, 1, 0); // Ctrl+A } break; } diff --git a/apps/progman/progman.c b/apps/progman/progman.c index 26ccf92..28304c7 100644 --- a/apps/progman/progman.c +++ b/apps/progman/progman.c @@ -30,7 +30,6 @@ #include "dvxWm.h" #include "dvxPlatform.h" #include "shellApp.h" -#include "shellTaskMgr.h" #include "shellInfo.h" #include @@ -314,7 +313,9 @@ static void onPmMenu(WindowT *win, int32_t menuId) { break; case CMD_TASK_MGR: - shellTaskMgrOpen(sAc); + if (shellCtrlEscFn) { + shellCtrlEscFn(sAc); + } break; } } diff --git a/config/taskmgr.dep b/config/taskmgr.dep new file mode 100644 index 0000000..3812493 --- /dev/null +++ b/config/taskmgr.dep @@ -0,0 +1,5 @@ +dvxshell +libtasks +libdvx +texthelp +listhelp diff --git a/core/dvxApp.c b/core/dvxApp.c index 87e5195..f189bc2 100644 --- a/core/dvxApp.c +++ b/core/dvxApp.c @@ -726,17 +726,15 @@ static bool dispatchAccelKey(AppContextT *ctx, char key) { sFocusedWidget = next; next->focused = true; - if (next->wclass && next->wclass->onAccelActivate) { - next->wclass->onAccelActivate(next, win->widgetRoot); - } + wclsOnAccelActivate(next, win->widgetRoot); wgtInvalidate(win->widgetRoot); } - } else if (target->wclass->onAccelActivate) { + } else if (wclsHas(target, WGT_METHOD_ON_ACCEL_ACTIVATE)) { if (sFocusedWidget) { sFocusedWidget->focused = false; } sFocusedWidget = target; target->focused = true; - target->wclass->onAccelActivate(target, win->widgetRoot); + wclsOnAccelActivate(target, win->widgetRoot); wgtInvalidate(win->widgetRoot); } @@ -1136,7 +1134,7 @@ static void dispatchEvents(AppContextT *ctx) { if (win->widgetRoot) { WidgetT *focus = wgtGetFocused(); - if (focus && focus->wclass && focus->wclass->onKey) { + if (focus && wclsHas(focus, WGT_METHOD_ON_KEY)) { // Find the scrollable target: either the focused widget // itself or a ScrollPane ancestor that contains it. WidgetT *target = NULL; @@ -1153,13 +1151,13 @@ static void dispatchEvents(AppContextT *ctx) { } } - if (target && target->wclass && target->wclass->onKey) { + if (target && wclsHas(target, WGT_METHOD_ON_KEY)) { int32_t delta = ctx->mouseWheel * ctx->wheelDirection; int32_t arrowKey = (delta > 0) ? (0x50 | 0x100) : (0x48 | 0x100); int32_t steps = abs(delta) * MOUSE_WHEEL_STEP; for (int32_t s = 0; s < steps; s++) { - target->wclass->onKey(target, arrowKey, 0); + wclsOnKey(target, arrowKey, 0); } // Ensure the window repaints even if the widget's @@ -2657,12 +2655,12 @@ bool dvxUpdate(AppContextT *ctx) { // onClick. The one-frame delay ensures the pressed visual state // renders before the callback runs (which may open a dialog, etc.). if (sKeyPressedBtn) { - if (sKeyPressedBtn->wclass && sKeyPressedBtn->wclass->onDragEnd) { + if (wclsHas(sKeyPressedBtn, WGT_METHOD_ON_DRAG_END)) { // Pass button center as coordinates so bounds check succeeds and onClick fires WidgetT *root = sKeyPressedBtn->window ? sKeyPressedBtn->window->widgetRoot : sKeyPressedBtn; - sKeyPressedBtn->wclass->onDragEnd(sKeyPressedBtn, root, - sKeyPressedBtn->x + sKeyPressedBtn->w / 2, - sKeyPressedBtn->y + sKeyPressedBtn->h / 2); + wclsOnDragEnd(sKeyPressedBtn, root, + sKeyPressedBtn->x + sKeyPressedBtn->w / 2, + sKeyPressedBtn->y + sKeyPressedBtn->h / 2); } wgtInvalidate(sKeyPressedBtn); @@ -3634,17 +3632,17 @@ static void pollWidgets(AppContextT *ctx) { // ============================================================ static void pollWidgetsWalk(AppContextT *ctx, WidgetT *w, WindowT *win) { - if (w->wclass && (w->wclass->flags & WCLASS_NEEDS_POLL) && w->wclass->poll) { - w->wclass->poll(w, win); + if (w->wclass && (w->wclass->flags & WCLASS_NEEDS_POLL) && wclsHas(w, WGT_METHOD_POLL)) { + wclsPoll(w, win); // If the poll dirtied internal state and the widget supports // quickRepaint, render the dirty rows directly into the window's // content buffer and add the affected area to the global dirty list. - if (w->wclass->quickRepaint) { + if (wclsHas(w, WGT_METHOD_QUICK_REPAINT)) { int32_t dirtyY = 0; int32_t dirtyH = 0; - if (w->wclass->quickRepaint(w, &dirtyY, &dirtyH) > 0) { + if (wclsQuickRepaint(w, &dirtyY, &dirtyH) > 0) { int32_t scrollY = win->vScroll ? win->vScroll->value : 0; int32_t rectX = win->x + win->contentX; int32_t rectY = win->y + win->contentY + dirtyY - scrollY; @@ -4220,17 +4218,13 @@ static void pollKeyboard(AppContextT *ctx) { int32_t popY; int32_t popW; int32_t popH; - if (sOpenPopup->wclass && sOpenPopup->wclass->getPopupRect) { - sOpenPopup->wclass->getPopupRect(sOpenPopup, &ctx->font, popWin->contentH, &popX, &popY, &popW, &popH); - } + wclsGetPopupRect(sOpenPopup, &ctx->font, popWin->contentH, &popX, &popY, &popW, &popH); dirtyListAdd(&ctx->dirty, popWin->x + popWin->contentX + popX, popWin->y + popWin->contentY + popY, popW, popH); WidgetT *closing = sOpenPopup; sOpenPopup = NULL; - if (closing->wclass && closing->wclass->closePopup) { - closing->wclass->closePopup(closing); - } + wclsClosePopup(closing); wgtInvalidate(closing); continue; @@ -4364,8 +4358,8 @@ static void pollKeyboard(AppContextT *ctx) { // Scroll into view inside any scroll container ancestor for (WidgetT *p = next->parent; p; p = p->parent) { if (p->wclass && (p->wclass->flags & WCLASS_SCROLL_CONTAINER) && - p->wclass->scrollChildIntoView) { - p->wclass->scrollChildIntoView(p, next); + wclsHas(p, WGT_METHOD_SCROLL_CHILD_INTO_VIEW)) { + wclsScrollChildIntoView(p, next); break; } } @@ -4552,8 +4546,8 @@ static void updateCursorShape(AppContextT *ctx) { } } // Active widget drag -- query cursor shape from the dragged widget - else if (sDragWidget && sDragWidget->wclass && sDragWidget->wclass->getCursorShape) { - int32_t shape = sDragWidget->wclass->getCursorShape(sDragWidget, 0, 0); + else if (sDragWidget) { + int32_t shape = wclsGetCursorShape(sDragWidget, 0, 0); if (shape > 0) { newCursor = shape; @@ -4597,8 +4591,8 @@ static void updateCursorShape(AppContextT *ctx) { WidgetT *hit = widgetHitTest(win->widgetRoot, vx, vy); - if (hit && hit->wclass && hit->wclass->getCursorShape) { - int32_t shape = hit->wclass->getCursorShape(hit, vx, vy); + if (hit) { + int32_t shape = wclsGetCursorShape(hit, vx, vy); if (shape > 0) { newCursor = shape; diff --git a/core/dvxWidget.h b/core/dvxWidget.h index 554ac40..1ffd3ef 100644 --- a/core/dvxWidget.h +++ b/core/dvxWidget.h @@ -111,7 +111,7 @@ typedef enum { // in their respective widget .c files. // ============================================================ -// Widget class vtable +// Widget class dispatch table // ============================================================ // // Each widget type has a WidgetClassT that defines its behavior. @@ -119,6 +119,13 @@ typedef enum { // (from DXE plugins) are stored in the mutable region of // widgetClassTable[]. // +// The handlers[] array provides ABI-stable dispatch: method IDs are +// fixed constants that never change. Adding new methods appends new +// IDs without shifting existing ones, so widget DXEs compiled against +// an older DVX version continue to work unmodified. The version field +// is checked at wgtRegisterClass() time to catch DXEs compiled against +// an incompatible layout. +// // Flags encode static properties checked by the framework: // FOCUSABLE -- can receive keyboard focus (Tab navigation) // BOX_CONTAINER -- uses the generic VBox/HBox layout algorithm @@ -143,55 +150,38 @@ typedef enum { #define WCLASS_PRESS_RELEASE 0x00001000 // click = press+release (Button, ImageButton) #define WCLASS_ACCEL_WHEN_HIDDEN 0x00002000 // accel matching works even when invisible +// Method IDs -- stable ABI, never reorder, never reuse. +// New methods are appended at the end with the next sequential ID. +#define WGT_METHOD_PAINT 0 // void (w, d, ops, font, colors) +#define WGT_METHOD_PAINT_OVERLAY 1 // void (w, d, ops, font, colors) +#define WGT_METHOD_CALC_MIN_SIZE 2 // void (w, font) +#define WGT_METHOD_LAYOUT 3 // void (w, font) +#define WGT_METHOD_GET_LAYOUT_METRICS 4 // void (w, font, pad, gap, extraTop, borderW) +#define WGT_METHOD_ON_MOUSE 5 // void (w, root, vx, vy) +#define WGT_METHOD_ON_KEY 6 // void (w, key, mod) +#define WGT_METHOD_ON_ACCEL_ACTIVATE 7 // void (w, root) +#define WGT_METHOD_DESTROY 8 // void (w) +#define WGT_METHOD_ON_CHILD_CHANGED 9 // void (parent, child) +#define WGT_METHOD_GET_TEXT 10 // const char *(w) +#define WGT_METHOD_SET_TEXT 11 // void (w, text) +#define WGT_METHOD_CLEAR_SELECTION 12 // bool (w) +#define WGT_METHOD_CLOSE_POPUP 13 // void (w) +#define WGT_METHOD_GET_POPUP_RECT 14 // void (w, font, contentH, popX, popY, popW, popH) +#define WGT_METHOD_ON_DRAG_UPDATE 15 // void (w, root, x, y) +#define WGT_METHOD_ON_DRAG_END 16 // void (w, root, x, y) +#define WGT_METHOD_GET_CURSOR_SHAPE 17 // int32_t (w, vx, vy) +#define WGT_METHOD_POLL 18 // void (w, win) +#define WGT_METHOD_QUICK_REPAINT 19 // int32_t (w, outY, outH) +#define WGT_METHOD_SCROLL_CHILD_INTO_VIEW 20 // void (parent, child) +#define WGT_METHOD_COUNT 21 +#define WGT_METHOD_MAX 32 // room for future methods + +#define WGT_CLASS_VERSION 1 // bump on breaking ABI change + typedef struct WidgetClassT { - uint32_t flags; - - // Rendering - void (*paint)(struct WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors); - void (*paintOverlay)(struct WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors); - - // Layout - void (*calcMinSize)(struct WidgetT *w, const BitmapFontT *font); - void (*layout)(struct WidgetT *w, const BitmapFontT *font); - void (*getLayoutMetrics)(const struct WidgetT *w, const BitmapFontT *font, int32_t *pad, int32_t *gap, int32_t *extraTop, int32_t *borderW); - - // Input - void (*onMouse)(struct WidgetT *w, struct WidgetT *root, int32_t vx, int32_t vy); - void (*onKey)(struct WidgetT *w, int32_t key, int32_t mod); - void (*onAccelActivate)(struct WidgetT *w, struct WidgetT *root); - - // Lifecycle - void (*destroy)(struct WidgetT *w); - void (*onChildChanged)(struct WidgetT *parent, struct WidgetT *child); - - // Text - const char *(*getText)(const struct WidgetT *w); - void (*setText)(struct WidgetT *w, const char *text); - - // Selection - bool (*clearSelection)(struct WidgetT *w); - - // Popup (dropdown/combobox) - void (*closePopup)(struct WidgetT *w); - void (*getPopupRect)(const struct WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH); - - // Generic drag (button press, slider, scrollbar, text select, reorder, etc.) - // Core sets sDragWidget on mouse-down; calls onDragUpdate on mouse-move - // and onDragEnd on mouse-up. Each widget stores its own drag state. - void (*onDragUpdate)(struct WidgetT *w, struct WidgetT *root, int32_t x, int32_t y); - void (*onDragEnd)(struct WidgetT *w, struct WidgetT *root, int32_t x, int32_t y); - - // Cursor shape (returns cursor ID, 0 = default) - int32_t (*getCursorShape)(const struct WidgetT *w, int32_t vx, int32_t vy); - - // Polling (AnsiTerm comms) - void (*poll)(struct WidgetT *w, WindowT *win); - - // Fast incremental repaint (returns dirty row count, 0 = none) - int32_t (*quickRepaint)(struct WidgetT *w, int32_t *outY, int32_t *outH); - - // Scroll a child widget into the visible area (ScrollPane, etc.) - void (*scrollChildIntoView)(struct WidgetT *parent, const struct WidgetT *child); + uint32_t version; + uint32_t flags; + void *handlers[WGT_METHOD_MAX]; } WidgetClassT; // ============================================================ @@ -277,6 +267,145 @@ typedef struct WidgetT { } WidgetT; +// ============================================================ +// Typed dispatch helpers +// ============================================================ +// +// Each wclsFoo() inline function extracts a handler by stable method ID, +// casts it to the correct function pointer type, and calls it with a +// NULL check. This gives callers type-safe dispatch with the same +// codegen as a direct struct field call. + +static inline bool wclsHas(const WidgetT *w, int32_t methodId) { + return w->wclass && w->wclass->handlers[methodId] != NULL; +} + +static inline void wclsPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) { + typedef void (*FnT)(WidgetT *, DisplayT *, const BlitOpsT *, const BitmapFontT *, const ColorSchemeT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_PAINT] : NULL; + if (fn) { fn(w, d, ops, font, colors); } +} + +static inline void wclsPaintOverlay(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) { + typedef void (*FnT)(WidgetT *, DisplayT *, const BlitOpsT *, const BitmapFontT *, const ColorSchemeT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_PAINT_OVERLAY] : NULL; + if (fn) { fn(w, d, ops, font, colors); } +} + +static inline void wclsCalcMinSize(WidgetT *w, const BitmapFontT *font) { + typedef void (*FnT)(WidgetT *, const BitmapFontT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_CALC_MIN_SIZE] : NULL; + if (fn) { fn(w, font); } +} + +static inline void wclsLayout(WidgetT *w, const BitmapFontT *font) { + typedef void (*FnT)(WidgetT *, const BitmapFontT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_LAYOUT] : NULL; + if (fn) { fn(w, font); } +} + +static inline void wclsGetLayoutMetrics(const WidgetT *w, const BitmapFontT *font, int32_t *pad, int32_t *gap, int32_t *extraTop, int32_t *borderW) { + typedef void (*FnT)(const WidgetT *, const BitmapFontT *, int32_t *, int32_t *, int32_t *, int32_t *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_GET_LAYOUT_METRICS] : NULL; + if (fn) { fn(w, font, pad, gap, extraTop, borderW); } +} + +static inline void wclsOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { + typedef void (*FnT)(WidgetT *, WidgetT *, int32_t, int32_t); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_MOUSE] : NULL; + if (fn) { fn(w, root, vx, vy); } +} + +static inline void wclsOnKey(WidgetT *w, int32_t key, int32_t mod) { + typedef void (*FnT)(WidgetT *, int32_t, int32_t); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_KEY] : NULL; + if (fn) { fn(w, key, mod); } +} + +static inline void wclsOnAccelActivate(WidgetT *w, WidgetT *root) { + typedef void (*FnT)(WidgetT *, WidgetT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_ACCEL_ACTIVATE] : NULL; + if (fn) { fn(w, root); } +} + +static inline void wclsDestroy(WidgetT *w) { + typedef void (*FnT)(WidgetT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_DESTROY] : NULL; + if (fn) { fn(w); } +} + +static inline void wclsOnChildChanged(WidgetT *parent, WidgetT *child) { + typedef void (*FnT)(WidgetT *, WidgetT *); + FnT fn = parent->wclass ? (FnT)parent->wclass->handlers[WGT_METHOD_ON_CHILD_CHANGED] : NULL; + if (fn) { fn(parent, child); } +} + +static inline const char *wclsGetText(const WidgetT *w) { + typedef const char *(*FnT)(const WidgetT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_GET_TEXT] : NULL; + return fn ? fn(w) : ""; +} + +static inline void wclsSetText(WidgetT *w, const char *text) { + typedef void (*FnT)(WidgetT *, const char *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_SET_TEXT] : NULL; + if (fn) { fn(w, text); } +} + +static inline bool wclsClearSelection(WidgetT *w) { + typedef bool (*FnT)(WidgetT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_CLEAR_SELECTION] : NULL; + return fn ? fn(w) : false; +} + +static inline void wclsClosePopup(WidgetT *w) { + typedef void (*FnT)(WidgetT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_CLOSE_POPUP] : NULL; + if (fn) { fn(w); } +} + +static inline void wclsGetPopupRect(const WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH) { + typedef void (*FnT)(const WidgetT *, const BitmapFontT *, int32_t, int32_t *, int32_t *, int32_t *, int32_t *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_GET_POPUP_RECT] : NULL; + if (fn) { fn(w, font, contentH, popX, popY, popW, popH); } +} + +static inline void wclsOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + typedef void (*FnT)(WidgetT *, WidgetT *, int32_t, int32_t); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_DRAG_UPDATE] : NULL; + if (fn) { fn(w, root, x, y); } +} + +static inline void wclsOnDragEnd(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + typedef void (*FnT)(WidgetT *, WidgetT *, int32_t, int32_t); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_ON_DRAG_END] : NULL; + if (fn) { fn(w, root, x, y); } +} + +static inline int32_t wclsGetCursorShape(const WidgetT *w, int32_t vx, int32_t vy) { + typedef int32_t (*FnT)(const WidgetT *, int32_t, int32_t); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_GET_CURSOR_SHAPE] : NULL; + return fn ? fn(w, vx, vy) : 0; +} + +static inline void wclsPoll(WidgetT *w, WindowT *win) { + typedef void (*FnT)(WidgetT *, WindowT *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_POLL] : NULL; + if (fn) { fn(w, win); } +} + +static inline int32_t wclsQuickRepaint(WidgetT *w, int32_t *outY, int32_t *outH) { + typedef int32_t (*FnT)(WidgetT *, int32_t *, int32_t *); + FnT fn = w->wclass ? (FnT)w->wclass->handlers[WGT_METHOD_QUICK_REPAINT] : NULL; + return fn ? fn(w, outY, outH) : 0; +} + +static inline void wclsScrollChildIntoView(WidgetT *parent, const WidgetT *child) { + typedef void (*FnT)(WidgetT *, const WidgetT *); + FnT fn = parent->wclass ? (FnT)parent->wclass->handlers[WGT_METHOD_SCROLL_CHILD_INTO_VIEW] : NULL; + if (fn) { fn(parent, child); } +} + // ============================================================ // Window integration // ============================================================ diff --git a/core/widgetCore.c b/core/widgetCore.c index d3fcefa..9383c5c 100644 --- a/core/widgetCore.c +++ b/core/widgetCore.c @@ -251,9 +251,7 @@ void widgetDestroyChildren(WidgetT *w) { WidgetT *next = child->nextSibling; widgetDestroyChildren(child); - if (child->wclass && child->wclass->destroy) { - child->wclass->destroy(child); - } + wclsDestroy(child); // Clear static references if they point to destroyed widgets if (sFocusedWidget == child) { @@ -455,7 +453,7 @@ WidgetT *widgetFindPrevFocusable(WidgetT *root, WidgetT *before) { // ============================================================ int32_t widgetFrameBorderWidth(const WidgetT *w) { - if (!w->wclass || !w->wclass->getLayoutMetrics) { + if (!wclsHas(w, WGT_METHOD_GET_LAYOUT_METRICS)) { return 0; } @@ -464,7 +462,7 @@ int32_t widgetFrameBorderWidth(const WidgetT *w) { int32_t extraTop = 0; int32_t borderW = 0; - w->wclass->getLayoutMetrics(w, NULL, &pad, &gap, &extraTop, &borderW); + wclsGetLayoutMetrics(w, NULL, &pad, &gap, &extraTop, &borderW); return borderW; } diff --git a/core/widgetEvent.c b/core/widgetEvent.c index 8d1289e..50da465 100644 --- a/core/widgetEvent.c +++ b/core/widgetEvent.c @@ -173,9 +173,7 @@ void widgetOnKey(WindowT *win, int32_t key, int32_t mod) { } // Dispatch to per-widget onKey handler via vtable - if (focus->wclass && focus->wclass->onKey) { - focus->wclass->onKey(focus, key, mod); - } + wclsOnKey(focus, key, mod); } @@ -207,18 +205,13 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { // Close popups from other windows if (sOpenPopup && sOpenPopup->window != win) { - if (sOpenPopup->wclass && sOpenPopup->wclass->closePopup) { - sOpenPopup->wclass->closePopup(sOpenPopup); - } - + wclsClosePopup(sOpenPopup); sOpenPopup = NULL; } // Handle drag release if (sDragWidget && !(buttons & MOUSE_LEFT)) { - if (sDragWidget->wclass && sDragWidget->wclass->onDragEnd) { - sDragWidget->wclass->onDragEnd(sDragWidget, root, x, y); - } + wclsOnDragEnd(sDragWidget, root, x, y); wgtInvalidatePaint(root); sDragWidget = NULL; @@ -227,16 +220,14 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { // Handle drag move if (sDragWidget && (buttons & MOUSE_LEFT)) { - if (sDragWidget->wclass && sDragWidget->wclass->onDragUpdate) { - sDragWidget->wclass->onDragUpdate(sDragWidget, root, x, y); - } + wclsOnDragUpdate(sDragWidget, root, x, y); // quickRepaint fast path for text drag (dirty rect instead of full repaint) - if (sDragWidget->wclass && sDragWidget->wclass->quickRepaint) { + if (wclsHas(sDragWidget, WGT_METHOD_QUICK_REPAINT)) { int32_t dirtyY = 0; int32_t dirtyH = 0; - if (sDragWidget->wclass->quickRepaint(sDragWidget, &dirtyY, &dirtyH) > 0) { + if (wclsQuickRepaint(sDragWidget, &dirtyY, &dirtyH) > 0) { AppContextT *ctx = (AppContextT *)root->userData; int32_t scrollY2 = win->vScroll ? win->vScroll->value : 0; int32_t rectX = win->x + win->contentX; @@ -268,18 +259,16 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { int32_t popW; int32_t popH; - if (!sOpenPopup->wclass || !sOpenPopup->wclass->getPopupRect) { + if (!wclsHas(sOpenPopup, WGT_METHOD_GET_POPUP_RECT)) { sOpenPopup = NULL; return; } - sOpenPopup->wclass->getPopupRect(sOpenPopup, font, win->contentH, &popX, &popY, &popW, &popH); + wclsGetPopupRect(sOpenPopup, font, win->contentH, &popX, &popY, &popW, &popH); if (x >= popX && x < popX + popW && y >= popY && y < popY + popH) { // Click on popup item -- dispatch to widget's onMouse - if (sOpenPopup->wclass && sOpenPopup->wclass->onMouse) { - sOpenPopup->wclass->onMouse(sOpenPopup, root, x, y); - } + wclsOnMouse(sOpenPopup, root, x, y); sOpenPopup = NULL; wgtInvalidate(root); @@ -289,10 +278,7 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { // Click outside popup -- close it and remember which widget it was sClosedPopup = sOpenPopup; - if (sOpenPopup->wclass && sOpenPopup->wclass->closePopup) { - sOpenPopup->wclass->closePopup(sOpenPopup); - } - + wclsClosePopup(sOpenPopup); sOpenPopup = NULL; wgtInvalidatePaint(root); // Fall through to normal click handling @@ -325,8 +311,8 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { // Dispatch to the hit widget's mouse handler via vtable. The handler // is responsible for setting hit->focused=true if it wants focus. - if (hit->enabled && hit->wclass && hit->wclass->onMouse) { - hit->wclass->onMouse(hit, root, vx, vy); + if (hit->enabled) { + wclsOnMouse(hit, root, vx, vy); } // Universal click/double-click callbacks -- fire for ALL widget types diff --git a/core/widgetLayout.c b/core/widgetLayout.c index 6d57d10..5ab9a24 100644 --- a/core/widgetLayout.c +++ b/core/widgetLayout.c @@ -62,9 +62,9 @@ void widgetCalcMinSizeBox(WidgetT *w, const BitmapFontT *font) { // Widgets with getLayoutMetrics override default padding/gap/extraTop int32_t frameExtraTop = 0; - if (w->wclass && w->wclass->getLayoutMetrics) { + if (wclsHas(w, WGT_METHOD_GET_LAYOUT_METRICS)) { int32_t metricBorderW = 0; - w->wclass->getLayoutMetrics(w, font, &pad, &gap, &frameExtraTop, &metricBorderW); + wclsGetLayoutMetrics(w, font, &pad, &gap, &frameExtraTop, &metricBorderW); } for (WidgetT *c = w->firstChild; c; c = c->nextSibling) { @@ -103,7 +103,7 @@ void widgetCalcMinSizeBox(WidgetT *w, const BitmapFontT *font) { } // Border (Frame and similar containers with getLayoutMetrics) - if (w->wclass && w->wclass->getLayoutMetrics) { + if (wclsHas(w, WGT_METHOD_GET_LAYOUT_METRICS)) { int32_t fb = widgetFrameBorderWidth(w); w->calcMinW += fb * 2; w->calcMinH += fb * 2; @@ -130,8 +130,8 @@ void widgetCalcMinSizeBox(WidgetT *w, const BitmapFontT *font) { void widgetCalcMinSizeTree(WidgetT *w, const BitmapFontT *font) { if (widgetIsBoxContainer(w->type)) { widgetCalcMinSizeBox(w, font); - } else if (w->wclass && w->wclass->calcMinSize) { - w->wclass->calcMinSize(w, font); + } else if (wclsHas(w, WGT_METHOD_CALC_MIN_SIZE)) { + wclsCalcMinSize(w, font); } else { w->calcMinW = 0; w->calcMinH = 0; @@ -201,8 +201,8 @@ void widgetLayoutBox(WidgetT *w, const BitmapFontT *font) { int32_t frameExtraTop = 0; int32_t fb = 0; - if (w->wclass && w->wclass->getLayoutMetrics) { - w->wclass->getLayoutMetrics(w, font, &pad, &gap, &frameExtraTop, &fb); + if (wclsHas(w, WGT_METHOD_GET_LAYOUT_METRICS)) { + wclsGetLayoutMetrics(w, font, &pad, &gap, &frameExtraTop, &fb); } int32_t innerX = w->x + pad + fb; @@ -338,8 +338,8 @@ void widgetLayoutBox(WidgetT *w, const BitmapFontT *font) { void widgetLayoutChildren(WidgetT *w, const BitmapFontT *font) { if (widgetIsBoxContainer(w->type)) { widgetLayoutBox(w, font); - } else if (w->wclass && w->wclass->layout) { - w->wclass->layout(w, font); + } else if (wclsHas(w, WGT_METHOD_LAYOUT)) { + wclsLayout(w, font); } } diff --git a/core/widgetOps.c b/core/widgetOps.c index b396e01..42a0157 100644 --- a/core/widgetOps.c +++ b/core/widgetOps.c @@ -75,9 +75,7 @@ void widgetPaintOne(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFo } // Paint this widget via vtable - if (w->wclass && w->wclass->paint) { - w->wclass->paint(w, d, ops, font, colors); - } + wclsPaint(w, d, ops, font, colors); // Widgets that paint their own children return early if (w->wclass && (w->wclass->flags & WCLASS_PAINTS_CHILDREN)) { @@ -128,9 +126,7 @@ void widgetPaintOverlays(WidgetT *root, DisplayT *d, const BlitOpsT *ops, const return; } - if (sOpenPopup->wclass && sOpenPopup->wclass->paintOverlay) { - sOpenPopup->wclass->paintOverlay(sOpenPopup, d, ops, font, colors); - } + wclsPaintOverlay(sOpenPopup, d, ops, font, colors); } @@ -158,8 +154,8 @@ void wgtDestroy(WidgetT *w) { // Notify parent chain of child destruction via onChildChanged vtable if (w->parent) { for (WidgetT *p = w->parent; p; p = p->parent) { - if (p->wclass && p->wclass->onChildChanged) { - p->wclass->onChildChanged(p, w); + if (wclsHas(p, WGT_METHOD_ON_CHILD_CHANGED)) { + wclsOnChildChanged(p, w); break; } } @@ -171,9 +167,7 @@ void wgtDestroy(WidgetT *w) { widgetDestroyChildren(w); - if (w->wclass && w->wclass->destroy) { - w->wclass->destroy(w); - } + wclsDestroy(w); // Clear static references if (sFocusedWidget == w) { @@ -280,11 +274,7 @@ const char *wgtGetText(const WidgetT *w) { return ""; } - if (w->wclass && w->wclass->getText) { - return w->wclass->getText(w); - } - - return ""; + return wclsGetText(w); } @@ -502,9 +492,7 @@ void wgtSetText(WidgetT *w, const char *text) { return; } - if (w->wclass && w->wclass->setText) { - w->wclass->setText(w, text); - } + wclsSetText(w, text); wgtInvalidate(w); } @@ -532,8 +520,8 @@ void wgtSetVisible(WidgetT *w, bool visible) { // Notify parent chain of child visibility change via onChildChanged vtable if (w->parent) { for (WidgetT *p = w->parent; p; p = p->parent) { - if (p->wclass && p->wclass->onChildChanged) { - p->wclass->onChildChanged(p, w); + if (wclsHas(p, WGT_METHOD_ON_CHILD_CHANGED)) { + wclsOnChildChanged(p, w); break; } } diff --git a/shell/Makefile b/shell/Makefile index 8aecfcd..181aaec 100644 --- a/shell/Makefile +++ b/shell/Makefile @@ -13,7 +13,7 @@ CONFIGDIR = ../bin/config THEMEDIR = ../bin/config/themes WPAPERDIR = ../bin/config/wpaper -SRCS = shellMain.c shellApp.c shellInfo.c shellTaskMgr.c +SRCS = shellMain.c shellApp.c shellInfo.c OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS)) TARGET = $(LIBSDIR)/dvxshell.lib @@ -63,7 +63,6 @@ SHELL_DEPS = shellApp.h ../core/dvxWidget.h ../core/dvxApp.h ../core/dvxTypes.h $(OBJDIR)/shellMain.o: shellMain.c $(SHELL_DEPS) $(OBJDIR)/shellApp.o: shellApp.c $(SHELL_DEPS) $(OBJDIR)/shellInfo.o: shellInfo.c shellInfo.h $(SHELL_DEPS) -$(OBJDIR)/shellTaskMgr.o: shellTaskMgr.c shellTaskMgr.h $(SHELL_DEPS) clean: rm -f $(OBJS) $(TARGET) $(LIBSDIR)/dvxshell.dep diff --git a/shell/shellApp.c b/shell/shellApp.c index 44a369b..4693048 100644 --- a/shell/shellApp.c +++ b/shell/shellApp.c @@ -25,6 +25,9 @@ static ShellAppT *sApps = NULL; static int32_t sAppsCap = 0; // number of slots allocated (including slot 0) +// Ctrl+Esc handler -- set by taskmgr DXE constructor, NULL if not loaded +void (*shellCtrlEscFn)(AppContextT *ctx) = NULL; + // ============================================================ // Prototypes // ============================================================ diff --git a/shell/shellApp.h b/shell/shellApp.h index de416d5..86fbfa6 100644 --- a/shell/shellApp.h +++ b/shell/shellApp.h @@ -170,4 +170,12 @@ void shellUnregisterDesktopUpdate(void (*updateFn)(void)); // Notify the desktop app that app state has changed (load, reap, crash). void shellDesktopUpdate(void); +// ============================================================ +// Ctrl+Esc handler (set by taskmgr library) +// ============================================================ + +// Function pointer set by the taskmgr DXE's constructor. The shell +// calls this on Ctrl+Esc. NULL if taskmgr is not loaded. +extern void (*shellCtrlEscFn)(AppContextT *ctx); + #endif // SHELL_APP_H diff --git a/shell/shellMain.c b/shell/shellMain.c index 002d8b4..453b4b1 100644 --- a/shell/shellMain.c +++ b/shell/shellMain.c @@ -28,7 +28,6 @@ #include "shellApp.h" #include "shellInfo.h" -#include "shellTaskMgr.h" #include "dvxDialog.h" #include "dvxPrefs.h" #include "dvxPlatform.h" @@ -77,7 +76,9 @@ void shellDesktopUpdate(void) { // ============================================================ static void ctrlEscHandler(void *ctx) { - shellTaskMgrOpen((AppContextT *)ctx); + if (shellCtrlEscFn) { + shellCtrlEscFn((AppContextT *)ctx); + } } diff --git a/taskmgr/Makefile b/taskmgr/Makefile new file mode 100644 index 0000000..2da93da --- /dev/null +++ b/taskmgr/Makefile @@ -0,0 +1,41 @@ +# DVX Task Manager Makefile for DJGPP cross-compilation +# +# Builds taskmgr.lib -- the Task Manager, loaded as a separate DXE. + +DJGPP_PREFIX = $(HOME)/djgpp/djgpp +CC = $(DJGPP_PREFIX)/bin/i586-pc-msdosdjgpp-gcc +DXE3GEN = PATH=$(DJGPP_PREFIX)/bin:$(PATH) DJDIR=$(DJGPP_PREFIX)/i586-pc-msdosdjgpp $(DJGPP_PREFIX)/i586-pc-msdosdjgpp/bin/dxe3gen +CFLAGS = -O2 -Wall -Wextra -march=i486 -mtune=i586 -I../core -I../core/platform -I../widgets -I../shell -I../tasks -I../core/thirdparty + +OBJDIR = ../obj/taskmgr +LIBSDIR = ../bin/libs + +SRCS = shellTaskMgr.c +OBJS = $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS)) +TARGET = $(LIBSDIR)/taskmgr.lib + +.PHONY: all clean + +all: $(TARGET) $(LIBSDIR)/taskmgr.dep + +$(LIBSDIR)/taskmgr.dep: ../config/taskmgr.dep | $(LIBSDIR) + sed 's/$$/\r/' $< > $@ + +$(TARGET): $(OBJS) | $(LIBSDIR) + $(DXE3GEN) -o $(LIBSDIR)/taskmgr.dxe -U $(OBJS) + mv $(LIBSDIR)/taskmgr.dxe $@ + +$(OBJDIR)/%.o: %.c | $(OBJDIR) + $(CC) $(CFLAGS) -c -o $@ $< + +$(OBJDIR): + mkdir -p $(OBJDIR) + +$(LIBSDIR): + mkdir -p $(LIBSDIR) + +# Dependencies +$(OBJDIR)/shellTaskMgr.o: shellTaskMgr.c shellTaskMgr.h ../shell/shellApp.h ../core/dvxWidget.h ../core/dvxApp.h + +clean: + rm -f $(OBJS) $(TARGET) $(LIBSDIR)/taskmgr.dep diff --git a/shell/shellTaskMgr.c b/taskmgr/shellTaskMgr.c similarity index 93% rename from shell/shellTaskMgr.c rename to taskmgr/shellTaskMgr.c index c573950..2f320ce 100644 --- a/shell/shellTaskMgr.c +++ b/taskmgr/shellTaskMgr.c @@ -5,7 +5,7 @@ // all running apps with Switch To, End Task, and Run buttons. #include "shellTaskMgr.h" -#include "shellApp.h" +#include "../shell/shellApp.h" #include "dvxDialog.h" #include "dvxWidget.h" #include "widgetBox.h" @@ -329,8 +329,9 @@ void shellTaskMgrOpen(AppContextT *ctx) { tmCols[4].align = ListViewAlignLeftE; sTmListView = wgtListView(root); - sTmListView->weight = 100; - sTmListView->prefH = wgtPixels(TM_LIST_PREF_H); + sTmListView->weight = 100; + sTmListView->prefH = wgtPixels(TM_LIST_PREF_H); + sTmListView->onDblClick = onTmSwitchTo; wgtListViewSetColumns(sTmListView, tmCols, TM_COL_COUNT); WidgetT *btnRow = wgtHBox(root); @@ -339,15 +340,15 @@ void shellTaskMgrOpen(AppContextT *ctx) { sTmStatusLbl = wgtLabel(btnRow, ""); sTmStatusLbl->weight = 100; - WidgetT *switchBtn = wgtButton(btnRow, "Switch To"); + WidgetT *switchBtn = wgtButton(btnRow, "&Switch To"); switchBtn->onClick = onTmSwitchTo; switchBtn->prefW = wgtPixels(TM_BTN_W); - WidgetT *endBtn = wgtButton(btnRow, "End Task"); + WidgetT *endBtn = wgtButton(btnRow, "&End Task"); endBtn->onClick = onTmEndTask; endBtn->prefW = wgtPixels(TM_BTN_W); - WidgetT *runBtn = wgtButton(btnRow, "Run..."); + WidgetT *runBtn = wgtButton(btnRow, "&Run..."); runBtn->onClick = onTmRun; runBtn->prefW = wgtPixels(TM_BTN_W); @@ -368,3 +369,13 @@ void shellTaskMgrRefresh(void) { updateStatusText(); } } + + +// ============================================================ +// DXE constructor -- register Ctrl+Esc handler with the shell +// ============================================================ + +static void taskmgrInit(void) __attribute__((constructor)); +static void taskmgrInit(void) { + shellCtrlEscFn = shellTaskMgrOpen; +} diff --git a/shell/shellTaskMgr.h b/taskmgr/shellTaskMgr.h similarity index 100% rename from shell/shellTaskMgr.h rename to taskmgr/shellTaskMgr.h diff --git a/texthelp/textHelp.c b/texthelp/textHelp.c index 405ff0e..2827fd8 100644 --- a/texthelp/textHelp.c +++ b/texthelp/textHelp.c @@ -114,11 +114,7 @@ void clearOtherSelections(WidgetT *except) { static bool clearSelectionOnWidget(WidgetT *w) { - if (w->wclass && w->wclass->clearSelection) { - return w->wclass->clearSelection(w); - } - - return false; + return wclsClearSelection(w); } diff --git a/widgets/widgetAnsiTerm.c b/widgets/widgetAnsiTerm.c index 55d6021..5a40d0f 100644 --- a/widgets/widgetAnsiTerm.c +++ b/widgets/widgetAnsiTerm.c @@ -960,20 +960,19 @@ static void widgetAnsiTermOnDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, in static const WidgetClassT sClassAnsiTerm = { - .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE | WCLASS_NEEDS_POLL | WCLASS_SWALLOWS_TAB, - .paint = widgetAnsiTermPaint, - .paintOverlay = NULL, - .calcMinSize = widgetAnsiTermCalcMinSize, - .layout = NULL, - .onMouse = widgetAnsiTermOnMouse, - .onKey = widgetAnsiTermOnKey, - .destroy = widgetAnsiTermDestroy, - .getText = NULL, - .setText = NULL, - .clearSelection = widgetAnsiTermClearSelection, - .onDragUpdate = widgetAnsiTermOnDragUpdate, - .poll = widgetAnsiTermPollVtable, - .quickRepaint = wgtAnsiTermRepaint + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE | WCLASS_NEEDS_POLL | WCLASS_SWALLOWS_TAB, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetAnsiTermPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetAnsiTermCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetAnsiTermOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetAnsiTermOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetAnsiTermDestroy, + [WGT_METHOD_CLEAR_SELECTION] = (void *)widgetAnsiTermClearSelection, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetAnsiTermOnDragUpdate, + [WGT_METHOD_POLL] = (void *)widgetAnsiTermPollVtable, + [WGT_METHOD_QUICK_REPAINT] = (void *)wgtAnsiTermRepaint, + } }; diff --git a/widgets/widgetBox.c b/widgets/widgetBox.c index 85709db..e89b9da 100644 --- a/widgets/widgetBox.c +++ b/widgets/widgetBox.c @@ -140,43 +140,23 @@ void widgetFrameDestroy(WidgetT *w) { static const WidgetClassT sClassVBox = { - .flags = WCLASS_BOX_CONTAINER, - .paint = NULL, - .paintOverlay = NULL, - .calcMinSize = NULL, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = NULL, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = WCLASS_BOX_CONTAINER, }; static const WidgetClassT sClassHBox = { - .flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER, - .paint = NULL, - .paintOverlay = NULL, - .calcMinSize = NULL, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = NULL, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER, }; static const WidgetClassT sClassFrame = { - .flags = WCLASS_BOX_CONTAINER | WCLASS_FOCUS_FORWARD, - .paint = widgetFramePaint, - .paintOverlay = NULL, - .calcMinSize = NULL, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = widgetFrameDestroy, - .getText = NULL, - .setText = NULL, - .getLayoutMetrics = widgetFrameGetLayoutMetrics + .version = WGT_CLASS_VERSION, + .flags = WCLASS_BOX_CONTAINER | WCLASS_FOCUS_FORWARD, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetFramePaint, + [WGT_METHOD_DESTROY] = (void *)widgetFrameDestroy, + [WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetFrameGetLayoutMetrics, + } }; // ============================================================ diff --git a/widgets/widgetButton.c b/widgets/widgetButton.c index 461fc5c..6402711 100644 --- a/widgets/widgetButton.c +++ b/widgets/widgetButton.c @@ -215,19 +215,20 @@ void widgetButtonSetText(WidgetT *w, const char *text) { static const WidgetClassT sClassButton = { - .flags = WCLASS_FOCUSABLE | WCLASS_PRESS_RELEASE, - .paint = widgetButtonPaint, - .paintOverlay = NULL, - .calcMinSize = widgetButtonCalcMinSize, - .layout = NULL, - .onMouse = widgetButtonOnMouse, - .onKey = widgetButtonOnKey, - .onAccelActivate = widgetButtonAccelActivate, - .destroy = widgetButtonDestroy, - .getText = widgetButtonGetText, - .setText = widgetButtonSetText, - .onDragUpdate = widgetButtonOnDragUpdate, - .onDragEnd = widgetButtonOnDragEnd + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_PRESS_RELEASE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetButtonPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetButtonCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetButtonOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetButtonOnKey, + [WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetButtonAccelActivate, + [WGT_METHOD_DESTROY] = (void *)widgetButtonDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetButtonGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetButtonSetText, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetButtonOnDragUpdate, + [WGT_METHOD_ON_DRAG_END] = (void *)widgetButtonOnDragEnd, + } }; // ============================================================ diff --git a/widgets/widgetCanvas.c b/widgets/widgetCanvas.c index 516615b..e3137cd 100644 --- a/widgets/widgetCanvas.c +++ b/widgets/widgetCanvas.c @@ -657,17 +657,15 @@ void widgetCanvasPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitma // ============================================================ static const WidgetClassT sClassCanvas = { - .flags = 0, - .paint = widgetCanvasPaint, - .paintOverlay = NULL, - .calcMinSize = widgetCanvasCalcMinSize, - .layout = NULL, - .onMouse = widgetCanvasOnMouse, - .onDragUpdate = widgetCanvasOnDragUpdate, - .onKey = NULL, - .destroy = widgetCanvasDestroy, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = 0, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetCanvasPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCanvasCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetCanvasOnMouse, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetCanvasOnDragUpdate, + [WGT_METHOD_DESTROY] = (void *)widgetCanvasDestroy, + } }; diff --git a/widgets/widgetCheckbox.c b/widgets/widgetCheckbox.c index b9ab49d..f3b9e2b 100644 --- a/widgets/widgetCheckbox.c +++ b/widgets/widgetCheckbox.c @@ -186,17 +186,18 @@ void widgetCheckboxSetText(WidgetT *w, const char *text) { static const WidgetClassT sClassCheckbox = { - .flags = WCLASS_FOCUSABLE, - .paint = widgetCheckboxPaint, - .paintOverlay = NULL, - .calcMinSize = widgetCheckboxCalcMinSize, - .layout = NULL, - .onMouse = widgetCheckboxOnMouse, - .onKey = widgetCheckboxOnKey, - .onAccelActivate = widgetCheckboxAccelActivate, - .destroy = widgetCheckboxDestroy, - .getText = widgetCheckboxGetText, - .setText = widgetCheckboxSetText + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetCheckboxPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCheckboxCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetCheckboxOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetCheckboxOnKey, + [WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetCheckboxAccelActivate, + [WGT_METHOD_DESTROY] = (void *)widgetCheckboxDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetCheckboxGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetCheckboxSetText, + } }; // ============================================================ diff --git a/widgets/widgetComboBox.c b/widgets/widgetComboBox.c index 6506701..b2add7d 100644 --- a/widgets/widgetComboBox.c +++ b/widgets/widgetComboBox.c @@ -415,21 +415,23 @@ static void widgetComboBoxOnDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, in static const WidgetClassT sClassComboBox = { - .flags = WCLASS_FOCUSABLE | WCLASS_HAS_POPUP | WCLASS_SCROLLABLE, - .paint = widgetComboBoxPaint, - .paintOverlay = widgetComboBoxPaintPopup, - .calcMinSize = widgetComboBoxCalcMinSize, - .layout = NULL, - .onMouse = widgetComboBoxOnMouse, - .onKey = widgetComboBoxOnKey, - .onAccelActivate = widgetComboBoxAccelActivate, - .destroy = widgetComboBoxDestroy, - .getText = widgetComboBoxGetText, - .setText = widgetComboBoxSetText, - .closePopup = widgetComboBoxClosePopup, - .clearSelection = widgetComboBoxClearSelection, - .onDragUpdate = widgetComboBoxOnDragUpdate, - .getPopupRect = widgetComboBoxGetPopupRect + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_HAS_POPUP | WCLASS_SCROLLABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetComboBoxPaint, + [WGT_METHOD_PAINT_OVERLAY] = (void *)widgetComboBoxPaintPopup, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetComboBoxCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetComboBoxOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetComboBoxOnKey, + [WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetComboBoxAccelActivate, + [WGT_METHOD_DESTROY] = (void *)widgetComboBoxDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetComboBoxGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetComboBoxSetText, + [WGT_METHOD_CLOSE_POPUP] = (void *)widgetComboBoxClosePopup, + [WGT_METHOD_CLEAR_SELECTION] = (void *)widgetComboBoxClearSelection, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetComboBoxOnDragUpdate, + [WGT_METHOD_GET_POPUP_RECT] = (void *)widgetComboBoxGetPopupRect, + } }; diff --git a/widgets/widgetDropdown.c b/widgets/widgetDropdown.c index e3a8e44..07344a9 100644 --- a/widgets/widgetDropdown.c +++ b/widgets/widgetDropdown.c @@ -309,19 +309,20 @@ static void widgetDropdownGetPopupRect(const WidgetT *w, const BitmapFontT *font static const WidgetClassT sClassDropdown = { - .flags = WCLASS_FOCUSABLE | WCLASS_HAS_POPUP | WCLASS_SCROLLABLE, - .paint = widgetDropdownPaint, - .paintOverlay = widgetDropdownPaintPopup, - .calcMinSize = widgetDropdownCalcMinSize, - .layout = NULL, - .onMouse = widgetDropdownOnMouse, - .onKey = widgetDropdownOnKey, - .onAccelActivate = widgetDropdownAccelActivate, - .destroy = widgetDropdownDestroy, - .getText = widgetDropdownGetText, - .setText = NULL, - .closePopup = widgetDropdownClosePopup, - .getPopupRect = widgetDropdownGetPopupRect + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_HAS_POPUP | WCLASS_SCROLLABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetDropdownPaint, + [WGT_METHOD_PAINT_OVERLAY] = (void *)widgetDropdownPaintPopup, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetDropdownCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetDropdownOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetDropdownOnKey, + [WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetDropdownAccelActivate, + [WGT_METHOD_DESTROY] = (void *)widgetDropdownDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetDropdownGetText, + [WGT_METHOD_CLOSE_POPUP] = (void *)widgetDropdownClosePopup, + [WGT_METHOD_GET_POPUP_RECT] = (void *)widgetDropdownGetPopupRect, + } }; // ============================================================ diff --git a/widgets/widgetImage.c b/widgets/widgetImage.c index 97fd60c..f920a42 100644 --- a/widgets/widgetImage.c +++ b/widgets/widgetImage.c @@ -117,16 +117,14 @@ void widgetImagePaint(WidgetT *w, DisplayT *disp, const BlitOpsT *ops, const Bit // ============================================================ static const WidgetClassT sClassImage = { - .flags = 0, - .paint = widgetImagePaint, - .paintOverlay = NULL, - .calcMinSize = widgetImageCalcMinSize, - .layout = NULL, - .onMouse = widgetImageOnMouse, - .onKey = NULL, - .destroy = widgetImageDestroy, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = 0, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetImagePaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetImageCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetImageOnMouse, + [WGT_METHOD_DESTROY] = (void *)widgetImageDestroy, + } }; diff --git a/widgets/widgetImageButton.c b/widgets/widgetImageButton.c index d855be3..321f01b 100644 --- a/widgets/widgetImageButton.c +++ b/widgets/widgetImageButton.c @@ -181,19 +181,18 @@ static void widgetImageButtonOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, // ============================================================ static const WidgetClassT sClassImageButton = { - .flags = WCLASS_FOCUSABLE | WCLASS_PRESS_RELEASE, - .paint = widgetImageButtonPaint, - .paintOverlay = NULL, - .calcMinSize = widgetImageButtonCalcMinSize, - .layout = NULL, - .onMouse = widgetImageButtonOnMouse, - .onKey = widgetImageButtonOnKey, - .onAccelActivate = widgetImageButtonAccelActivate, - .destroy = widgetImageButtonDestroy, - .getText = NULL, - .setText = NULL, - .onDragUpdate = widgetImageButtonOnDragUpdate, - .onDragEnd = widgetImageButtonOnDragEnd + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_PRESS_RELEASE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetImageButtonPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetImageButtonCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetImageButtonOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetImageButtonOnKey, + [WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetImageButtonAccelActivate, + [WGT_METHOD_DESTROY] = (void *)widgetImageButtonDestroy, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetImageButtonOnDragUpdate, + [WGT_METHOD_ON_DRAG_END] = (void *)widgetImageButtonOnDragEnd, + } }; diff --git a/widgets/widgetLabel.c b/widgets/widgetLabel.c index 99cad7a..6a00de0 100644 --- a/widgets/widgetLabel.c +++ b/widgets/widgetLabel.c @@ -109,16 +109,15 @@ void widgetLabelSetText(WidgetT *w, const char *text) { static const WidgetClassT sClassLabel = { - .flags = WCLASS_FOCUS_FORWARD, - .paint = widgetLabelPaint, - .paintOverlay = NULL, - .calcMinSize = widgetLabelCalcMinSize, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = widgetLabelDestroy, - .getText = widgetLabelGetText, - .setText = widgetLabelSetText + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUS_FORWARD, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetLabelPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetLabelCalcMinSize, + [WGT_METHOD_DESTROY] = (void *)widgetLabelDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetLabelGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetLabelSetText, + } }; // ============================================================ diff --git a/widgets/widgetListBox.c b/widgets/widgetListBox.c index e22b7fb..8b14377 100644 --- a/widgets/widgetListBox.c +++ b/widgets/widgetListBox.c @@ -623,18 +623,17 @@ static void widgetListBoxOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int3 static const WidgetClassT sClassListBox = { - .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, - .paint = widgetListBoxPaint, - .paintOverlay = NULL, - .calcMinSize = widgetListBoxCalcMinSize, - .layout = NULL, - .onMouse = widgetListBoxOnMouse, - .onKey = widgetListBoxOnKey, - .destroy = widgetListBoxDestroy, - .getText = NULL, - .setText = NULL, - .onDragUpdate = widgetListBoxOnDragUpdate, - .onDragEnd = widgetListBoxOnDragEnd + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetListBoxPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetListBoxCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetListBoxOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetListBoxOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetListBoxDestroy, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetListBoxOnDragUpdate, + [WGT_METHOD_ON_DRAG_END] = (void *)widgetListBoxOnDragEnd, + } }; // ============================================================ diff --git a/widgets/widgetListView.c b/widgets/widgetListView.c index d7e2347..5368ec4 100644 --- a/widgets/widgetListView.c +++ b/widgets/widgetListView.c @@ -1460,18 +1460,29 @@ static void widgetListViewReorderDrop(WidgetT *w) { moving[c] = lv->cellData[from * cols + c]; } + // Save the moving row's selection bit + uint8_t movingSel = (lv->selBits && from < lv->rowCount) ? lv->selBits[from] : 0; + if (to > from) { // Moving down: shift rows up for (int32_t r = from; r < to - 1; r++) { for (int32_t c = 0; c < cols; c++) { ((const char **)lv->cellData)[r * cols + c] = lv->cellData[(r + 1) * cols + c]; } + + if (lv->selBits) { + lv->selBits[r] = lv->selBits[r + 1]; + } } for (int32_t c = 0; c < cols; c++) { ((const char **)lv->cellData)[(to - 1) * cols + c] = moving[c]; } + if (lv->selBits) { + lv->selBits[to - 1] = movingSel; + } + lv->selectedIdx = to - 1; } else { // Moving up: shift rows down @@ -1479,12 +1490,20 @@ static void widgetListViewReorderDrop(WidgetT *w) { for (int32_t c = 0; c < cols; c++) { ((const char **)lv->cellData)[r * cols + c] = lv->cellData[(r - 1) * cols + c]; } + + if (lv->selBits) { + lv->selBits[r] = lv->selBits[r - 1]; + } } for (int32_t c = 0; c < cols; c++) { ((const char **)lv->cellData)[to * cols + c] = moving[c]; } + if (lv->selBits) { + lv->selBits[to] = movingSel; + } + lv->selectedIdx = to; } @@ -1534,19 +1553,18 @@ static void widgetListViewOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int static const WidgetClassT sClassListView = { - .flags = WCLASS_FOCUSABLE | WCLASS_NO_HIT_RECURSE | WCLASS_SCROLLABLE, - .paint = widgetListViewPaint, - .paintOverlay = NULL, - .calcMinSize = widgetListViewCalcMinSize, - .layout = NULL, - .onMouse = widgetListViewOnMouse, - .onKey = widgetListViewOnKey, - .destroy = widgetListViewDestroy, - .getText = NULL, - .setText = NULL, - .getCursorShape = widgetListViewGetCursorShape, - .onDragUpdate = widgetListViewOnDragUpdate, - .onDragEnd = widgetListViewOnDragEnd + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_NO_HIT_RECURSE | WCLASS_SCROLLABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetListViewPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetListViewCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetListViewOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetListViewOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetListViewDestroy, + [WGT_METHOD_GET_CURSOR_SHAPE] = (void *)widgetListViewGetCursorShape, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetListViewOnDragUpdate, + [WGT_METHOD_ON_DRAG_END] = (void *)widgetListViewOnDragEnd, + } }; diff --git a/widgets/widgetProgressBar.c b/widgets/widgetProgressBar.c index 477b0a6..b9f9194 100644 --- a/widgets/widgetProgressBar.c +++ b/widgets/widgetProgressBar.c @@ -122,16 +122,13 @@ void widgetProgressBarDestroy(WidgetT *w) { // ============================================================ static const WidgetClassT sClassProgressBar = { - .flags = 0, - .paint = widgetProgressBarPaint, - .paintOverlay = NULL, - .calcMinSize = widgetProgressBarCalcMinSize, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = widgetProgressBarDestroy, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = 0, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetProgressBarPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetProgressBarCalcMinSize, + [WGT_METHOD_DESTROY] = (void *)widgetProgressBarDestroy, + } }; diff --git a/widgets/widgetRadio.c b/widgets/widgetRadio.c index e9fd7fc..6564a1d 100644 --- a/widgets/widgetRadio.c +++ b/widgets/widgetRadio.c @@ -313,30 +313,26 @@ void widgetRadioSetText(WidgetT *w, const char *text) { static const WidgetClassT sClassRadioGroup = { - .flags = WCLASS_BOX_CONTAINER, - .paint = NULL, - .paintOverlay = NULL, - .calcMinSize = NULL, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = widgetRadioGroupDestroy, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = WCLASS_BOX_CONTAINER, + .handlers = { + [WGT_METHOD_DESTROY] = (void *)widgetRadioGroupDestroy, + } }; static const WidgetClassT sClassRadio = { - .flags = WCLASS_FOCUSABLE, - .paint = widgetRadioPaint, - .paintOverlay = NULL, - .calcMinSize = widgetRadioCalcMinSize, - .layout = NULL, - .onMouse = widgetRadioOnMouse, - .onKey = widgetRadioOnKey, - .onAccelActivate = widgetRadioAccelActivate, - .destroy = widgetRadioDestroy, - .getText = widgetRadioGetText, - .setText = widgetRadioSetText + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetRadioPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetRadioCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetRadioOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetRadioOnKey, + [WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetRadioAccelActivate, + [WGT_METHOD_DESTROY] = (void *)widgetRadioDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetRadioGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetRadioSetText, + } }; // ============================================================ diff --git a/widgets/widgetScrollPane.c b/widgets/widgetScrollPane.c index 29843fe..c96c8b9 100644 --- a/widgets/widgetScrollPane.c +++ b/widgets/widgetScrollPane.c @@ -608,13 +608,13 @@ void widgetScrollPaneOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy } } - if (child && child->enabled && child->wclass && child->wclass->onMouse) { + if (child && child->enabled && wclsHas(child, WGT_METHOD_ON_MOUSE)) { // Clear old focus if (sFocusedWidget && sFocusedWidget != child) { sFocusedWidget->focused = false; } - child->wclass->onMouse(child, root, vx, vy); + wclsOnMouse(child, root, vx, vy); if (child->focused) { sFocusedWidget = child; @@ -776,18 +776,18 @@ void widgetScrollPanePaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const B // ============================================================ static const WidgetClassT sClassScrollPane = { - .flags = WCLASS_PAINTS_CHILDREN | WCLASS_NO_HIT_RECURSE | WCLASS_SCROLL_CONTAINER | WCLASS_RELAYOUT_ON_SCROLL, - .paint = widgetScrollPanePaint, - .paintOverlay = NULL, - .calcMinSize = widgetScrollPaneCalcMinSize, - .layout = widgetScrollPaneLayout, - .onMouse = widgetScrollPaneOnMouse, - .onKey = widgetScrollPaneOnKey, - .destroy = widgetScrollPaneDestroy, - .getText = NULL, - .setText = NULL, - .scrollChildIntoView = wgtScrollPaneScrollToChild, - .onDragUpdate = widgetScrollPaneOnDragUpdate + .version = WGT_CLASS_VERSION, + .flags = WCLASS_PAINTS_CHILDREN | WCLASS_NO_HIT_RECURSE | WCLASS_SCROLL_CONTAINER | WCLASS_RELAYOUT_ON_SCROLL, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetScrollPanePaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetScrollPaneCalcMinSize, + [WGT_METHOD_LAYOUT] = (void *)widgetScrollPaneLayout, + [WGT_METHOD_ON_MOUSE] = (void *)widgetScrollPaneOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetScrollPaneOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetScrollPaneDestroy, + [WGT_METHOD_SCROLL_CHILD_INTO_VIEW] = (void *)wgtScrollPaneScrollToChild, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetScrollPaneOnDragUpdate, + } }; diff --git a/widgets/widgetSeparator.c b/widgets/widgetSeparator.c index 2debfd3..e3fb483 100644 --- a/widgets/widgetSeparator.c +++ b/widgets/widgetSeparator.c @@ -90,16 +90,13 @@ void widgetSeparatorPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bi static const WidgetClassT sClassSeparator = { - .flags = 0, - .paint = widgetSeparatorPaint, - .paintOverlay = NULL, - .calcMinSize = widgetSeparatorCalcMinSize, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = widgetSeparatorDestroy, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = 0, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetSeparatorPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetSeparatorCalcMinSize, + [WGT_METHOD_DESTROY] = (void *)widgetSeparatorDestroy, + } }; // ============================================================ diff --git a/widgets/widgetSlider.c b/widgets/widgetSlider.c index e57e033..bb0f4ca 100644 --- a/widgets/widgetSlider.c +++ b/widgets/widgetSlider.c @@ -320,17 +320,16 @@ static void widgetSliderDestroy(WidgetT *w) { static const WidgetClassT sClassSlider = { - .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, - .paint = widgetSliderPaint, - .paintOverlay = NULL, - .calcMinSize = widgetSliderCalcMinSize, - .layout = NULL, - .onMouse = widgetSliderOnMouse, - .onKey = widgetSliderOnKey, - .destroy = widgetSliderDestroy, - .getText = NULL, - .setText = NULL, - .onDragUpdate = widgetSliderOnDragUpdate + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetSliderPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetSliderCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetSliderOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetSliderOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetSliderDestroy, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetSliderOnDragUpdate, + } }; // ============================================================ diff --git a/widgets/widgetSpacer.c b/widgets/widgetSpacer.c index d268a8a..f55f04b 100644 --- a/widgets/widgetSpacer.c +++ b/widgets/widgetSpacer.c @@ -35,16 +35,11 @@ void widgetSpacerCalcMinSize(WidgetT *w, const BitmapFontT *font) { static const WidgetClassT sClassSpacer = { - .flags = 0, - .paint = NULL, - .paintOverlay = NULL, - .calcMinSize = widgetSpacerCalcMinSize, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = NULL, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = 0, + .handlers = { + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetSpacerCalcMinSize, + } }; // ============================================================ diff --git a/widgets/widgetSpinner.c b/widgets/widgetSpinner.c index fcf6999..2cfdb56 100644 --- a/widgets/widgetSpinner.c +++ b/widgets/widgetSpinner.c @@ -489,16 +489,17 @@ void widgetSpinnerDestroy(WidgetT *w) { // ============================================================ static const WidgetClassT sClassSpinner = { - .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, - .paint = widgetSpinnerPaint, - .paintOverlay = NULL, - .calcMinSize = widgetSpinnerCalcMinSize, - .layout = NULL, - .onMouse = widgetSpinnerOnMouse, - .onKey = widgetSpinnerOnKey, - .destroy = widgetSpinnerDestroy, - .getText = widgetSpinnerGetText, - .setText = widgetSpinnerSetText + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetSpinnerPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetSpinnerCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetSpinnerOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetSpinnerOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetSpinnerDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetSpinnerGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetSpinnerSetText, + } }; diff --git a/widgets/widgetSplitter.c b/widgets/widgetSplitter.c index 1a68f6a..3b3f792 100644 --- a/widgets/widgetSplitter.c +++ b/widgets/widgetSplitter.c @@ -271,12 +271,12 @@ void widgetSplitterOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) } } - if (child && child->enabled && child->wclass && child->wclass->onMouse) { + if (child && child->enabled && wclsHas(child, WGT_METHOD_ON_MOUSE)) { if (sFocusedWidget && sFocusedWidget != child) { sFocusedWidget->focused = false; } - child->wclass->onMouse(child, root, vx, vy); + wclsOnMouse(child, root, vx, vy); if (child->focused) { sFocusedWidget = child; @@ -406,8 +406,8 @@ int32_t widgetSplitterGetCursorShape(const WidgetT *w, int32_t vx, int32_t vy) { for (WidgetT *c = w->firstChild; c; c = c->nextSibling) { WidgetT *child = widgetHitTest(c, vx, vy); - if (child && child->wclass && child->wclass->getCursorShape) { - int32_t shape = child->wclass->getCursorShape(child, vx, vy); + if (child) { + int32_t shape = wclsGetCursorShape(child, vx, vy); if (shape > 0) { return shape; @@ -462,18 +462,17 @@ static void widgetSplitterOnDragUpdate(WidgetT *w, WidgetT *root, int32_t mouseX // ============================================================ static const WidgetClassT sClassSplitter = { - .flags = WCLASS_PAINTS_CHILDREN | WCLASS_NO_HIT_RECURSE, - .paint = widgetSplitterPaint, - .paintOverlay = NULL, - .calcMinSize = widgetSplitterCalcMinSize, - .layout = widgetSplitterLayout, - .onMouse = widgetSplitterOnMouse, - .onKey = NULL, - .destroy = widgetSplitterDestroy, - .getText = NULL, - .setText = NULL, - .getCursorShape = widgetSplitterGetCursorShape, - .onDragUpdate = widgetSplitterOnDragUpdate + .version = WGT_CLASS_VERSION, + .flags = WCLASS_PAINTS_CHILDREN | WCLASS_NO_HIT_RECURSE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetSplitterPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetSplitterCalcMinSize, + [WGT_METHOD_LAYOUT] = (void *)widgetSplitterLayout, + [WGT_METHOD_ON_MOUSE] = (void *)widgetSplitterOnMouse, + [WGT_METHOD_DESTROY] = (void *)widgetSplitterDestroy, + [WGT_METHOD_GET_CURSOR_SHAPE] = (void *)widgetSplitterGetCursorShape, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetSplitterOnDragUpdate, + } }; diff --git a/widgets/widgetStatusBar.c b/widgets/widgetStatusBar.c index 9ffccd4..2148752 100644 --- a/widgets/widgetStatusBar.c +++ b/widgets/widgetStatusBar.c @@ -71,17 +71,12 @@ void widgetStatusBarGetLayoutMetrics(const WidgetT *w, const BitmapFontT *font, static const WidgetClassT sClassStatusBar = { - .flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER, - .paint = widgetStatusBarPaint, - .paintOverlay = NULL, - .calcMinSize = NULL, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = NULL, - .getText = NULL, - .setText = NULL, - .getLayoutMetrics = widgetStatusBarGetLayoutMetrics + .version = WGT_CLASS_VERSION, + .flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetStatusBarPaint, + [WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetStatusBarGetLayoutMetrics, + } }; // ============================================================ diff --git a/widgets/widgetTabControl.c b/widgets/widgetTabControl.c index d254322..666ebd7 100644 --- a/widgets/widgetTabControl.c +++ b/widgets/widgetTabControl.c @@ -68,10 +68,7 @@ static bool tabNeedScroll(const WidgetT *w, const BitmapFontT *font); static void tabClosePopup(void) { if (sOpenPopup) { - if (sOpenPopup->wclass && sOpenPopup->wclass->closePopup) { - sOpenPopup->wclass->closePopup(sOpenPopup); - } - + wclsClosePopup(sOpenPopup); sOpenPopup = NULL; } } @@ -585,30 +582,25 @@ void widgetTabPageDestroy(WidgetT *w) { static const WidgetClassT sClassTabControl = { - .flags = WCLASS_FOCUSABLE | WCLASS_PAINTS_CHILDREN, - .paint = widgetTabControlPaint, - .paintOverlay = NULL, - .calcMinSize = widgetTabControlCalcMinSize, - .layout = widgetTabControlLayout, - .onMouse = widgetTabControlOnMouse, - .onKey = widgetTabControlOnKey, - .destroy = widgetTabControlDestroy, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_PAINTS_CHILDREN, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetTabControlPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetTabControlCalcMinSize, + [WGT_METHOD_LAYOUT] = (void *)widgetTabControlLayout, + [WGT_METHOD_ON_MOUSE] = (void *)widgetTabControlOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetTabControlOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetTabControlDestroy, + } }; static const WidgetClassT sClassTabPage = { - .flags = WCLASS_BOX_CONTAINER | WCLASS_ACCEL_WHEN_HIDDEN, - .paint = NULL, - .paintOverlay = NULL, - .calcMinSize = NULL, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .onAccelActivate = widgetTabPageAccelActivate, - .destroy = widgetTabPageDestroy, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = WCLASS_BOX_CONTAINER | WCLASS_ACCEL_WHEN_HIDDEN, + .handlers = { + [WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetTabPageAccelActivate, + [WGT_METHOD_DESTROY] = (void *)widgetTabPageDestroy, + } }; diff --git a/widgets/widgetTextInput.c b/widgets/widgetTextInput.c index 42004f4..be5f374 100644 --- a/widgets/widgetTextInput.c +++ b/widgets/widgetTextInput.c @@ -2045,18 +2045,19 @@ static void widgetTextInputOnDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, i static const WidgetClassT sClassTextInput = { - .flags = WCLASS_FOCUSABLE, - .paint = widgetTextInputPaint, - .paintOverlay = NULL, - .calcMinSize = widgetTextInputCalcMinSize, - .layout = NULL, - .onMouse = widgetTextInputOnMouse, - .onKey = widgetTextInputOnKey, - .destroy = widgetTextInputDestroy, - .getText = widgetTextInputGetText, - .setText = widgetTextInputSetText, - .clearSelection = widgetTextInputClearSelection, - .onDragUpdate = widgetTextInputOnDragUpdate + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetTextInputPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetTextInputCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetTextInputOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetTextInputOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetTextInputDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetTextInputGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetTextInputSetText, + [WGT_METHOD_CLEAR_SELECTION] = (void *)widgetTextInputClearSelection, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetTextInputOnDragUpdate, + } }; // ============================================================ @@ -2201,18 +2202,19 @@ static void widgetTextAreaDragSelect(WidgetT *w, WidgetT *root, int32_t vx, int3 static const WidgetClassT sClassTextArea = { - .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, - .paint = widgetTextAreaPaint, - .paintOverlay = NULL, - .calcMinSize = widgetTextAreaCalcMinSize, - .layout = NULL, - .onMouse = widgetTextAreaOnMouse, - .onKey = widgetTextAreaOnKey, - .destroy = widgetTextAreaDestroy, - .getText = widgetTextAreaGetText, - .setText = widgetTextAreaSetText, - .clearSelection = widgetTextAreaClearSelection, - .onDragUpdate = widgetTextAreaOnDragUpdate + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetTextAreaPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetTextAreaCalcMinSize, + [WGT_METHOD_ON_MOUSE] = (void *)widgetTextAreaOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetTextAreaOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetTextAreaDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetTextAreaGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetTextAreaSetText, + [WGT_METHOD_CLEAR_SELECTION] = (void *)widgetTextAreaClearSelection, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetTextAreaOnDragUpdate, + } }; // ============================================================ diff --git a/widgets/widgetTimer.c b/widgets/widgetTimer.c index 88c575a..5431e97 100644 --- a/widgets/widgetTimer.c +++ b/widgets/widgetTimer.c @@ -94,16 +94,12 @@ static void widgetTimerDestroy(WidgetT *w) { // ============================================================ static const WidgetClassT sClassTimer = { - .flags = 0, - .paint = NULL, - .paintOverlay = NULL, - .calcMinSize = widgetTimerCalcMinSize, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = widgetTimerDestroy, - .getText = NULL, - .setText = NULL + .version = WGT_CLASS_VERSION, + .flags = 0, + .handlers = { + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetTimerCalcMinSize, + [WGT_METHOD_DESTROY] = (void *)widgetTimerDestroy, + } }; diff --git a/widgets/widgetToolbar.c b/widgets/widgetToolbar.c index 9e5951b..ee01c5b 100644 --- a/widgets/widgetToolbar.c +++ b/widgets/widgetToolbar.c @@ -63,17 +63,12 @@ void widgetToolbarGetLayoutMetrics(const WidgetT *w, const BitmapFontT *font, in // ============================================================ static const WidgetClassT sClassToolbar = { - .flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER, - .paint = widgetToolbarPaint, - .paintOverlay = NULL, - .calcMinSize = NULL, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = NULL, - .getText = NULL, - .setText = NULL, - .getLayoutMetrics = widgetToolbarGetLayoutMetrics + .version = WGT_CLASS_VERSION, + .flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetToolbarPaint, + [WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetToolbarGetLayoutMetrics, + } }; diff --git a/widgets/widgetTreeView.c b/widgets/widgetTreeView.c index 0f80c18..11dacb9 100644 --- a/widgets/widgetTreeView.c +++ b/widgets/widgetTreeView.c @@ -1520,32 +1520,29 @@ static void widgetTreeViewOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int static const WidgetClassT sClassTreeView = { - .flags = WCLASS_FOCUSABLE | WCLASS_PAINTS_CHILDREN | WCLASS_NO_HIT_RECURSE | WCLASS_SCROLLABLE, - .paint = widgetTreeViewPaint, - .paintOverlay = NULL, - .calcMinSize = widgetTreeViewCalcMinSize, - .layout = widgetTreeViewLayout, - .onMouse = widgetTreeViewOnMouse, - .onKey = widgetTreeViewOnKey, - .destroy = widgetTreeViewDestroy, - .getText = NULL, - .setText = NULL, - .onChildChanged = widgetTreeViewOnChildChanged, - .onDragUpdate = widgetTreeViewOnDragUpdate, - .onDragEnd = widgetTreeViewOnDragEnd + .version = WGT_CLASS_VERSION, + .flags = WCLASS_FOCUSABLE | WCLASS_PAINTS_CHILDREN | WCLASS_NO_HIT_RECURSE | WCLASS_SCROLLABLE, + .handlers = { + [WGT_METHOD_PAINT] = (void *)widgetTreeViewPaint, + [WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetTreeViewCalcMinSize, + [WGT_METHOD_LAYOUT] = (void *)widgetTreeViewLayout, + [WGT_METHOD_ON_MOUSE] = (void *)widgetTreeViewOnMouse, + [WGT_METHOD_ON_KEY] = (void *)widgetTreeViewOnKey, + [WGT_METHOD_DESTROY] = (void *)widgetTreeViewDestroy, + [WGT_METHOD_ON_CHILD_CHANGED] = (void *)widgetTreeViewOnChildChanged, + [WGT_METHOD_ON_DRAG_UPDATE] = (void *)widgetTreeViewOnDragUpdate, + [WGT_METHOD_ON_DRAG_END] = (void *)widgetTreeViewOnDragEnd, + } }; static const WidgetClassT sClassTreeItem = { - .flags = 0, - .paint = NULL, - .paintOverlay = NULL, - .calcMinSize = NULL, - .layout = NULL, - .onMouse = NULL, - .onKey = NULL, - .destroy = widgetTreeItemDestroy, - .getText = widgetTreeItemGetText, - .setText = widgetTreeItemSetText + .version = WGT_CLASS_VERSION, + .flags = 0, + .handlers = { + [WGT_METHOD_DESTROY] = (void *)widgetTreeItemDestroy, + [WGT_METHOD_GET_TEXT] = (void *)widgetTreeItemGetText, + [WGT_METHOD_SET_TEXT] = (void *)widgetTreeItemSetText, + } };