More optimizing.
This commit is contained in:
parent
54d9180d3e
commit
e489f54ef0
17 changed files with 118 additions and 74 deletions
25
dvx/dvxApp.c
25
dvx/dvxApp.c
|
|
@ -137,8 +137,6 @@ static void compositeAndFlush(AppContextT *ctx) {
|
||||||
RectT popIsect;
|
RectT popIsect;
|
||||||
|
|
||||||
if (rectIntersect(dr, &popRect, &popIsect)) {
|
if (rectIntersect(dr, &popRect, &popIsect)) {
|
||||||
setClipRect(d, dr->x, dr->y, dr->w, dr->h);
|
|
||||||
|
|
||||||
// Find the window and menu
|
// Find the window and menu
|
||||||
for (int32_t j = 0; j < ws->count; j++) {
|
for (int32_t j = 0; j < ws->count; j++) {
|
||||||
if (ws->windows[j]->id == ctx->popup.windowId) {
|
if (ws->windows[j]->id == ctx->popup.windowId) {
|
||||||
|
|
@ -202,8 +200,6 @@ static void compositeAndFlush(AppContextT *ctx) {
|
||||||
RectT smIsect;
|
RectT smIsect;
|
||||||
|
|
||||||
if (rectIntersect(dr, &smRect, &smIsect)) {
|
if (rectIntersect(dr, &smRect, &smIsect)) {
|
||||||
setClipRect(d, dr->x, dr->y, dr->w, dr->h);
|
|
||||||
|
|
||||||
BevelStyleT smBevel;
|
BevelStyleT smBevel;
|
||||||
smBevel.highlight = ctx->colors.windowHighlight;
|
smBevel.highlight = ctx->colors.windowHighlight;
|
||||||
smBevel.shadow = ctx->colors.windowShadow;
|
smBevel.shadow = ctx->colors.windowShadow;
|
||||||
|
|
@ -465,10 +461,10 @@ static void dispatchEvents(AppContextT *ctx) {
|
||||||
if (mx != ctx->prevMouseX || my != ctx->prevMouseY) {
|
if (mx != ctx->prevMouseX || my != ctx->prevMouseY) {
|
||||||
dirtyCursorArea(ctx, ctx->prevMouseX, ctx->prevMouseY);
|
dirtyCursorArea(ctx, ctx->prevMouseX, ctx->prevMouseY);
|
||||||
dirtyCursorArea(ctx, mx, my);
|
dirtyCursorArea(ctx, mx, my);
|
||||||
}
|
|
||||||
|
|
||||||
// Update cursor shape based on what the mouse is hovering over
|
// Update cursor shape based on what the mouse is hovering over
|
||||||
updateCursorShape(ctx);
|
updateCursorShape(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle active drag
|
// Handle active drag
|
||||||
if (ctx->stack.dragWindow >= 0) {
|
if (ctx->stack.dragWindow >= 0) {
|
||||||
|
|
@ -1380,9 +1376,16 @@ static void pollAnsiTermWidgetsWalk(AppContextT *ctx, WidgetT *w, WindowT *win)
|
||||||
static void pollKeyboard(AppContextT *ctx) {
|
static void pollKeyboard(AppContextT *ctx) {
|
||||||
__dpmi_regs r;
|
__dpmi_regs r;
|
||||||
|
|
||||||
// Check if key is available (INT 16h, enhanced function 11h)
|
// Read shift state once per poll (INT 16h, AH=12h)
|
||||||
while (1) {
|
|
||||||
memset(&r, 0, sizeof(r));
|
memset(&r, 0, sizeof(r));
|
||||||
|
r.x.ax = 0x1200;
|
||||||
|
__dpmi_int(0x16, &r);
|
||||||
|
int32_t shiftFlags = r.x.ax & 0xFF;
|
||||||
|
bool shiftHeld = (shiftFlags & 0x03) != 0; // left or right shift
|
||||||
|
|
||||||
|
// Process buffered keys
|
||||||
|
while (1) {
|
||||||
|
// Check if key is available (INT 16h, enhanced function 11h)
|
||||||
r.x.ax = 0x1100;
|
r.x.ax = 0x1100;
|
||||||
__dpmi_int(0x16, &r);
|
__dpmi_int(0x16, &r);
|
||||||
|
|
||||||
|
|
@ -1392,7 +1395,6 @@ static void pollKeyboard(AppContextT *ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the key (INT 16h, enhanced function 10h)
|
// Read the key (INT 16h, enhanced function 10h)
|
||||||
memset(&r, 0, sizeof(r));
|
|
||||||
r.x.ax = 0x1000;
|
r.x.ax = 0x1000;
|
||||||
__dpmi_int(0x16, &r);
|
__dpmi_int(0x16, &r);
|
||||||
|
|
||||||
|
|
@ -1406,13 +1408,6 @@ static void pollKeyboard(AppContextT *ctx) {
|
||||||
ascii = 0;
|
ascii = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read shift state (INT 16h, AH=12h — enhanced shift flags)
|
|
||||||
memset(&r, 0, sizeof(r));
|
|
||||||
r.x.ax = 0x1200;
|
|
||||||
__dpmi_int(0x16, &r);
|
|
||||||
int32_t shiftFlags = r.x.ax & 0xFF;
|
|
||||||
bool shiftHeld = (shiftFlags & 0x03) != 0; // left or right shift
|
|
||||||
|
|
||||||
// Alt+Tab / Shift+Alt+Tab — cycle windows
|
// Alt+Tab / Shift+Alt+Tab — cycle windows
|
||||||
// Alt+Tab: scancode=0xA5, ascii=0x00
|
// Alt+Tab: scancode=0xA5, ascii=0x00
|
||||||
if (ascii == 0 && scancode == 0xA5) {
|
if (ascii == 0 && scancode == 0xA5) {
|
||||||
|
|
|
||||||
|
|
@ -77,12 +77,15 @@ void dirtyListMerge(DirtyListT *dl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Single-pass O(N²): for each rect, try to merge it into an
|
||||||
|
// earlier rect. When a merge succeeds the merged rect may now
|
||||||
|
// overlap others, so restart the inner scan for that slot.
|
||||||
|
for (int32_t i = 0; i < dl->count; i++) {
|
||||||
bool merged = true;
|
bool merged = true;
|
||||||
|
|
||||||
while (merged) {
|
while (merged) {
|
||||||
merged = false;
|
merged = false;
|
||||||
|
|
||||||
for (int32_t i = 0; i < dl->count; i++) {
|
|
||||||
for (int32_t j = i + 1; j < dl->count; j++) {
|
for (int32_t j = i + 1; j < dl->count; j++) {
|
||||||
if (rectsOverlapOrAdjacent(&dl->rects[i], &dl->rects[j], DIRTY_MERGE_GAP)) {
|
if (rectsOverlapOrAdjacent(&dl->rects[i], &dl->rects[j], DIRTY_MERGE_GAP)) {
|
||||||
rectUnion(&dl->rects[i], &dl->rects[j], &dl->rects[i]);
|
rectUnion(&dl->rects[i], &dl->rects[j], &dl->rects[i]);
|
||||||
|
|
@ -104,15 +107,12 @@ void dirtyListMerge(DirtyListT *dl) {
|
||||||
void flushRect(DisplayT *d, const RectT *r) {
|
void flushRect(DisplayT *d, const RectT *r) {
|
||||||
int32_t bpp = d->format.bytesPerPixel;
|
int32_t bpp = d->format.bytesPerPixel;
|
||||||
|
|
||||||
|
// Caller (compositeAndFlush) already clips to screen bounds
|
||||||
int32_t x = r->x;
|
int32_t x = r->x;
|
||||||
int32_t y = r->y;
|
int32_t y = r->y;
|
||||||
int32_t w = r->w;
|
int32_t w = r->w;
|
||||||
int32_t h = r->h;
|
int32_t h = r->h;
|
||||||
|
|
||||||
if (__builtin_expect(x < 0, 0)) { w += x; x = 0; }
|
|
||||||
if (__builtin_expect(y < 0, 0)) { h += y; y = 0; }
|
|
||||||
if (__builtin_expect(x + w > d->width, 0)) { w = d->width - x; }
|
|
||||||
if (__builtin_expect(y + h > d->height, 0)) { h = d->height - y; }
|
|
||||||
if (__builtin_expect(w <= 0 || h <= 0, 0)) { return; }
|
if (__builtin_expect(w <= 0 || h <= 0, 0)) { return; }
|
||||||
|
|
||||||
int32_t rowBytes = w * bpp;
|
int32_t rowBytes = w * bpp;
|
||||||
|
|
|
||||||
|
|
@ -576,6 +576,9 @@ int32_t wgtAnsiTermRepaint(WidgetT *w, int32_t *outY, int32_t *outH);
|
||||||
// Mark a widget (and ancestors) for relayout and repaint
|
// Mark a widget (and ancestors) for relayout and repaint
|
||||||
void wgtInvalidate(WidgetT *w);
|
void wgtInvalidate(WidgetT *w);
|
||||||
|
|
||||||
|
// Repaint only — skip measure/layout (use for visual-only changes)
|
||||||
|
void wgtInvalidatePaint(WidgetT *w);
|
||||||
|
|
||||||
// Set/get widget text (label, button, textInput, etc.)
|
// Set/get widget text (label, button, textInput, etc.)
|
||||||
void wgtSetText(WidgetT *w, const char *text);
|
void wgtSetText(WidgetT *w, const char *text);
|
||||||
const char *wgtGetText(const WidgetT *w);
|
const char *wgtGetText(const WidgetT *w);
|
||||||
|
|
|
||||||
|
|
@ -1553,7 +1553,7 @@ void widgetAnsiTermOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
if (ansiTermHasSelection(w)) {
|
if (ansiTermHasSelection(w)) {
|
||||||
ansiTermCopySelection(w);
|
ansiTermCopySelection(w);
|
||||||
ansiTermClearSelection(w);
|
ansiTermClearSelection(w);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1563,7 +1563,7 @@ void widgetAnsiTermOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
// Ctrl+V: paste from clipboard to terminal
|
// Ctrl+V: paste from clipboard to terminal
|
||||||
if (key == 0x16 && (mod & KEY_MOD_CTRL)) {
|
if (key == 0x16 && (mod & KEY_MOD_CTRL)) {
|
||||||
ansiTermPasteToComm(w);
|
ansiTermPasteToComm(w);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1645,7 +1645,7 @@ void widgetAnsiTermOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->as.ansiTerm.commWrite(w->as.ansiTerm.commCtx, buf, len);
|
w->as.ansiTerm.commWrite(w->as.ansiTerm.commCtx, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1822,8 +1822,18 @@ void widgetAnsiTermPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bit
|
||||||
// Determine if viewing live terminal or scrollback
|
// Determine if viewing live terminal or scrollback
|
||||||
bool viewingLive = (w->as.ansiTerm.scrollPos == sbCount);
|
bool viewingLive = (w->as.ansiTerm.scrollPos == sbCount);
|
||||||
|
|
||||||
// Render character cells row by row using bulk renderer
|
// Render character cells row by row using bulk renderer.
|
||||||
|
// Only repaint rows marked dirty; 0xFFFFFFFF means all rows.
|
||||||
|
uint32_t dirty = w->as.ansiTerm.dirtyRows;
|
||||||
|
if (dirty == 0) {
|
||||||
|
dirty = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
for (int32_t row = 0; row < rows; row++) {
|
for (int32_t row = 0; row < rows; row++) {
|
||||||
|
if (row < 32 && !(dirty & (1U << row))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t lineIndex = w->as.ansiTerm.scrollPos + row;
|
int32_t lineIndex = w->as.ansiTerm.scrollPos + row;
|
||||||
const uint8_t *lineData = ansiTermGetLine(w, lineIndex);
|
const uint8_t *lineData = ansiTermGetLine(w, lineIndex);
|
||||||
|
|
||||||
|
|
@ -1838,6 +1848,8 @@ void widgetAnsiTermPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bit
|
||||||
ansiTermPaintSelRow(w, d, ops, font, row, baseX, baseY);
|
ansiTermPaintSelRow(w, d, ops, font, row, baseX, baseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w->as.ansiTerm.dirtyRows = 0;
|
||||||
|
|
||||||
// Draw scrollbar
|
// Draw scrollbar
|
||||||
int32_t sbX = baseX + cols * cellW;
|
int32_t sbX = baseX + cols * cellW;
|
||||||
int32_t sbY = baseY;
|
int32_t sbY = baseY;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ void widgetButtonOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
if (key == ' ' || key == 0x0D) {
|
if (key == ' ' || key == 0x0D) {
|
||||||
w->as.button.pressed = true;
|
w->as.button.pressed = true;
|
||||||
sKeyPressedBtn = w;
|
sKeyPressedBtn = w;
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -709,7 +709,7 @@ void widgetCanvasOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) {
|
||||||
hit->as.canvas.lastX = cx;
|
hit->as.canvas.lastX = cx;
|
||||||
hit->as.canvas.lastY = cy;
|
hit->as.canvas.lastY = cy;
|
||||||
|
|
||||||
wgtInvalidate(hit);
|
wgtInvalidatePaint(hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ void widgetCheckboxOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->onChange(w);
|
w->onChange(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ void widgetComboBoxOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ void widgetComboBoxOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,7 +194,7 @@ void widgetComboBoxOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->onChange(w);
|
w->onChange(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +213,7 @@ void widgetComboBoxOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->as.comboBox.listScrollPos = w->as.comboBox.hoverIdx;
|
w->as.comboBox.listScrollPos = w->as.comboBox.hoverIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -426,7 +426,7 @@ void widgetComboBoxPaintPopup(WidgetT *w, DisplayT *d, const BlitOpsT *ops, cons
|
||||||
rectFill(d, ops, popX + 2, iy, textW + TEXT_INPUT_PAD * 2, font->charHeight, ibg);
|
rectFill(d, ops, popX + 2, iy, textW + TEXT_INPUT_PAD * 2, font->charHeight, ibg);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawText(d, ops, font, textX, iy, items[idx], ifg, ibg, idx == hoverIdx);
|
drawText(d, ops, font, textX, iy, items[idx], ifg, ibg, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ void widgetDropdownOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -280,6 +280,6 @@ void widgetDropdownPaintPopup(WidgetT *w, DisplayT *d, const BlitOpsT *ops, cons
|
||||||
rectFill(d, ops, popX + 2, iy, textW + TEXT_INPUT_PAD * 2, font->charHeight, ibg);
|
rectFill(d, ops, popX + 2, iy, textW + TEXT_INPUT_PAD * 2, font->charHeight, ibg);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawText(d, ops, font, textX, iy, items[idx], ifg, ibg, idx == hoverIdx);
|
drawText(d, ops, font, textX, iy, items[idx], ifg, ibg, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,21 +192,21 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
||||||
sDrawingCanvas->as.canvas.lastX = -1;
|
sDrawingCanvas->as.canvas.lastX = -1;
|
||||||
sDrawingCanvas->as.canvas.lastY = -1;
|
sDrawingCanvas->as.canvas.lastY = -1;
|
||||||
sDrawingCanvas = NULL;
|
sDrawingCanvas = NULL;
|
||||||
wgtInvalidate(root);
|
wgtInvalidatePaint(root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle canvas drawing (mouse move while pressed)
|
// Handle canvas drawing (mouse move while pressed)
|
||||||
if (sDrawingCanvas && (buttons & 1)) {
|
if (sDrawingCanvas && (buttons & 1)) {
|
||||||
widgetCanvasOnMouse(sDrawingCanvas, root, x, y);
|
widgetCanvasOnMouse(sDrawingCanvas, root, x, y);
|
||||||
wgtInvalidate(root);
|
wgtInvalidatePaint(root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle slider drag release
|
// Handle slider drag release
|
||||||
if (sDragSlider && !(buttons & 1)) {
|
if (sDragSlider && !(buttons & 1)) {
|
||||||
sDragSlider = NULL;
|
sDragSlider = NULL;
|
||||||
wgtInvalidate(root);
|
wgtInvalidatePaint(root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,7 +242,7 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
||||||
sDragSlider->onChange(sDragSlider);
|
sDragSlider->onChange(sDragSlider);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(root);
|
wgtInvalidatePaint(root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,7 +272,7 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(sPressedButton);
|
wgtInvalidatePaint(sPressedButton);
|
||||||
sPressedButton = NULL;
|
sPressedButton = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +302,7 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
||||||
sPressedButton->as.button.pressed = over;
|
sPressedButton->as.button.pressed = over;
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(sPressedButton);
|
wgtInvalidatePaint(sPressedButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -376,7 +376,7 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sOpenPopup = NULL;
|
sOpenPopup = NULL;
|
||||||
wgtInvalidate(root);
|
wgtInvalidatePaint(root);
|
||||||
// Fall through to normal click handling
|
// Fall through to normal click handling
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ void widgetImageOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) {
|
||||||
(void)vx;
|
(void)vx;
|
||||||
(void)vy;
|
(void)vy;
|
||||||
w->as.image.pressed = true;
|
w->as.image.pressed = true;
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
|
|
||||||
if (w->onClick) {
|
if (w->onClick) {
|
||||||
w->onClick(w);
|
w->onClick(w);
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ void widgetImageButtonOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
if (key == ' ' || key == 0x0D) {
|
if (key == ' ' || key == 0x0D) {
|
||||||
w->as.imageButton.pressed = true;
|
w->as.imageButton.pressed = true;
|
||||||
sKeyPressedBtn = w;
|
sKeyPressedBtn = w;
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ void widgetListBoxOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->onChange(w);
|
w->onChange(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -292,7 +292,7 @@ void widgetListBoxPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitm
|
||||||
rectFill(d, ops, w->x + LISTBOX_BORDER, iy, contentW, font->charHeight, ibg);
|
rectFill(d, ops, w->x + LISTBOX_BORDER, iy, contentW, font->charHeight, ibg);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawText(d, ops, font, innerX, iy, w->as.listBox.items[idx], ifg, ibg, idx == w->as.listBox.selectedIdx);
|
drawText(d, ops, font, innerX, iy, w->as.listBox.items[idx], ifg, ibg, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw scrollbar
|
// Draw scrollbar
|
||||||
|
|
|
||||||
|
|
@ -250,6 +250,40 @@ void wgtInvalidate(WidgetT *w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// wgtInvalidatePaint
|
||||||
|
// ============================================================
|
||||||
|
//
|
||||||
|
// Lightweight repaint — skips measure/layout/scrollbar management.
|
||||||
|
// Use when only visual state changed (slider value, cursor blink,
|
||||||
|
// selection highlight, checkbox toggle) but widget sizes are stable.
|
||||||
|
|
||||||
|
void wgtInvalidatePaint(WidgetT *w) {
|
||||||
|
if (!w || !w->window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetT *root = w;
|
||||||
|
|
||||||
|
while (root->parent) {
|
||||||
|
root = root->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppContextT *ctx = (AppContextT *)root->userData;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repaint without measure/layout
|
||||||
|
RectT fullRect = {0, 0, w->window->contentW, w->window->contentH};
|
||||||
|
widgetOnPaint(w->window, &fullRect);
|
||||||
|
w->window->contentDirty = true;
|
||||||
|
|
||||||
|
dvxInvalidateWindow(ctx, w->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// wgtPaint
|
// wgtPaint
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ void widgetRadioOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
} else if (key == (0x50 | 0x100) || key == (0x4D | 0x100)) {
|
} else if (key == (0x50 | 0x100) || key == (0x4D | 0x100)) {
|
||||||
// Down or Right — next radio in group
|
// Down or Right — next radio in group
|
||||||
if (w->parent && w->parent->type == WidgetRadioGroupE) {
|
if (w->parent && w->parent->type == WidgetRadioGroupE) {
|
||||||
|
|
@ -115,7 +115,7 @@ void widgetRadioOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
next->parent->onChange(next->parent);
|
next->parent->onChange(next->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(next);
|
wgtInvalidatePaint(next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (key == (0x48 | 0x100) || key == (0x4B | 0x100)) {
|
} else if (key == (0x48 | 0x100) || key == (0x4B | 0x100)) {
|
||||||
|
|
@ -139,7 +139,7 @@ void widgetRadioOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
prev->parent->onChange(prev->parent);
|
prev->parent->onChange(prev->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(prev);
|
wgtInvalidatePaint(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ void widgetSliderOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->onChange(w);
|
w->onChange(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -697,7 +697,7 @@ done:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -948,7 +948,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
textAreaOffToRowCol(buf, *pLen, pRow, pCol);
|
textAreaOffToRowCol(buf, *pLen, pRow, pCol);
|
||||||
w->as.textArea.desiredCol = *pCol;
|
w->as.textArea.desiredCol = *pCol;
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -996,7 +996,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1023,7 +1023,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1067,7 +1067,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1105,7 +1105,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1144,7 +1144,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1181,7 +1181,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1197,7 +1197,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->as.textArea.desiredCol = *pCol;
|
w->as.textArea.desiredCol = *pCol;
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1213,7 +1213,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->as.textArea.desiredCol = *pCol;
|
w->as.textArea.desiredCol = *pCol;
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1229,7 +1229,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
|
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1245,7 +1245,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
|
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1256,7 +1256,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->as.textArea.desiredCol = 0;
|
w->as.textArea.desiredCol = 0;
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1267,7 +1267,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->as.textArea.desiredCol = *pCol;
|
w->as.textArea.desiredCol = *pCol;
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1284,7 +1284,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
*pCol = w->as.textArea.desiredCol < lineL ? w->as.textArea.desiredCol : lineL;
|
*pCol = w->as.textArea.desiredCol < lineL ? w->as.textArea.desiredCol : lineL;
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1301,7 +1301,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
*pCol = w->as.textArea.desiredCol < lineL ? w->as.textArea.desiredCol : lineL;
|
*pCol = w->as.textArea.desiredCol < lineL ? w->as.textArea.desiredCol : lineL;
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1313,7 +1313,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->as.textArea.desiredCol = 0;
|
w->as.textArea.desiredCol = 0;
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1324,7 +1324,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->as.textArea.desiredCol = *pCol;
|
w->as.textArea.desiredCol = *pCol;
|
||||||
SEL_END();
|
SEL_END();
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1361,7 +1361,7 @@ void widgetTextAreaOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
}
|
}
|
||||||
|
|
||||||
textAreaEnsureVisible(w, visRows, visCols);
|
textAreaEnsureVisible(w, visRows, visCols);
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2520,5 +2520,5 @@ adjustScroll:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidate(w);
|
wgtInvalidatePaint(w);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue