From 8886cee9335067c58963d6b182e6ad84a3bc9fb4 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Thu, 26 Mar 2026 15:38:58 -0500 Subject: [PATCH] VTable optimizations --- core/README.md | 10 +- core/dvxApp.c | 26 +++-- core/dvxWidget.h | 22 ++-- core/dvxWidgetPlugin.h | 24 +---- core/widgetCore.c | 48 +-------- core/widgetEvent.c | 193 ++++-------------------------------- core/widgetOps.c | 8 +- core/widgetScrollbar.c | 17 ---- listhelp/README.md | 3 +- listhelp/listHelp.c | 8 +- listhelp/listHelp.h | 2 +- texthelp/README.md | 3 +- texthelp/textHelp.c | 14 +-- texthelp/textHelp.h | 2 +- widgets/widgetAnsiTerm.c | 10 +- widgets/widgetButton.c | 34 ++++++- widgets/widgetCanvas.c | 36 +++++-- widgets/widgetComboBox.c | 41 ++------ widgets/widgetDropdown.c | 32 +----- widgets/widgetImageButton.c | 34 ++++++- widgets/widgetListBox.c | 49 +++++++-- widgets/widgetListView.c | 60 +++++++++-- widgets/widgetScrollPane.c | 27 +++-- widgets/widgetSlider.c | 21 ++-- widgets/widgetSpinner.c | 3 +- widgets/widgetSplitter.c | 23 +++-- widgets/widgetTextInput.c | 62 +++++++----- widgets/widgetTreeView.c | 55 ++++++++-- 28 files changed, 374 insertions(+), 493 deletions(-) diff --git a/core/README.md b/core/README.md index 57eb162..0e35d8e 100644 --- a/core/README.md +++ b/core/README.md @@ -165,19 +165,13 @@ The vtable has 26 function slots plus a flags field: | `getText` | `(w)` | Return widget text | | `setText` | `(w, text)` | Set widget text | | `clearSelection` | `(w)` | Clear text/item selection | -| `dragSelect` | `(w, root, vx, vy)` | Handle drag selection | -| `openPopup` | `(w)` | Open dropdown popup | | `closePopup` | `(w)` | Close dropdown popup | -| `getPopupItemCount` | `(w)` | Return number of popup items | | `getPopupRect` | `(w, font, contentH, popX, popY, popW, popH)` | Compute popup rectangle | -| `setPressed` | `(w, pressed)` | Set button press visual state | -| `reorderDrop` | `(w)` | Complete drag-reorder operation | -| `reorderUpdate` | `(w, root, x, y)` | Update drag-reorder position | +| `onDragUpdate` | `(w, root, x, y)` | Mouse move during drag | +| `onDragEnd` | `(w, root, x, y)` | Mouse release after drag | | `getCursorShape` | `(w, vx, vy)` | Return cursor ID for this position | | `poll` | `(w, win)` | Periodic polling (AnsiTerm comms) | | `quickRepaint` | `(w, outY, outH)` | Fast incremental repaint | -| `getTextFieldWidth` | `(w)` | Text field width for scroll calc | -| `scrollDragUpdate` | `(w, orient, dragOff, mouseX, mouseY)` | Scrollbar drag update | ### WidgetClassT Flags diff --git a/core/dvxApp.c b/core/dvxApp.c index e4a3297..87e5195 100644 --- a/core/dvxApp.c +++ b/core/dvxApp.c @@ -2657,12 +2657,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->setPressed) { - sKeyPressedBtn->wclass->setPressed(sKeyPressedBtn, false); - } - - if (sKeyPressedBtn->onClick) { - sKeyPressedBtn->onClick(sKeyPressedBtn); + if (sKeyPressedBtn->wclass && sKeyPressedBtn->wclass->onDragEnd) { + // 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); } wgtInvalidate(sKeyPressedBtn); @@ -4551,14 +4551,12 @@ static void updateCursorShape(AppContextT *ctx) { newCursor = CURSOR_RESIZE_V; } } - // Active ListView column resize drag - else if (sResizeListView) { - newCursor = CURSOR_RESIZE_H; - } - // Active splitter drag - else if (sDragSplitter) { - if (sDragSplitter->wclass && sDragSplitter->wclass->getCursorShape) { - newCursor = sDragSplitter->wclass->getCursorShape(sDragSplitter, 0, 0); + // 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); + + if (shape > 0) { + newCursor = shape; } } // Not in an active drag/resize -- check what we're hovering diff --git a/core/dvxWidget.h b/core/dvxWidget.h index 6570515..554ac40 100644 --- a/core/dvxWidget.h +++ b/core/dvxWidget.h @@ -168,22 +168,18 @@ typedef struct WidgetClassT { const char *(*getText)(const struct WidgetT *w); void (*setText)(struct WidgetT *w, const char *text); - // Selection / drag-select + // Selection bool (*clearSelection)(struct WidgetT *w); - void (*dragSelect)(struct WidgetT *w, struct WidgetT *root, int32_t vx, int32_t vy); // Popup (dropdown/combobox) - void (*openPopup)(struct WidgetT *w); void (*closePopup)(struct WidgetT *w); - int32_t (*getPopupItemCount)(const 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); - // Button press state - void (*setPressed)(struct WidgetT *w, bool pressed); - - // Drag reorder (listbox/listview/treeview) - void (*reorderDrop)(struct WidgetT *w); - void (*reorderUpdate)(struct WidgetT *w, struct WidgetT *root, int32_t x, int32_t y); + // 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); @@ -194,14 +190,8 @@ typedef struct WidgetClassT { // Fast incremental repaint (returns dirty row count, 0 = none) int32_t (*quickRepaint)(struct WidgetT *w, int32_t *outY, int32_t *outH); - // Text field width (for scroll calculations; 0 = use widget width) - int32_t (*getTextFieldWidth)(const struct WidgetT *w); - // Scroll a child widget into the visible area (ScrollPane, etc.) void (*scrollChildIntoView)(struct WidgetT *parent, const struct WidgetT *child); - - // Scrollbar drag update (orient: 0=vert, 1=horiz) - void (*scrollDragUpdate)(struct WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY); } WidgetClassT; // ============================================================ diff --git a/core/dvxWidgetPlugin.h b/core/dvxWidgetPlugin.h index f1c3926..c4e24bf 100644 --- a/core/dvxWidgetPlugin.h +++ b/core/dvxWidgetPlugin.h @@ -101,18 +101,7 @@ extern WidgetT *sClosedPopup; extern WidgetT *sFocusedWidget; extern WidgetT *sKeyPressedBtn; extern WidgetT *sOpenPopup; -extern WidgetT *sPressedButton; -extern WidgetT *sDragSlider; -extern WidgetT *sDrawingCanvas; -extern WidgetT *sDragTextSelect; -extern int32_t sDragOffset; -extern WidgetT *sResizeListView; -extern WidgetT *sDragSplitter; -extern int32_t sDragSplitStart; -extern WidgetT *sDragReorder; -extern WidgetT *sDragScrollbar; -extern int32_t sDragScrollbarOff; -extern int32_t sDragScrollbarOrient; +extern WidgetT *sDragWidget; // widget being dragged (any drag type) extern void (*sCursorBlinkFn)(void); // ============================================================ @@ -167,7 +156,6 @@ typedef enum { void widgetDrawScrollbarH(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t sbX, int32_t sbY, int32_t sbW, int32_t totalSize, int32_t visibleSize, int32_t scrollPos); void widgetDrawScrollbarV(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t sbX, int32_t sbY, int32_t sbH, int32_t totalSize, int32_t visibleSize, int32_t scrollPos); -void widgetScrollbarDragUpdate(WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY); ScrollHitE widgetScrollbarHitTest(int32_t sbLen, int32_t relPos, int32_t totalSize, int32_t visibleSize, int32_t scrollPos); // ============================================================ @@ -202,14 +190,4 @@ void widgetPaintOverlays(WidgetT *root, DisplayT *d, const BlitOpsT *ops, const // listhelp/listHelp.h -- dropdown arrow, popup list, keyboard nav // Widget DXEs that use these include the headers directly. -// widgetTextDragUpdate stays in core (widgetCore.c) -void widgetTextDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy); - -// ============================================================ -// Drag-reorder helpers (widgetEvent.c) -// ============================================================ - -void widgetReorderUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y); -void widgetReorderDrop(WidgetT *w); - #endif // DVX_WIDGET_PLUGIN_H diff --git a/core/widgetCore.c b/core/widgetCore.c index 79673a2..d3fcefa 100644 --- a/core/widgetCore.c +++ b/core/widgetCore.c @@ -46,18 +46,7 @@ clock_t sDblClickTicks = 0; // set from ctx->dblClickTicks during first p bool sDebugLayout = false; WidgetT *sFocusedWidget = NULL; // currently focused widget (O(1) access, avoids tree walk) WidgetT *sOpenPopup = NULL; // dropdown/combobox with open popup list -WidgetT *sPressedButton = NULL; // button being held down (tracks mouse in/out) -WidgetT *sDragSlider = NULL; // slider being dragged -WidgetT *sDrawingCanvas = NULL; // canvas receiving paint strokes -WidgetT *sDragTextSelect = NULL; // text widget in drag-select mode -int32_t sDragOffset = 0; // pixel offset from drag start to thumb center -WidgetT *sResizeListView = NULL; // ListView undergoing column resize -WidgetT *sDragSplitter = NULL; // splitter being dragged -int32_t sDragSplitStart = 0; // mouse offset from splitter edge at drag start -WidgetT *sDragReorder = NULL; // list/tree widget in drag-reorder mode -WidgetT *sDragScrollbar = NULL; // widget whose scrollbar thumb is being dragged -int32_t sDragScrollbarOff = 0; // mouse offset within thumb at drag start -int32_t sDragScrollbarOrient = 0; // 0=vertical, 1=horizontal +WidgetT *sDragWidget = NULL; // widget being dragged (any drag type) // Shared clipboard -- process-wide, not per-widget. #define CLIPBOARD_MAX 4096 @@ -275,24 +264,8 @@ void widgetDestroyChildren(WidgetT *w) { sOpenPopup = NULL; } - if (sPressedButton == child) { - sPressedButton = NULL; - } - - if (sDragSlider == child) { - sDragSlider = NULL; - } - - if (sDrawingCanvas == child) { - sDrawingCanvas = NULL; - } - - if (sResizeListView == child) { - sResizeListView = NULL; - } - - if (sDragScrollbar == child) { - sDragScrollbar = NULL; + if (sDragWidget == child) { + sDragWidget = NULL; } free(child); @@ -657,18 +630,3 @@ void widgetRemoveChild(WidgetT *parent, WidgetT *child) { } -// ============================================================ -// widgetTextDragUpdate -- update selection during mouse drag -// ============================================================ -// -// Called by the event loop on mouse-move while sDragTextSelect is set. -// Extends the selection from the anchor to the current mouse position. -// Handles auto-scroll: when the mouse is past the widget edges, the -// scroll offset is nudged by one unit per event, creating a smooth -// scroll-while-dragging effect. - -void widgetTextDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { - if (w->wclass && w->wclass->dragSelect) { - w->wclass->dragSelect(w, root, vx, vy); - } -} diff --git a/core/widgetEvent.c b/core/widgetEvent.c index 91e1fcd..8d1289e 100644 --- a/core/widgetEvent.c +++ b/core/widgetEvent.c @@ -214,23 +214,29 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { sOpenPopup = NULL; } - // Handle text drag-select release - if (sDragTextSelect && !(buttons & MOUSE_LEFT)) { - sDragTextSelect = NULL; + // Handle drag release + if (sDragWidget && !(buttons & MOUSE_LEFT)) { + if (sDragWidget->wclass && sDragWidget->wclass->onDragEnd) { + sDragWidget->wclass->onDragEnd(sDragWidget, root, x, y); + } + + wgtInvalidatePaint(root); + sDragWidget = NULL; return; } - // Handle text drag-select (mouse move while pressed) - if (sDragTextSelect && (buttons & MOUSE_LEFT)) { - widgetTextDragUpdate(sDragTextSelect, root, x, y); + // Handle drag move + if (sDragWidget && (buttons & MOUSE_LEFT)) { + if (sDragWidget->wclass && sDragWidget->wclass->onDragUpdate) { + sDragWidget->wclass->onDragUpdate(sDragWidget, root, x, y); + } - if (sDragTextSelect->wclass && sDragTextSelect->wclass->quickRepaint) { - // Fast path: repaint only dirty rows into the content - // buffer, then dirty just that screen stripe. + // quickRepaint fast path for text drag (dirty rect instead of full repaint) + if (sDragWidget->wclass && sDragWidget->wclass->quickRepaint) { int32_t dirtyY = 0; int32_t dirtyH = 0; - if (sDragTextSelect->wclass->quickRepaint(sDragTextSelect, &dirtyY, &dirtyH) > 0) { + if (sDragWidget->wclass->quickRepaint(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; @@ -238,108 +244,13 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { int32_t rectW = win->contentW; win->contentDirty = true; dirtyListAdd(&ctx->dirty, rectX, rectY, rectW, dirtyH); + return; } - } else { - wgtInvalidate(root); } - return; - } - - // Handle canvas drawing release - if (sDrawingCanvas && !(buttons & MOUSE_LEFT)) { - sDrawingCanvas = NULL; - wgtInvalidatePaint(root); - return; - } - - // Handle canvas drawing (mouse move while pressed) - if (sDrawingCanvas && (buttons & MOUSE_LEFT)) { - if (sDrawingCanvas->wclass && sDrawingCanvas->wclass->onMouse) { - sDrawingCanvas->wclass->onMouse(sDrawingCanvas, root, x, y); - } - wgtInvalidatePaint(root); - return; - } - - // Handle slider drag release - if (sDragSlider && !(buttons & MOUSE_LEFT)) { - sDragSlider = NULL; - wgtInvalidatePaint(root); - return; - } - - // Handle slider drag (mouse move while pressed) - if (sDragSlider && (buttons & MOUSE_LEFT)) { - if (sDragSlider->wclass && sDragSlider->wclass->scrollDragUpdate) { - sDragSlider->wclass->scrollDragUpdate(sDragSlider, 0, sDragOffset, x, y); - wgtInvalidatePaint(root); - } - - return; - } - - // Handle ListView column resize release - if (sResizeListView && !(buttons & MOUSE_LEFT)) { - sResizeListView = NULL; - return; - } - - // Handle ListView column resize drag via vtable - if (sResizeListView && (buttons & MOUSE_LEFT)) { - if (sResizeListView->wclass && sResizeListView->wclass->scrollDragUpdate) { - sResizeListView->wclass->scrollDragUpdate(sResizeListView, -1, 0, x, y); - wgtInvalidatePaint(root); - } - - return; - } - - // Handle drag-reorder release - if (sDragReorder && !(buttons & MOUSE_LEFT)) { - widgetReorderDrop(sDragReorder); - sDragReorder = NULL; - wgtInvalidatePaint(root); - return; - } - - // Handle drag-reorder move - if (sDragReorder && (buttons & MOUSE_LEFT)) { - widgetReorderUpdate(sDragReorder, root, x, y); - wgtInvalidatePaint(root); - return; - } - - // Handle splitter drag release - if (sDragSplitter && !(buttons & MOUSE_LEFT)) { - sDragSplitter = NULL; - return; - } - - // Handle splitter drag via vtable - if (sDragSplitter && (buttons & MOUSE_LEFT)) { - if (sDragSplitter->wclass && sDragSplitter->wclass->scrollDragUpdate) { - sDragSplitter->wclass->scrollDragUpdate(sDragSplitter, 0, sDragSplitStart, x, y); - } - - return; - } - - // Handle scrollbar thumb drag release - if (sDragScrollbar && !(buttons & MOUSE_LEFT)) { - sDragScrollbar = NULL; - wgtInvalidatePaint(root); - return; - } - - // Handle scrollbar thumb drag (mouse move while pressed) - if (sDragScrollbar && (buttons & MOUSE_LEFT)) { - widgetScrollbarDragUpdate(sDragScrollbar, sDragScrollbarOrient, sDragScrollbarOff, x, y); - - // Scroll containers need full relayout because they position children - // at absolute coordinates incorporating the scroll offset. - if (sDragScrollbar->wclass && (sDragScrollbar->wclass->flags & WCLASS_RELAYOUT_ON_SCROLL)) { - wgtInvalidate(sDragScrollbar); + // Scroll containers need full relayout + if (sDragWidget->wclass && (sDragWidget->wclass->flags & WCLASS_RELAYOUT_ON_SCROLL)) { + wgtInvalidate(sDragWidget); } else { wgtInvalidatePaint(root); } @@ -347,44 +258,6 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { return; } - // Handle button press release - if (sPressedButton && !(buttons & MOUSE_LEFT)) { - if (sPressedButton->wclass && sPressedButton->wclass->setPressed) { - sPressedButton->wclass->setPressed(sPressedButton, false); - } - - // Fire onClick if released over the same button in the same window - if (sPressedButton->window == win) { - if (x >= sPressedButton->x && x < sPressedButton->x + sPressedButton->w && - y >= sPressedButton->y && y < sPressedButton->y + sPressedButton->h) { - if (sPressedButton->onClick) { - sPressedButton->onClick(sPressedButton); - } - } - } - - wgtInvalidatePaint(sPressedButton); - sPressedButton = NULL; - return; - } - - // Handle button press tracking (mouse move while held) - if (sPressedButton && (buttons & MOUSE_LEFT)) { - bool over = false; - - if (sPressedButton->window == win) { - over = (x >= sPressedButton->x && x < sPressedButton->x + sPressedButton->w && - y >= sPressedButton->y && y < sPressedButton->y + sPressedButton->h); - } - - if (sPressedButton->wclass && sPressedButton->wclass->setPressed) { - sPressedButton->wclass->setPressed(sPressedButton, over); - } - - wgtInvalidatePaint(sPressedButton); - return; - } - // Handle open popup clicks if (sOpenPopup && (buttons & MOUSE_LEFT)) { AppContextT *ctx = (AppContextT *)root->userData; @@ -627,29 +500,3 @@ void widgetOnScroll(WindowT *win, ScrollbarOrientE orient, int32_t value) { } -// ============================================================ -// widgetReorderDrop -- finalize drag-reorder on mouse release -// ============================================================ -// -// Dispatches to the widget's reorderDrop vtable method, which handles -// the type-specific logic for completing the drag-reorder operation. - -void widgetReorderDrop(WidgetT *w) { - if (w->wclass && w->wclass->reorderDrop) { - w->wclass->reorderDrop(w); - } -} - - -// ============================================================ -// widgetReorderUpdate -- update drop position during drag -// ============================================================ -// -// Dispatches to the widget's reorderUpdate vtable method, which handles -// type-specific drop indicator positioning and auto-scrolling. - -void widgetReorderUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { - if (w->wclass && w->wclass->reorderUpdate) { - w->wclass->reorderUpdate(w, root, x, y); - } -} diff --git a/core/widgetOps.c b/core/widgetOps.c index 0279937..b396e01 100644 --- a/core/widgetOps.c +++ b/core/widgetOps.c @@ -184,12 +184,8 @@ void wgtDestroy(WidgetT *w) { sOpenPopup = NULL; } - if (sDragSlider == w) { - sDragSlider = NULL; - } - - if (sDrawingCanvas == w) { - sDrawingCanvas = NULL; + if (sDragWidget == w) { + sDragWidget = NULL; } // If this is the root, clear the window's reference diff --git a/core/widgetScrollbar.c b/core/widgetScrollbar.c index ef14f5a..5527f65 100644 --- a/core/widgetScrollbar.c +++ b/core/widgetScrollbar.c @@ -136,23 +136,6 @@ void widgetDrawScrollbarV(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT * } -// ============================================================ -// widgetScrollbarDragUpdate -// ============================================================ - -// Handles ongoing scrollbar thumb drag for widget-internal scrollbars. -// Dispatches to the widget's scrollDragUpdate vtable method, which -// handles type-specific geometry extraction and scroll position update. -void widgetScrollbarDragUpdate(WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY) { - // Dispatch to the widget's scrollDragUpdate vtable method, which - // handles type-specific geometry extraction, thumb computation, - // and scroll position update. - if (w->wclass && w->wclass->scrollDragUpdate) { - w->wclass->scrollDragUpdate(w, orient, dragOff, mouseX, mouseY); - } -} - - // ============================================================ // widgetScrollbarHitTest // ============================================================ diff --git a/listhelp/README.md b/listhelp/README.md index 02dfcb2..ab41824 100644 --- a/listhelp/README.md +++ b/listhelp/README.md @@ -45,7 +45,8 @@ index, clamped to valid range. ```c void widgetDropdownPopupRect(WidgetT *w, const BitmapFontT *font, - int32_t contentH, int32_t *popX, int32_t *popY, + int32_t contentH, int32_t itemCount, + int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH); ``` diff --git a/listhelp/listHelp.c b/listhelp/listHelp.c index 795b3a9..ad70599 100644 --- a/listhelp/listHelp.c +++ b/listhelp/listHelp.c @@ -154,13 +154,7 @@ void widgetPaintPopupList(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *f // Shared between Dropdown and ComboBox since they have identical // popup positioning logic. -void widgetDropdownPopupRect(WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH) { - int32_t itemCount = 0; - - if (w->wclass && w->wclass->getPopupItemCount) { - itemCount = w->wclass->getPopupItemCount(w); - } - +void widgetDropdownPopupRect(WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t itemCount, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH) { int32_t visibleItems = itemCount; if (visibleItems > DROPDOWN_MAX_VISIBLE) { diff --git a/listhelp/listHelp.h b/listhelp/listHelp.h index c7001d3..df3a3f5 100644 --- a/listhelp/listHelp.h +++ b/listhelp/listHelp.h @@ -34,7 +34,7 @@ int32_t widgetNavigateIndex(int32_t key, int32_t current, int32_t count, int32_t // Popup rect calculation // ============================================================ -void widgetDropdownPopupRect(WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH); +void widgetDropdownPopupRect(WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t itemCount, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH); // ============================================================ // Popup list painting diff --git a/texthelp/README.md b/texthelp/README.md index 12be228..b539cc4 100644 --- a/texthelp/README.md +++ b/texthelp/README.md @@ -62,7 +62,8 @@ void widgetTextEditOnKey(WidgetT *w, int32_t key, int32_t mod, char *buf, int32_t bufSize, int32_t *pLen, int32_t *pCursor, int32_t *pScrollOff, int32_t *pSelStart, int32_t *pSelEnd, - char *undoBuf, int32_t *pUndoLen, int32_t *pUndoCursor); + char *undoBuf, int32_t *pUndoLen, int32_t *pUndoCursor, + int32_t fieldWidth); ``` Handles all keyboard input: character insertion, deletion (Backspace, diff --git a/texthelp/textHelp.c b/texthelp/textHelp.c index 1fbbd64..405ff0e 100644 --- a/texthelp/textHelp.c +++ b/texthelp/textHelp.c @@ -231,7 +231,7 @@ void widgetTextEditMouseClick(WidgetT *w, int32_t vx, int32_t vy, int32_t textLe *pSelStart = 0; *pSelEnd = len; *pCursorPos = len; - sDragTextSelect = NULL; + sDragWidget = NULL; return; } @@ -248,7 +248,7 @@ void widgetTextEditMouseClick(WidgetT *w, int32_t vx, int32_t vy, int32_t textLe *pCursorPos = len; } - sDragTextSelect = NULL; + sDragWidget = NULL; return; } @@ -256,7 +256,7 @@ void widgetTextEditMouseClick(WidgetT *w, int32_t vx, int32_t vy, int32_t textLe *pCursorPos = charPos; *pSelStart = charPos; *pSelEnd = charPos; - sDragTextSelect = dragSelect ? w : NULL; + sDragWidget = dragSelect ? w : NULL; } @@ -267,7 +267,7 @@ void widgetTextEditMouseClick(WidgetT *w, int32_t vx, int32_t vy, int32_t textLe // This is the core single-line text editing engine, parameterized by // pointer to allow reuse across TextInput, Spinner, and ComboBox. -void widgetTextEditOnKey(WidgetT *w, int32_t key, int32_t mod, char *buf, int32_t bufSize, int32_t *pLen, int32_t *pCursor, int32_t *pScrollOff, int32_t *pSelStart, int32_t *pSelEnd, char *undoBuf, int32_t *pUndoLen, int32_t *pUndoCursor) { +void widgetTextEditOnKey(WidgetT *w, int32_t key, int32_t mod, char *buf, int32_t bufSize, int32_t *pLen, int32_t *pCursor, int32_t *pScrollOff, int32_t *pSelStart, int32_t *pSelEnd, char *undoBuf, int32_t *pUndoLen, int32_t *pUndoCursor, int32_t fieldWidth) { bool shift = (mod & KEY_MOD_SHIFT) != 0; bool hasSel = (pSelStart && pSelEnd && *pSelStart >= 0 && *pSelEnd >= 0 && *pSelStart != *pSelEnd); int32_t selLo = hasSel ? (*pSelStart < *pSelEnd ? *pSelStart : *pSelEnd) : -1; @@ -638,11 +638,7 @@ adjustScroll: { AppContextT *ctx = wgtGetContext(w); const BitmapFontT *font = &ctx->font; - int32_t fieldW = w->w; - - if (w->wclass && w->wclass->getTextFieldWidth) { - fieldW = w->wclass->getTextFieldWidth(w); - } + int32_t fieldW = fieldWidth > 0 ? fieldWidth : w->w; int32_t visibleChars = (fieldW - TEXT_INPUT_PAD * 2) / font->charWidth; diff --git a/texthelp/textHelp.h b/texthelp/textHelp.h index 6ac490f..ebd38d7 100644 --- a/texthelp/textHelp.h +++ b/texthelp/textHelp.h @@ -38,7 +38,7 @@ int32_t wordStart(const char *buf, int32_t pos); void widgetTextEditDragUpdateLine(int32_t vx, int32_t leftEdge, int32_t maxChars, const BitmapFontT *font, int32_t len, int32_t *pCursorPos, int32_t *pScrollOff, int32_t *pSelEnd); void widgetTextEditMouseClick(WidgetT *w, int32_t vx, int32_t vy, int32_t textLeftX, const BitmapFontT *font, const char *buf, int32_t len, int32_t scrollOff, int32_t *pCursorPos, int32_t *pSelStart, int32_t *pSelEnd, bool wordSelect, bool dragSelect); -void widgetTextEditOnKey(WidgetT *w, int32_t key, int32_t mod, char *buf, int32_t bufSize, int32_t *pLen, int32_t *pCursor, int32_t *pScrollOff, int32_t *pSelStart, int32_t *pSelEnd, char *undoBuf, int32_t *pUndoLen, int32_t *pUndoCursor); +void widgetTextEditOnKey(WidgetT *w, int32_t key, int32_t mod, char *buf, int32_t bufSize, int32_t *pLen, int32_t *pCursor, int32_t *pScrollOff, int32_t *pSelStart, int32_t *pSelEnd, char *undoBuf, int32_t *pUndoLen, int32_t *pUndoCursor, int32_t fieldWidth); void widgetTextEditPaintLine(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors, int32_t textX, int32_t textY, const char *buf, int32_t visLen, int32_t scrollOff, int32_t cursorPos, int32_t selStart, int32_t selEnd, uint32_t fg, uint32_t bg, bool showCursor, int32_t cursorMinX, int32_t cursorMaxX); #endif // TEXT_HELP_H diff --git a/widgets/widgetAnsiTerm.c b/widgets/widgetAnsiTerm.c index 199864c..55d6021 100644 --- a/widgets/widgetAnsiTerm.c +++ b/widgets/widgetAnsiTerm.c @@ -807,7 +807,7 @@ void widgetAnsiTermOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) if (clicks >= 3) { at->selStartLine = lineIndex; at->selStartCol = 0; at->selEndLine = lineIndex; at->selEndCol = cols; - at->selecting = false; sDragTextSelect = NULL; + at->selecting = false; sDragWidget = NULL; } else if (clicks == 2) { const uint8_t *lineData = ansiTermGetLine(hit, lineIndex); int32_t ws = clickCol; int32_t we = clickCol; @@ -815,11 +815,11 @@ void widgetAnsiTermOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) while (we < cols && isWordChar((char)lineData[we * 2])) { we++; } at->selStartLine = lineIndex; at->selStartCol = ws; at->selEndLine = lineIndex; at->selEndCol = we; - at->selecting = false; sDragTextSelect = NULL; + at->selecting = false; sDragWidget = NULL; } else { at->selStartLine = lineIndex; at->selStartCol = clickCol; at->selEndLine = lineIndex; at->selEndCol = clickCol; - at->selecting = true; sDragTextSelect = hit; + at->selecting = true; sDragWidget = hit; } at->dirtyRows = 0xFFFFFFFF; return; @@ -925,7 +925,7 @@ static bool widgetAnsiTermClearSelection(WidgetT *w) { } -static void widgetAnsiTermDragSelect(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { +static void widgetAnsiTermOnDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { (void)root; AnsiTermDataT *at = (AnsiTermDataT *)w->data; AppContextT *ctx = wgtGetContext(w); @@ -971,7 +971,7 @@ static const WidgetClassT sClassAnsiTerm = { .getText = NULL, .setText = NULL, .clearSelection = widgetAnsiTermClearSelection, - .dragSelect = widgetAnsiTermDragSelect, + .onDragUpdate = widgetAnsiTermOnDragUpdate, .poll = widgetAnsiTermPollVtable, .quickRepaint = wgtAnsiTermRepaint }; diff --git a/widgets/widgetButton.c b/widgets/widgetButton.c index c5e8d34..461fc5c 100644 --- a/widgets/widgetButton.c +++ b/widgets/widgetButton.c @@ -116,7 +116,7 @@ void widgetButtonOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { ButtonDataT *d = (ButtonDataT *)w->data; w->focused = true; d->pressed = true; - sPressedButton = w; + sDragWidget = w; } @@ -165,12 +165,35 @@ void widgetButtonPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitma // ============================================================ -// widgetButtonSetPressed +// widgetButtonOnDragEnd // ============================================================ -void widgetButtonSetPressed(WidgetT *w, bool pressed) { +static void widgetButtonOnDragEnd(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { ButtonDataT *d = (ButtonDataT *)w->data; - d->pressed = pressed; + d->pressed = false; + + if (w->window == root->window && + x >= w->x && x < w->x + w->w && + y >= w->y && y < w->y + w->h) { + if (w->onClick) { + w->onClick(w); + } + } + + wgtInvalidatePaint(w); +} + + +// ============================================================ +// widgetButtonOnDragUpdate +// ============================================================ + +static void widgetButtonOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + ButtonDataT *d = (ButtonDataT *)w->data; + bool over = (w->window == root->window && + x >= w->x && x < w->x + w->w && + y >= w->y && y < w->y + w->h); + d->pressed = over; wgtInvalidatePaint(w); } @@ -203,7 +226,8 @@ static const WidgetClassT sClassButton = { .destroy = widgetButtonDestroy, .getText = widgetButtonGetText, .setText = widgetButtonSetText, - .setPressed = widgetButtonSetPressed + .onDragUpdate = widgetButtonOnDragUpdate, + .onDragEnd = widgetButtonOnDragEnd }; // ============================================================ diff --git a/widgets/widgetCanvas.c b/widgets/widgetCanvas.c index fd3ca23..516615b 100644 --- a/widgets/widgetCanvas.c +++ b/widgets/widgetCanvas.c @@ -581,22 +581,41 @@ void widgetCanvasOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { int32_t cx = vx - hit->x - CANVAS_BORDER; int32_t cy = vy - hit->y - CANVAS_BORDER; - bool drag = (sDrawingCanvas == hit); - - if (!drag) { - sDrawingCanvas = hit; - cd->lastX = -1; - cd->lastY = -1; - } + sDragWidget = hit; + cd->lastX = -1; + cd->lastY = -1; cd->lastX = cx; cd->lastY = cy; - cd->onMouse(hit, cx, cy, drag); + cd->onMouse(hit, cx, cy, false); wgtInvalidatePaint(hit); } +// ============================================================ +// widgetCanvasOnDragUpdate +// ============================================================ + +static void widgetCanvasOnDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { + (void)root; + CanvasDataT *cd = (CanvasDataT *)w->data; + + if (!cd->onMouse) { + return; + } + + int32_t cx = vx - w->x - CANVAS_BORDER; + int32_t cy = vy - w->y - CANVAS_BORDER; + + cd->lastX = cx; + cd->lastY = cy; + + cd->onMouse(w, cx, cy, true); + wgtInvalidatePaint(w); +} + + // ============================================================ // widgetCanvasPaint // ============================================================ @@ -644,6 +663,7 @@ static const WidgetClassT sClassCanvas = { .calcMinSize = widgetCanvasCalcMinSize, .layout = NULL, .onMouse = widgetCanvasOnMouse, + .onDragUpdate = widgetCanvasOnDragUpdate, .onKey = NULL, .destroy = widgetCanvasDestroy, .getText = NULL, diff --git a/widgets/widgetComboBox.c b/widgets/widgetComboBox.c index 3df8e30..6506701 100644 --- a/widgets/widgetComboBox.c +++ b/widgets/widgetComboBox.c @@ -19,7 +19,7 @@ // // Text selection supports single-click (cursor placement + drag start), // double-click (word select), and triple-click (select all). Drag-select -// is tracked via the sDragTextSelect global. +// is tracked via the sDragWidget global. #include "dvxWidgetPlugin.h" #include "../texthelp/textHelp.h" @@ -190,7 +190,8 @@ void widgetComboBoxOnKey(WidgetT *w, int32_t key, int32_t mod) { &d->scrollOff, &d->selStart, &d->selEnd, d->undoBuf, &d->undoLen, - &d->undoCursor); + &d->undoCursor, + w->w - DROPDOWN_BTN_WIDTH); } @@ -211,7 +212,7 @@ void widgetComboBoxOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { int32_t popW; int32_t popH; - widgetDropdownPopupRect(w, font, w->window->contentH, &popX, &popY, &popW, &popH); + widgetDropdownPopupRect(w, font, w->window->contentH, d->itemCount, &popX, &popY, &popW, &popH); int32_t itemIdx = d->listScrollPos + (vy - popY - 2) / font->charHeight; @@ -329,7 +330,7 @@ void widgetComboBoxPaintPopup(WidgetT *w, DisplayT *disp, const BlitOpsT *ops, c int32_t popW; int32_t popH; - widgetDropdownPopupRect(w, font, disp->clipH, &popX, &popY, &popW, &popH); + widgetDropdownPopupRect(w, font, disp->clipH, d->itemCount, &popX, &popY, &popW, &popH); widgetPaintPopupList(disp, ops, font, colors, popX, popY, popW, popH, d->items, d->itemCount, d->hoverIdx, d->listScrollPos); } @@ -378,35 +379,13 @@ void widgetComboBoxClosePopup(WidgetT *w) { } -// ============================================================ -// widgetComboBoxGetPopupItemCount -// ============================================================ - -int32_t widgetComboBoxGetPopupItemCount(const WidgetT *w) { - const ComboBoxDataT *d = (const ComboBoxDataT *)w->data; - return d->itemCount; -} - - -// ============================================================ -// widgetComboBoxOpenPopup -// ============================================================ - -void widgetComboBoxOpenPopup(WidgetT *w) { - ComboBoxDataT *d = (ComboBoxDataT *)w->data; - d->open = true; - d->hoverIdx = d->selectedIdx; - sOpenPopup = w; - wgtInvalidatePaint(w); -} - - // ============================================================ // DXE registration // ============================================================ static void widgetComboBoxGetPopupRect(const WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH) { - widgetDropdownPopupRect((WidgetT *)w, font, contentH, popX, popY, popW, popH); + const ComboBoxDataT *d = (const ComboBoxDataT *)w->data; + widgetDropdownPopupRect((WidgetT *)w, font, contentH, d->itemCount, popX, popY, popW, popH); } @@ -423,7 +402,7 @@ static bool widgetComboBoxClearSelection(WidgetT *w) { } -static void widgetComboBoxDragSelect(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { +static void widgetComboBoxOnDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { (void)root; (void)vy; ComboBoxDataT *d = (ComboBoxDataT *)w->data; @@ -447,11 +426,9 @@ static const WidgetClassT sClassComboBox = { .destroy = widgetComboBoxDestroy, .getText = widgetComboBoxGetText, .setText = widgetComboBoxSetText, - .openPopup = widgetComboBoxOpenPopup, .closePopup = widgetComboBoxClosePopup, - .getPopupItemCount = widgetComboBoxGetPopupItemCount, .clearSelection = widgetComboBoxClearSelection, - .dragSelect = widgetComboBoxDragSelect, + .onDragUpdate = widgetComboBoxOnDragUpdate, .getPopupRect = widgetComboBoxGetPopupRect }; diff --git a/widgets/widgetDropdown.c b/widgets/widgetDropdown.c index 4e535e9..e3a8e44 100644 --- a/widgets/widgetDropdown.c +++ b/widgets/widgetDropdown.c @@ -173,7 +173,7 @@ void widgetDropdownOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { int32_t popW; int32_t popH; - widgetDropdownPopupRect(w, font, w->window->contentH, &popX, &popY, &popW, &popH); + widgetDropdownPopupRect(w, font, w->window->contentH, d->itemCount, &popX, &popY, &popW, &popH); int32_t itemIdx = d->scrollPos + (vy - popY - 2) / font->charHeight; @@ -267,7 +267,7 @@ void widgetDropdownPaintPopup(WidgetT *w, DisplayT *disp, const BlitOpsT *ops, c int32_t popW; int32_t popH; - widgetDropdownPopupRect(w, font, disp->clipH, &popX, &popY, &popW, &popH); + widgetDropdownPopupRect(w, font, disp->clipH, d->itemCount, &popX, &popY, &popW, &popH); widgetPaintPopupList(disp, ops, font, colors, popX, popY, popW, popH, d->items, d->itemCount, d->hoverIdx, d->scrollPos); } @@ -297,36 +297,14 @@ void widgetDropdownClosePopup(WidgetT *w) { } -// ============================================================ -// widgetDropdownGetPopupItemCount -// ============================================================ - -int32_t widgetDropdownGetPopupItemCount(const WidgetT *w) { - const DropdownDataT *d = (const DropdownDataT *)w->data; - return d->itemCount; -} - - -// ============================================================ -// widgetDropdownOpenPopup -// ============================================================ - -void widgetDropdownOpenPopup(WidgetT *w) { - DropdownDataT *d = (DropdownDataT *)w->data; - d->open = true; - d->hoverIdx = d->selectedIdx; - sOpenPopup = w; - wgtInvalidatePaint(w); -} - - // ============================================================ // DXE registration // ============================================================ static void widgetDropdownGetPopupRect(const WidgetT *w, const BitmapFontT *font, int32_t contentH, int32_t *popX, int32_t *popY, int32_t *popW, int32_t *popH) { - widgetDropdownPopupRect((WidgetT *)w, font, contentH, popX, popY, popW, popH); + const DropdownDataT *d = (const DropdownDataT *)w->data; + widgetDropdownPopupRect((WidgetT *)w, font, contentH, d->itemCount, popX, popY, popW, popH); } @@ -342,9 +320,7 @@ static const WidgetClassT sClassDropdown = { .destroy = widgetDropdownDestroy, .getText = widgetDropdownGetText, .setText = NULL, - .openPopup = widgetDropdownOpenPopup, .closePopup = widgetDropdownClosePopup, - .getPopupItemCount = widgetDropdownGetPopupItemCount, .getPopupRect = widgetDropdownGetPopupRect }; diff --git a/widgets/widgetImageButton.c b/widgets/widgetImageButton.c index 0ee0dc3..d855be3 100644 --- a/widgets/widgetImageButton.c +++ b/widgets/widgetImageButton.c @@ -85,7 +85,7 @@ void widgetImageButtonOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) ImageButtonDataT *d = (ImageButtonDataT *)w->data; w->focused = true; d->pressed = true; - sPressedButton = w; + sDragWidget = w; } @@ -143,12 +143,35 @@ void widgetImageButtonAccelActivate(WidgetT *w, WidgetT *root) { // ============================================================ -// widgetImageButtonSetPressed +// widgetImageButtonOnDragEnd // ============================================================ -void widgetImageButtonSetPressed(WidgetT *w, bool pressed) { +static void widgetImageButtonOnDragEnd(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { ImageButtonDataT *d = (ImageButtonDataT *)w->data; - d->pressed = pressed; + d->pressed = false; + + if (w->window == root->window && + x >= w->x && x < w->x + w->w && + y >= w->y && y < w->y + w->h) { + if (w->onClick) { + w->onClick(w); + } + } + + wgtInvalidatePaint(w); +} + + +// ============================================================ +// widgetImageButtonOnDragUpdate +// ============================================================ + +static void widgetImageButtonOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + ImageButtonDataT *d = (ImageButtonDataT *)w->data; + bool over = (w->window == root->window && + x >= w->x && x < w->x + w->w && + y >= w->y && y < w->y + w->h); + d->pressed = over; wgtInvalidatePaint(w); } @@ -169,7 +192,8 @@ static const WidgetClassT sClassImageButton = { .destroy = widgetImageButtonDestroy, .getText = NULL, .setText = NULL, - .setPressed = widgetImageButtonSetPressed + .onDragUpdate = widgetImageButtonOnDragUpdate, + .onDragEnd = widgetImageButtonOnDragEnd }; diff --git a/widgets/widgetListBox.c b/widgets/widgetListBox.c index 0b90da6..e22b7fb 100644 --- a/widgets/widgetListBox.c +++ b/widgets/widgetListBox.c @@ -47,6 +47,8 @@ typedef struct { bool reorderable; int32_t dragIdx; int32_t dropIdx; + int32_t sbDragOrient; + int32_t sbDragOff; } ListBoxDataT; #include @@ -309,9 +311,9 @@ void widgetListBoxOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { int32_t thumbSize; widgetScrollbarThumb(trackLen, d->itemCount, visibleRows, d->scrollPos, &thumbPos, &thumbSize); - sDragScrollbar = hit; - sDragScrollbarOrient = 0; - sDragScrollbarOff = relY - WGT_SB_W - thumbPos; + sDragWidget = hit; + d->sbDragOrient = 0; + d->sbDragOff = relY - WGT_SB_W - thumbPos; } hit->focused = true; @@ -368,7 +370,7 @@ void widgetListBoxOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { if (d->reorderable && !shift && !ctrl) { d->dragIdx = idx; d->dropIdx = idx; - sDragReorder = hit; + sDragWidget = hit; } } @@ -586,6 +588,40 @@ static void widgetListBoxReorderDrop(WidgetT *w) { } +// ============================================================ +// widgetListBoxOnDragEnd +// ============================================================ + +static void widgetListBoxOnDragEnd(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + (void)root; + (void)x; + (void)y; + ListBoxDataT *d = (ListBoxDataT *)w->data; + + if (d->dragIdx >= 0) { + widgetListBoxReorderDrop(w); + d->dragIdx = -1; + } + + wgtInvalidatePaint(w); +} + + +// ============================================================ +// widgetListBoxOnDragUpdate +// ============================================================ + +static void widgetListBoxOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + ListBoxDataT *d = (ListBoxDataT *)w->data; + + if (d->dragIdx >= 0) { + widgetListBoxReorderUpdate(w, root, x, y); + } else { + widgetListBoxScrollDragUpdate(w, d->sbDragOrient, d->sbDragOff, x, y); + } +} + + static const WidgetClassT sClassListBox = { .flags = WCLASS_FOCUSABLE | WCLASS_SCROLLABLE, .paint = widgetListBoxPaint, @@ -597,9 +633,8 @@ static const WidgetClassT sClassListBox = { .destroy = widgetListBoxDestroy, .getText = NULL, .setText = NULL, - .reorderDrop = widgetListBoxReorderDrop, - .reorderUpdate = widgetListBoxReorderUpdate, - .scrollDragUpdate = widgetListBoxScrollDragUpdate + .onDragUpdate = widgetListBoxOnDragUpdate, + .onDragEnd = widgetListBoxOnDragEnd }; // ============================================================ diff --git a/widgets/widgetListView.c b/widgets/widgetListView.c index 4bdaa04..d7e2347 100644 --- a/widgets/widgetListView.c +++ b/widgets/widgetListView.c @@ -94,6 +94,8 @@ typedef struct { int32_t resizeStartX; int32_t resizeOrigW; bool resizeDragging; + int32_t sbDragOrient; + int32_t sbDragOff; } ListViewDataT; @@ -625,9 +627,9 @@ void widgetListViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) int32_t thumbSize; widgetScrollbarThumb(trackLen, lv->rowCount, visibleRows, lv->scrollPos, &thumbPos, &thumbSize); - sDragScrollbar = hit; - sDragScrollbarOrient = 0; - sDragScrollbarOff = relY - WGT_SB_W - thumbPos; + sDragWidget = hit; + lv->sbDragOrient = 0; + lv->sbDragOff = relY - WGT_SB_W - thumbPos; } return; @@ -663,9 +665,9 @@ void widgetListViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) int32_t thumbSize; widgetScrollbarThumb(trackLen, totalColW, innerW, lv->scrollPosH, &thumbPos, &thumbSize); - sDragScrollbar = hit; - sDragScrollbarOrient = 1; - sDragScrollbarOff = relX - WGT_SB_W - thumbPos; + sDragWidget = hit; + lv->sbDragOrient = 1; + lv->sbDragOff = relX - WGT_SB_W - thumbPos; } lv->scrollPosH = clampInt(lv->scrollPosH, 0, maxScrollH); @@ -730,7 +732,7 @@ void widgetListViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) wgtInvalidatePaint(hit); } else { // Start column resize drag (deferred until mouse moves) - sResizeListView = hit; + sDragWidget = hit; lv->resizeCol = c; lv->resizeStartX = vx; lv->resizeOrigW = cw; @@ -858,7 +860,7 @@ void widgetListViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) if (lv->reorderable && !shift && !ctrl) { lv->dragIdx = dataRow; lv->dropIdx = dataRow; - sDragReorder = hit; + sDragWidget = hit; } } @@ -1494,6 +1496,43 @@ static void widgetListViewReorderDrop(WidgetT *w) { } +// ============================================================ +// widgetListViewOnDragEnd +// ============================================================ + +static void widgetListViewOnDragEnd(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + (void)root; + (void)x; + (void)y; + ListViewDataT *lv = (ListViewDataT *)w->data; + + if (lv->dragIdx >= 0) { + widgetListViewReorderDrop(w); + lv->dragIdx = -1; + } + + lv->resizeDragging = false; + wgtInvalidatePaint(w); +} + + +// ============================================================ +// widgetListViewOnDragUpdate +// ============================================================ + +static void widgetListViewOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + ListViewDataT *lv = (ListViewDataT *)w->data; + + if (lv->resizeDragging) { + widgetListViewScrollDragUpdate(w, -1, 0, x, y); + } else if (lv->dragIdx >= 0) { + widgetListViewReorderUpdate(w, root, x, y); + } else { + widgetListViewScrollDragUpdate(w, lv->sbDragOrient, lv->sbDragOff, x, y); + } +} + + static const WidgetClassT sClassListView = { .flags = WCLASS_FOCUSABLE | WCLASS_NO_HIT_RECURSE | WCLASS_SCROLLABLE, .paint = widgetListViewPaint, @@ -1506,9 +1545,8 @@ static const WidgetClassT sClassListView = { .getText = NULL, .setText = NULL, .getCursorShape = widgetListViewGetCursorShape, - .reorderDrop = widgetListViewReorderDrop, - .reorderUpdate = widgetListViewReorderUpdate, - .scrollDragUpdate = widgetListViewScrollDragUpdate + .onDragUpdate = widgetListViewOnDragUpdate, + .onDragEnd = widgetListViewOnDragEnd }; diff --git a/widgets/widgetScrollPane.c b/widgets/widgetScrollPane.c index a9e477f..29843fe 100644 --- a/widgets/widgetScrollPane.c +++ b/widgets/widgetScrollPane.c @@ -35,6 +35,8 @@ static int32_t sTypeId = -1; typedef struct { int32_t scrollPosV; int32_t scrollPosH; + int32_t sbDragOrient; + int32_t sbDragOff; } ScrollPaneDataT; #define SP_BORDER 2 @@ -50,7 +52,7 @@ static void drawSPHScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const static void drawSPVScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t sbX, int32_t sbY, int32_t sbH, int32_t totalH, int32_t visibleH); static void spCalcNeeds(WidgetT *w, const BitmapFontT *font, int32_t *contentMinW, int32_t *contentMinH, int32_t *innerW, int32_t *innerH, bool *needVSb, bool *needHSb); static void widgetScrollPaneDestroy(WidgetT *w); -static void widgetScrollPaneScrollDragUpdate(WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY); +static void widgetScrollPaneOnDragUpdate(WidgetT *w, WidgetT *root, int32_t mouseX, int32_t mouseY); void wgtScrollPaneScrollToChild(WidgetT *w, const WidgetT *child); @@ -527,9 +529,9 @@ void widgetScrollPaneOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy } else if (trackRelY >= thumbPos + thumbSize) { sp->scrollPosV += pageSize; } else { - sDragScrollbar = hit; - sDragScrollbarOrient = 0; - sDragScrollbarOff = trackRelY - thumbPos; + sDragWidget = hit; + sp->sbDragOrient = 0; + sp->sbDragOff = trackRelY - thumbPos; return; } } @@ -571,9 +573,9 @@ void widgetScrollPaneOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy } else if (trackRelX >= thumbPos + thumbSize) { sp->scrollPosH += pageSize; } else { - sDragScrollbar = hit; - sDragScrollbarOrient = 1; - sDragScrollbarOff = trackRelX - thumbPos; + sDragWidget = hit; + sp->sbDragOrient = 1; + sp->sbDragOff = trackRelX - thumbPos; return; } } @@ -626,13 +628,16 @@ void widgetScrollPaneOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy // ============================================================ -// widgetScrollPaneScrollDragUpdate +// widgetScrollPaneOnDragUpdate // ============================================================ // Handle scrollbar thumb drag for vertical and horizontal scrollbars. // Uses spCalcNeeds to determine content and viewport dimensions. -static void widgetScrollPaneScrollDragUpdate(WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY) { - ScrollPaneDataT *sp = (ScrollPaneDataT *)w->data; +static void widgetScrollPaneOnDragUpdate(WidgetT *w, WidgetT *root, int32_t mouseX, int32_t mouseY) { + (void)root; + ScrollPaneDataT *sp = (ScrollPaneDataT *)w->data; + int32_t orient = sp->sbDragOrient; + int32_t dragOff = sp->sbDragOff; AppContextT *ctx = wgtGetContext(w); const BitmapFontT *font = &ctx->font; @@ -782,7 +787,7 @@ static const WidgetClassT sClassScrollPane = { .getText = NULL, .setText = NULL, .scrollChildIntoView = wgtScrollPaneScrollToChild, - .scrollDragUpdate = widgetScrollPaneScrollDragUpdate + .onDragUpdate = widgetScrollPaneOnDragUpdate }; diff --git a/widgets/widgetSlider.c b/widgets/widgetSlider.c index 505fcbe..e57e033 100644 --- a/widgets/widgetSlider.c +++ b/widgets/widgetSlider.c @@ -33,6 +33,7 @@ typedef struct { int32_t minValue; int32_t maxValue; bool vertical; + int32_t dragOffset; } SliderDataT; @@ -152,8 +153,8 @@ void widgetSliderOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { if (mousePos >= thumbPos && mousePos < thumbPos + SLIDER_THUMB_W) { // Click on thumb -- start drag - sDragSlider = hit; - sDragOffset = mousePos - thumbPos; + sDragWidget = hit; + d->dragOffset = mousePos - thumbPos; } else { // Click on track -- jump to position int32_t newVal = d->minValue + ((mousePos - SLIDER_THUMB_W / 2) * range) / thumbRange; @@ -174,8 +175,8 @@ void widgetSliderOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { if (mousePos >= thumbPos && mousePos < thumbPos + SLIDER_THUMB_W) { // Click on thumb -- start drag - sDragSlider = hit; - sDragOffset = mousePos - thumbPos; + sDragWidget = hit; + d->dragOffset = mousePos - thumbPos; } else { // Click on track -- jump to position int32_t newVal = d->minValue + ((mousePos - SLIDER_THUMB_W / 2) * range) / thumbRange; @@ -265,14 +266,14 @@ void widgetSliderPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitma // ============================================================ -// widgetSliderScrollDragUpdate +// widgetSliderOnDragUpdate // ============================================================ // // Called by the event loop during slider thumb drag. Computes the // new value from mouse position and the stored drag offset. -static void widgetSliderScrollDragUpdate(WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY) { - (void)orient; +static void widgetSliderOnDragUpdate(WidgetT *w, WidgetT *root, int32_t mouseX, int32_t mouseY) { + (void)root; SliderDataT *d = (SliderDataT *)w->data; int32_t range = d->maxValue - d->minValue; @@ -284,11 +285,11 @@ static void widgetSliderScrollDragUpdate(WidgetT *w, int32_t orient, int32_t dra if (d->vertical) { int32_t thumbRange = w->h - SLIDER_THUMB_W; - int32_t relY = mouseY - w->y - dragOff; + int32_t relY = mouseY - w->y - d->dragOffset; newVal = d->minValue + (relY * range) / thumbRange; } else { int32_t thumbRange = w->w - SLIDER_THUMB_W; - int32_t relX = mouseX - w->x - dragOff; + int32_t relX = mouseX - w->x - d->dragOffset; newVal = d->minValue + (relX * range) / thumbRange; } @@ -329,7 +330,7 @@ static const WidgetClassT sClassSlider = { .destroy = widgetSliderDestroy, .getText = NULL, .setText = NULL, - .scrollDragUpdate = widgetSliderScrollDragUpdate + .onDragUpdate = widgetSliderOnDragUpdate }; // ============================================================ diff --git a/widgets/widgetSpinner.c b/widgets/widgetSpinner.c index 499c1db..fcf6999 100644 --- a/widgets/widgetSpinner.c +++ b/widgets/widgetSpinner.c @@ -287,7 +287,8 @@ void widgetSpinnerOnKey(WidgetT *w, int32_t key, int32_t mod) { &d->scrollOff, &d->selStart, &d->selEnd, d->undoBuf, &d->undoLen, - &d->undoCursor); + &d->undoCursor, + w->w - SPINNER_BORDER * 2 - SPINNER_BTN_W); // Validate buffer after paste -- reject non-numeric content. // Allow optional leading minus and digits only. diff --git a/widgets/widgetSplitter.c b/widgets/widgetSplitter.c index b683d5d..1a68f6a 100644 --- a/widgets/widgetSplitter.c +++ b/widgets/widgetSplitter.c @@ -38,6 +38,7 @@ static int32_t sTypeId = -1; typedef struct { int32_t dividerPos; bool vertical; + int32_t dragStart; } SplitterDataT; @@ -48,7 +49,7 @@ typedef struct { static WidgetT *spFirstChild(WidgetT *w); static WidgetT *spSecondChild(WidgetT *w); static void widgetSplitterDestroy(WidgetT *w); -static void widgetSplitterScrollDragUpdate(WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY); +static void widgetSplitterOnDragUpdate(WidgetT *w, WidgetT *root, int32_t mouseX, int32_t mouseY); // ============================================================ @@ -248,12 +249,12 @@ void widgetSplitterOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) if (onDivider) { // Start dragging - sDragSplitter = hit; + sDragWidget = hit; if (d->vertical) { - sDragSplitStart = vx - hit->x - pos; + d->dragStart = vx - hit->x - pos; } else { - sDragSplitStart = vy - hit->y - pos; + d->dragStart = vy - hit->y - pos; } return; @@ -380,7 +381,7 @@ int32_t widgetSplitterGetCursorShape(const WidgetT *w, int32_t vx, int32_t vy) { SplitterDataT *d = (SplitterDataT *)w->data; // During active drag, always show resize cursor - if (sDragSplitter == w) { + if (sDragWidget == w) { return d->vertical ? CURSOR_RESIZE_H : CURSOR_RESIZE_V; } @@ -428,18 +429,18 @@ static void widgetSplitterDestroy(WidgetT *w) { // ============================================================ -// widgetSplitterScrollDragUpdate +// widgetSplitterOnDragUpdate // ============================================================ -static void widgetSplitterScrollDragUpdate(WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY) { - (void)orient; +static void widgetSplitterOnDragUpdate(WidgetT *w, WidgetT *root, int32_t mouseX, int32_t mouseY) { + (void)root; SplitterDataT *d = (SplitterDataT *)w->data; int32_t pos; if (d->vertical) { - pos = mouseX - w->x - dragOff; + pos = mouseX - w->x - d->dragStart; } else { - pos = mouseY - w->y - dragOff; + pos = mouseY - w->y - d->dragStart; } widgetSplitterClampPos(w, &pos); @@ -472,7 +473,7 @@ static const WidgetClassT sClassSplitter = { .getText = NULL, .setText = NULL, .getCursorShape = widgetSplitterGetCursorShape, - .scrollDragUpdate = widgetSplitterScrollDragUpdate + .onDragUpdate = widgetSplitterOnDragUpdate }; diff --git a/widgets/widgetTextInput.c b/widgets/widgetTextInput.c index b42706a..42004f4 100644 --- a/widgets/widgetTextInput.c +++ b/widgets/widgetTextInput.c @@ -98,6 +98,9 @@ typedef struct { int32_t undoCursor; int32_t cachedLines; int32_t cachedMaxLL; + int32_t sbDragOrient; + int32_t sbDragOff; + bool sbDragging; } TextAreaDataT; #include @@ -133,7 +136,8 @@ static int32_t textAreaLineStart(const char *buf, int32_t len, int32_t row); static int32_t textAreaMaxLineLen(const char *buf, int32_t len); static void textAreaOffToRowCol(const char *buf, int32_t off, int32_t *row, int32_t *col); static void textEditSaveUndo(char *buf, int32_t len, int32_t cursor, char *undoBuf, int32_t *pUndoLen, int32_t *pUndoCursor, int32_t bufSize); -static void widgetTextAreaScrollDragUpdate(WidgetT *w, int32_t orient, int32_t dragOff, int32_t mouseX, int32_t mouseY); +static void widgetTextAreaDragSelect(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy); +static void widgetTextAreaOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y); static int32_t wordBoundaryLeft(const char *buf, int32_t pos); static int32_t wordBoundaryRight(const char *buf, int32_t len, int32_t pos); WidgetT *wgtTextInput(WidgetT *parent, int32_t maxLen); @@ -1324,7 +1328,7 @@ navigation: // clicks. Content clicks convert pixel coordinates to row/col using // font metrics and scroll offset. Multi-click: double-click selects // word, triple-click selects entire line. Single click starts a -// drag-select (sets sDragTextSelect which the event loop monitors +// drag-select (sets sDragWidget which the event loop monitors // on mouse-move to extend the selection). The drag-select global // is cleared on double/triple click since the selection is already // complete. @@ -1404,9 +1408,10 @@ void widgetTextAreaOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { ta->scrollCol += visCols; ta->scrollCol = clampInt(ta->scrollCol, 0, maxHScroll); } else { - sDragScrollbar = w; - sDragScrollbarOrient = 1; - sDragScrollbarOff = trackRelX - thumbPos; + sDragWidget = w; + ta->sbDragOrient = 1; + ta->sbDragging = true; + ta->sbDragOff = trackRelX - thumbPos; return; } } @@ -1448,9 +1453,10 @@ void widgetTextAreaOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { ta->scrollRow += visRows; ta->scrollRow = clampInt(ta->scrollRow, 0, maxScroll); } else { - sDragScrollbar = w; - sDragScrollbarOrient = 0; - sDragScrollbarOff = trackRelY - thumbPos; + sDragWidget = w; + ta->sbDragOrient = 0; + ta->sbDragging = true; + ta->sbDragOff = trackRelY - thumbPos; return; } } @@ -1495,7 +1501,7 @@ void widgetTextAreaOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { ta->desiredCol = lineL; ta->selAnchor = lineStart; ta->selCursor = lineEnd; - sDragTextSelect = NULL; + sDragWidget = NULL; return; } @@ -1514,7 +1520,7 @@ void widgetTextAreaOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { ta->desiredCol = weCol; ta->selAnchor = ws; ta->selCursor = we; - sDragTextSelect = NULL; + sDragWidget = NULL; return; } @@ -1526,7 +1532,8 @@ void widgetTextAreaOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { int32_t anchorOff = textAreaCursorToOff(ta->buf, ta->len, clickRow, clickCol); ta->selAnchor = anchorOff; ta->selCursor = anchorOff; - sDragTextSelect = w; + sDragWidget = w; + ta->sbDragging = false; } @@ -1909,7 +1916,8 @@ void widgetTextInputOnKey(WidgetT *w, int32_t key, int32_t mod) { &ti->scrollOff, &ti->selStart, &ti->selEnd, ti->undoBuf, &ti->undoLen, - &ti->undoCursor); + &ti->undoCursor, + w->w - TEXT_INPUT_PAD * 2); } @@ -1922,7 +1930,7 @@ void widgetTextInputOnKey(WidgetT *w, int32_t key, int32_t mod) { // scrollOff). Multi-click: double-click selects word (using // wordStart/wordEnd), triple-click selects all. Single click starts // drag-select by setting both selStart and selEnd to the click -// position and registering sDragTextSelect. +// position and registering sDragWidget. void widgetTextInputOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { TextInputDataT *ti = (TextInputDataT *)w->data; w->focused = true; @@ -2007,15 +2015,6 @@ void widgetTextInputSetText(WidgetT *w, const char *text) { } -// ============================================================ -// widgetTextInputGetFieldWidth -// ============================================================ - -int32_t widgetTextInputGetFieldWidth(const WidgetT *w) { - return w->w - TEXT_INPUT_PAD * 2; -} - - // ============================================================ // DXE registration // ============================================================ @@ -2034,7 +2033,7 @@ static bool widgetTextInputClearSelection(WidgetT *w) { } -static void widgetTextInputDragSelect(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { +static void widgetTextInputOnDragUpdate(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) { (void)root; (void)vy; TextInputDataT *ti = (TextInputDataT *)w->data; @@ -2057,8 +2056,7 @@ static const WidgetClassT sClassTextInput = { .getText = widgetTextInputGetText, .setText = widgetTextInputSetText, .clearSelection = widgetTextInputClearSelection, - .dragSelect = widgetTextInputDragSelect, - .getTextFieldWidth = widgetTextInputGetFieldWidth + .onDragUpdate = widgetTextInputOnDragUpdate }; // ============================================================ @@ -2129,6 +2127,17 @@ static void widgetTextAreaScrollDragUpdate(WidgetT *w, int32_t orient, int32_t d } +static void widgetTextAreaOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + TextAreaDataT *ta = (TextAreaDataT *)w->data; + + if (ta->sbDragging) { + widgetTextAreaScrollDragUpdate(w, ta->sbDragOrient, ta->sbDragOff, x, y); + } else { + widgetTextAreaDragSelect(w, root, x, y); + } +} + + static bool widgetTextAreaClearSelection(WidgetT *w) { TextAreaDataT *ta = (TextAreaDataT *)w->data; @@ -2203,8 +2212,7 @@ static const WidgetClassT sClassTextArea = { .getText = widgetTextAreaGetText, .setText = widgetTextAreaSetText, .clearSelection = widgetTextAreaClearSelection, - .dragSelect = widgetTextAreaDragSelect, - .scrollDragUpdate = widgetTextAreaScrollDragUpdate + .onDragUpdate = widgetTextAreaOnDragUpdate }; // ============================================================ diff --git a/widgets/widgetTreeView.c b/widgets/widgetTreeView.c index 04d8112..0f80c18 100644 --- a/widgets/widgetTreeView.c +++ b/widgets/widgetTreeView.c @@ -72,6 +72,8 @@ typedef struct { int32_t cachedTotalHeight; int32_t cachedMaxWidth; bool dimsValid; + int32_t sbDragOrient; + int32_t sbDragOff; } TreeViewDataT; typedef struct { @@ -1028,9 +1030,9 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) int32_t thumbSize; widgetScrollbarThumb(trackLen, totalH, innerH, tv->scrollPos, &thumbPos, &thumbSize); - sDragScrollbar = hit; - sDragScrollbarOrient = 0; - sDragScrollbarOff = relY - WGT_SB_W - thumbPos; + sDragWidget = hit; + tv->sbDragOrient = 0; + tv->sbDragOff = relY - WGT_SB_W - thumbPos; } tv->scrollPos = clampInt(tv->scrollPos, 0, maxScrollV); @@ -1066,9 +1068,9 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) int32_t thumbSize; widgetScrollbarThumb(trackLen, totalW, innerW, tv->scrollPosH, &thumbPos, &thumbSize); - sDragScrollbar = hit; - sDragScrollbarOrient = 1; - sDragScrollbarOff = relX - WGT_SB_W - thumbPos; + sDragWidget = hit; + tv->sbDragOrient = 1; + tv->sbDragOff = relX - WGT_SB_W - thumbPos; } tv->scrollPosH = clampInt(tv->scrollPosH, 0, maxScrollH); @@ -1192,7 +1194,7 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) if (tv->reorderable && !clickedExpandIcon && !shift && !ctrl) { tv->dragItem = item; tv->dropTarget = NULL; - sDragReorder = hit; + sDragWidget = hit; } } @@ -1483,6 +1485,40 @@ static void widgetTreeViewReorderDrop(WidgetT *w) { } +// ============================================================ +// widgetTreeViewOnDragEnd +// ============================================================ + +static void widgetTreeViewOnDragEnd(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + (void)root; + (void)x; + (void)y; + TreeViewDataT *tv = (TreeViewDataT *)w->data; + + if (tv->dragItem) { + widgetTreeViewReorderDrop(w); + tv->dragItem = NULL; + } + + wgtInvalidatePaint(w); +} + + +// ============================================================ +// widgetTreeViewOnDragUpdate +// ============================================================ + +static void widgetTreeViewOnDragUpdate(WidgetT *w, WidgetT *root, int32_t x, int32_t y) { + TreeViewDataT *tv = (TreeViewDataT *)w->data; + + if (tv->dragItem) { + widgetTreeViewReorderUpdate(w, root, x, y); + } else { + widgetTreeViewScrollDragUpdate(w, tv->sbDragOrient, tv->sbDragOff, x, y); + } +} + + static const WidgetClassT sClassTreeView = { .flags = WCLASS_FOCUSABLE | WCLASS_PAINTS_CHILDREN | WCLASS_NO_HIT_RECURSE | WCLASS_SCROLLABLE, .paint = widgetTreeViewPaint, @@ -1495,9 +1531,8 @@ static const WidgetClassT sClassTreeView = { .getText = NULL, .setText = NULL, .onChildChanged = widgetTreeViewOnChildChanged, - .reorderDrop = widgetTreeViewReorderDrop, - .reorderUpdate = widgetTreeViewReorderUpdate, - .scrollDragUpdate = widgetTreeViewScrollDragUpdate + .onDragUpdate = widgetTreeViewOnDragUpdate, + .onDragEnd = widgetTreeViewOnDragEnd }; static const WidgetClassT sClassTreeItem = {