VTable optimizations
This commit is contained in:
parent
0ceae99da3
commit
8886cee933
28 changed files with 374 additions and 493 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ typedef struct {
|
|||
bool reorderable;
|
||||
int32_t dragIdx;
|
||||
int32_t dropIdx;
|
||||
int32_t sbDragOrient;
|
||||
int32_t sbDragOff;
|
||||
} ListBoxDataT;
|
||||
|
||||
#include <stdlib.h>
|
||||
|
|
@ -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
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <ctype.h>
|
||||
|
|
@ -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
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue