diff --git a/dvx/dvxApp.c b/dvx/dvxApp.c index e088044..03f11b8 100644 --- a/dvx/dvxApp.c +++ b/dvx/dvxApp.c @@ -1959,13 +1959,7 @@ static void pollKeyboard(AppContextT *ctx) { win->vScroll->value = virtY + next->h - win->contentH; } - if (win->vScroll->value < win->vScroll->min) { - win->vScroll->value = win->vScroll->min; - } - - if (win->vScroll->value > win->vScroll->max) { - win->vScroll->value = win->vScroll->max; - } + win->vScroll->value = clampInt(win->vScroll->value, win->vScroll->min, win->vScroll->max); } if (win->hScroll) { @@ -1975,13 +1969,7 @@ static void pollKeyboard(AppContextT *ctx) { win->hScroll->value = virtX + next->w - win->contentW; } - if (win->hScroll->value < win->hScroll->min) { - win->hScroll->value = win->hScroll->min; - } - - if (win->hScroll->value > win->hScroll->max) { - win->hScroll->value = win->hScroll->max; - } + win->hScroll->value = clampInt(win->hScroll->value, win->hScroll->min, win->hScroll->max); } wgtInvalidate(win->widgetRoot); diff --git a/dvx/dvxDraw.c b/dvx/dvxDraw.c index 0b29720..b9d8c5a 100644 --- a/dvx/dvxDraw.c +++ b/dvx/dvxDraw.c @@ -10,7 +10,6 @@ char accelParse(const char *text); static inline void clipRect(const DisplayT *d, int32_t *x, int32_t *y, int32_t *w, int32_t *h); -void drawFocusRect(DisplayT *d, const BlitOpsT *ops, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color); static inline void putPixel(uint8_t *dst, uint32_t color, int32_t bpp); static void spanCopy8(uint8_t *dst, const uint8_t *src, int32_t count); static void spanCopy16(uint8_t *dst, const uint8_t *src, int32_t count); diff --git a/dvx/dvxTypes.h b/dvx/dvxTypes.h index 130e8d7..5f80c5c 100644 --- a/dvx/dvxTypes.h +++ b/dvx/dvxTypes.h @@ -77,6 +77,11 @@ typedef struct { int32_t width; // border thickness in pixels (typically 2) } BevelStyleT; +// Convenience initializers for common bevel styles (C99 compound literals) +#define BEVEL_RAISED(cs, bw) (BevelStyleT){ (cs)->windowHighlight, (cs)->windowShadow, (cs)->windowFace, (bw) } +#define BEVEL_SUNKEN(cs, face, bw) (BevelStyleT){ (cs)->windowShadow, (cs)->windowHighlight, (face), (bw) } +#define BEVEL_TROUGH(cs) (BevelStyleT){ (cs)->windowShadow, (cs)->windowHighlight, (cs)->scrollbarTrough, 1 } + // ============================================================ // Bitmap font // ============================================================ diff --git a/dvx/dvxVideo.c b/dvx/dvxVideo.c index 263ba9d..7c9264f 100644 --- a/dvx/dvxVideo.c +++ b/dvx/dvxVideo.c @@ -21,6 +21,7 @@ static int32_t findBestMode(int32_t requestedW, int32_t requestedH, int32_t pref static void getModeInfo(uint16_t mode, DisplayT *d, int32_t *score, int32_t requestedW, int32_t requestedH, int32_t preferredBpp); static int32_t mapLfb(DisplayT *d, uint32_t physAddr); static int32_t setVesaMode(uint16_t mode); +static void videoSetPalette(const uint8_t *pal, int32_t firstEntry, int32_t count); // ============================================================ @@ -160,10 +161,6 @@ static void getModeInfo(uint16_t mode, DisplayT *d, int32_t *score, int32_t requ // Must be a supported bpp if (bpp != 8 && bpp != 15 && bpp != 16 && bpp != 32) { - // Some cards report 24-bit; skip those - if (bpp == 24) { - return; - } return; } @@ -220,17 +217,6 @@ static void getModeInfo(uint16_t mode, DisplayT *d, int32_t *score, int32_t requ d->format.blueBits = blueSize; d->format.blueShift = bluePos; d->format.blueMask = ((1U << blueSize) - 1) << bluePos; - } else { - // 8-bit mode — masks not used, packColor returns palette index - d->format.redBits = 0; - d->format.redShift = 0; - d->format.redMask = 0; - d->format.greenBits = 0; - d->format.greenShift = 0; - d->format.greenMask = 0; - d->format.blueBits = 0; - d->format.blueShift = 0; - d->format.blueMask = 0; } // Store physical address in lfb field temporarily (will be remapped) @@ -404,7 +390,7 @@ int32_t videoInit(DisplayT *d, int32_t requestedW, int32_t requestedH, int32_t p // videoSetPalette // ============================================================ -void videoSetPalette(const uint8_t *pal, int32_t firstEntry, int32_t count) { +static void videoSetPalette(const uint8_t *pal, int32_t firstEntry, int32_t count) { // Set VGA DAC registers directly via port I/O // Port 0x3C8 = write index, Port 0x3C9 = data (R, G, B in 6-bit values) outportb(0x3C8, (uint8_t)firstEntry); diff --git a/dvx/dvxVideo.h b/dvx/dvxVideo.h index 59927b7..a91d386 100644 --- a/dvx/dvxVideo.h +++ b/dvx/dvxVideo.h @@ -22,7 +22,4 @@ void setClipRect(DisplayT *d, int32_t x, int32_t y, int32_t w, int32_t h); // Reset clip rectangle to full display void resetClipRect(DisplayT *d); -// Set VGA DAC palette (8-bit mode only) -void videoSetPalette(const uint8_t *pal, int32_t firstEntry, int32_t count); - #endif // DVX_VIDEO_H diff --git a/dvx/widgets/widgetCanvas.c b/dvx/widgets/widgetCanvas.c index f999e48..30b6e9b 100644 --- a/dvx/widgets/widgetCanvas.c +++ b/dvx/widgets/widgetCanvas.c @@ -16,6 +16,35 @@ static void canvasDrawLine(WidgetT *w, int32_t x0, int32_t y0, int32_t x1, int32 static void canvasUnpackColor(const DisplayT *d, uint32_t pixel, uint8_t *r, uint8_t *g, uint8_t *b); +// ============================================================ +// canvasPutPixel +// ============================================================ +// +// Write a single pixel of the given color at dst, respecting the display's +// bytes-per-pixel depth. + +static inline uint32_t canvasGetPixel(const uint8_t *src, int32_t bpp) { + if (bpp == 1) { + return *src; + } else if (bpp == 2) { + return *(const uint16_t *)src; + } else { + return *(const uint32_t *)src; + } +} + + +static inline void canvasPutPixel(uint8_t *dst, uint32_t color, int32_t bpp) { + if (bpp == 1) { + *dst = (uint8_t)color; + } else if (bpp == 2) { + *(uint16_t *)dst = (uint16_t)color; + } else { + *(uint32_t *)dst = color; + } +} + + // ============================================================ // canvasDrawDot // ============================================================ @@ -36,13 +65,7 @@ static void canvasDrawDot(WidgetT *w, int32_t cx, int32_t cy) { if (cx >= 0 && cx < cw && cy >= 0 && cy < ch) { uint8_t *dst = data + cy * pitch + cx * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } return; @@ -68,13 +91,7 @@ static void canvasDrawDot(WidgetT *w, int32_t cx, int32_t cy) { if (dx * dx + dy * dy <= r2) { uint8_t *dst = data + py * pitch + px * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } } } @@ -186,13 +203,7 @@ WidgetT *wgtCanvas(WidgetT *parent, int32_t w, int32_t h) { for (int32_t x = 0; x < w; x++) { uint8_t *dst = data + y * pitch + x * bpp; - if (bpp == 1) { - *dst = (uint8_t)white; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)white; - } else { - *(uint32_t *)dst = white; - } + canvasPutPixel(dst, white, bpp); } } @@ -233,13 +244,7 @@ void wgtCanvasClear(WidgetT *w, uint32_t color) { for (int32_t x = 0; x < cw; x++) { uint8_t *dst = w->as.canvas.data + y * pitch + x * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } } } @@ -291,13 +296,7 @@ void wgtCanvasDrawRect(WidgetT *w, int32_t x, int32_t y, int32_t width, int32_t if (y >= 0 && y < ch) { uint8_t *dst = data + y * pitch + px * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } int32_t by = y + height - 1; @@ -305,13 +304,7 @@ void wgtCanvasDrawRect(WidgetT *w, int32_t x, int32_t y, int32_t width, int32_t if (by >= 0 && by < ch && by != y) { uint8_t *dst = data + by * pitch + px * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } } @@ -324,13 +317,7 @@ void wgtCanvasDrawRect(WidgetT *w, int32_t x, int32_t y, int32_t width, int32_t if (x >= 0 && x < cw) { uint8_t *dst = data + py * pitch + x * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } int32_t rx = x + width - 1; @@ -338,13 +325,7 @@ void wgtCanvasDrawRect(WidgetT *w, int32_t x, int32_t y, int32_t width, int32_t if (rx >= 0 && rx < cw && rx != x) { uint8_t *dst = data + py * pitch + rx * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } } } @@ -390,13 +371,7 @@ void wgtCanvasFillCircle(WidgetT *w, int32_t cx, int32_t cy, int32_t radius) { if (dx * dx + dy * dy <= r2) { uint8_t *dst = data + py * pitch + px * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } } } @@ -435,13 +410,7 @@ void wgtCanvasFillRect(WidgetT *w, int32_t x, int32_t y, int32_t width, int32_t for (int32_t px = x0; px < x1; px++) { uint8_t *dst = data + py * pitch + px * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } } } @@ -463,13 +432,7 @@ uint32_t wgtCanvasGetPixel(const WidgetT *w, int32_t x, int32_t y) { int32_t bpp = w->as.canvas.canvasPitch / w->as.canvas.canvasW; const uint8_t *src = w->as.canvas.data + y * w->as.canvas.canvasPitch + x * bpp; - if (bpp == 1) { - return *src; - } else if (bpp == 2) { - return *(const uint16_t *)src; - } else { - return *(const uint32_t *)src; - } + return canvasGetPixel(src, bpp); } @@ -521,13 +484,7 @@ int32_t wgtCanvasLoad(WidgetT *w, const char *path) { uint32_t color = packColor(d, src[0], src[1], src[2]); uint8_t *dst = data + y * pitch + x * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } } @@ -581,15 +538,7 @@ int32_t wgtCanvasSave(WidgetT *w, const char *path) { for (int32_t y = 0; y < ch; y++) { for (int32_t x = 0; x < cw; x++) { const uint8_t *src = w->as.canvas.data + y * pitch + x * bpp; - uint32_t pixel; - - if (bpp == 1) { - pixel = *src; - } else if (bpp == 2) { - pixel = *(const uint16_t *)src; - } else { - pixel = *(const uint32_t *)src; - } + uint32_t pixel = canvasGetPixel(src, bpp); uint8_t *dst = rgb + (y * cw + x) * 3; canvasUnpackColor(d, pixel, &dst[0], &dst[1], &dst[2]); @@ -641,13 +590,7 @@ void wgtCanvasSetPixel(WidgetT *w, int32_t x, int32_t y, uint32_t color) { int32_t bpp = w->as.canvas.canvasPitch / w->as.canvas.canvasW; uint8_t *dst = w->as.canvas.data + y * w->as.canvas.canvasPitch + x * bpp; - if (bpp == 1) { - *dst = (uint8_t)color; - } else if (bpp == 2) { - *(uint16_t *)dst = (uint16_t)color; - } else { - *(uint32_t *)dst = color; - } + canvasPutPixel(dst, color, bpp); } diff --git a/dvx/widgets/widgetCore.c b/dvx/widgets/widgetCore.c index ab267b8..5a3eee7 100644 --- a/dvx/widgets/widgetCore.c +++ b/dvx/widgets/widgetCore.c @@ -394,9 +394,9 @@ bool widgetIsFocusable(WidgetTypeE type) { return type == WidgetTextInputE || type == WidgetComboBoxE || type == WidgetDropdownE || type == WidgetCheckboxE || type == WidgetRadioE || type == WidgetButtonE || - type == WidgetSliderE || type == WidgetListBoxE || - type == WidgetTreeViewE || type == WidgetAnsiTermE || - type == WidgetTabControlE; + type == WidgetImageButtonE || type == WidgetSliderE || + type == WidgetListBoxE || type == WidgetTreeViewE || + type == WidgetAnsiTermE || type == WidgetTabControlE; } @@ -424,6 +424,31 @@ bool widgetIsHorizContainer(WidgetTypeE type) { } +// ============================================================ +// widgetScrollbarThumb +// ============================================================ + +void widgetScrollbarThumb(int32_t trackLen, int32_t totalSize, int32_t visibleSize, int32_t scrollPos, int32_t *thumbPos, int32_t *thumbSize) { + *thumbSize = (trackLen * visibleSize) / totalSize; + + if (*thumbSize < SB_MIN_THUMB) { + *thumbSize = SB_MIN_THUMB; + } + + if (*thumbSize > trackLen) { + *thumbSize = trackLen; + } + + int32_t maxScroll = totalSize - visibleSize; + + if (maxScroll > 0) { + *thumbPos = ((trackLen - *thumbSize) * scrollPos) / maxScroll; + } else { + *thumbPos = 0; + } +} + + // ============================================================ // widgetRemoveChild // ============================================================ diff --git a/dvx/widgets/widgetEvent.c b/dvx/widgets/widgetEvent.c index 4d7657b..a1b08c7 100644 --- a/dvx/widgets/widgetEvent.c +++ b/dvx/widgets/widgetEvent.c @@ -121,7 +121,7 @@ void widgetOnKey(WindowT *win, int32_t key, int32_t mod) { while (top > 0) { WidgetT *w = stack[--top]; - if (w->focused && (w->type == WidgetTextInputE || w->type == WidgetComboBoxE || w->type == WidgetDropdownE || w->type == WidgetAnsiTermE || w->type == WidgetTreeViewE || w->type == WidgetListBoxE || w->type == WidgetButtonE || w->type == WidgetImageButtonE || w->type == WidgetCheckboxE || w->type == WidgetRadioE || w->type == WidgetSliderE || w->type == WidgetTabControlE)) { + if (w->focused && widgetIsFocusable(w->type)) { focus = w; break; } @@ -302,13 +302,7 @@ void widgetOnKey(WindowT *win, int32_t key, int32_t mod) { } // Clamp - if (focus->as.slider.value < focus->as.slider.minValue) { - focus->as.slider.value = focus->as.slider.minValue; - } - - if (focus->as.slider.value > focus->as.slider.maxValue) { - focus->as.slider.value = focus->as.slider.maxValue; - } + focus->as.slider.value = clampInt(focus->as.slider.value, focus->as.slider.minValue, focus->as.slider.maxValue); if (focus->onChange) { focus->onChange(focus); diff --git a/dvx/widgets/widgetInternal.h b/dvx/widgets/widgetInternal.h index 63f1ad0..3d7cd2a 100644 --- a/dvx/widgets/widgetInternal.h +++ b/dvx/widgets/widgetInternal.h @@ -39,6 +39,17 @@ #define TREE_BORDER 2 #define TREE_SB_W 14 #define TREE_MIN_ROWS 4 +#define SB_MIN_THUMB 14 + +// ============================================================ +// Inline helpers +// ============================================================ + +static inline int32_t clampInt(int32_t val, int32_t lo, int32_t hi) { + if (val < lo) { return lo; } + if (val > hi) { return hi; } + return val; +} // ============================================================ // Shared state (defined in widgetCore.c) @@ -71,6 +82,7 @@ bool widgetIsFocusable(WidgetTypeE type); bool widgetIsBoxContainer(WidgetTypeE type); bool widgetIsHorizContainer(WidgetTypeE type); void widgetRemoveChild(WidgetT *parent, WidgetT *child); +void widgetScrollbarThumb(int32_t trackLen, int32_t totalSize, int32_t visibleSize, int32_t scrollPos, int32_t *thumbPos, int32_t *thumbSize); // ============================================================ // Layout functions (widgetLayout.c) diff --git a/dvx/widgets/widgetListBox.c b/dvx/widgets/widgetListBox.c index 78211ad..7db1b90 100644 --- a/dvx/widgets/widgetListBox.c +++ b/dvx/widgets/widgetListBox.c @@ -8,38 +8,6 @@ #define LISTBOX_SB_W 14 -// ============================================================ -// Prototypes -// ============================================================ - -static void listBoxScrollbarThumb(int32_t trackLen, int32_t totalItems, int32_t visibleItems, int32_t scrollPos, int32_t *thumbPos, int32_t *thumbSize); - - -// ============================================================ -// listBoxScrollbarThumb -// ============================================================ - -static void listBoxScrollbarThumb(int32_t trackLen, int32_t totalItems, int32_t visibleItems, int32_t scrollPos, int32_t *thumbPos, int32_t *thumbSize) { - *thumbSize = (trackLen * visibleItems) / totalItems; - - if (*thumbSize < LISTBOX_SB_W) { - *thumbSize = LISTBOX_SB_W; - } - - if (*thumbSize > trackLen) { - *thumbSize = trackLen; - } - - int32_t maxScroll = totalItems - visibleItems; - - if (maxScroll > 0) { - *thumbPos = ((trackLen - *thumbSize) * scrollPos) / maxScroll; - } else { - *thumbPos = 0; - } -} - - // ============================================================ // wgtListBox // ============================================================ @@ -199,13 +167,7 @@ void widgetListBoxOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { maxScroll = 0; } - if (hit->as.listBox.scrollPos > maxScroll) { - hit->as.listBox.scrollPos = maxScroll; - } - - if (hit->as.listBox.scrollPos < 0) { - hit->as.listBox.scrollPos = 0; - } + hit->as.listBox.scrollPos = clampInt(hit->as.listBox.scrollPos, 0, maxScroll); // Check if click is on the scrollbar if (needSb) { @@ -231,22 +193,16 @@ void widgetListBoxOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { // Track — page up/down int32_t thumbPos; int32_t thumbSize; - listBoxScrollbarThumb(trackLen, hit->as.listBox.itemCount, visibleRows, hit->as.listBox.scrollPos, &thumbPos, &thumbSize); + widgetScrollbarThumb(trackLen, hit->as.listBox.itemCount, visibleRows, hit->as.listBox.scrollPos, &thumbPos, &thumbSize); int32_t trackRelY = relY - LISTBOX_SB_W; if (trackRelY < thumbPos) { hit->as.listBox.scrollPos -= visibleRows; - - if (hit->as.listBox.scrollPos < 0) { - hit->as.listBox.scrollPos = 0; - } + hit->as.listBox.scrollPos = clampInt(hit->as.listBox.scrollPos, 0, maxScroll); } else if (trackRelY >= thumbPos + thumbSize) { hit->as.listBox.scrollPos += visibleRows; - - if (hit->as.listBox.scrollPos > maxScroll) { - hit->as.listBox.scrollPos = maxScroll; - } + hit->as.listBox.scrollPos = clampInt(hit->as.listBox.scrollPos, 0, maxScroll); } } @@ -295,11 +251,7 @@ void widgetListBoxPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitm } // Sunken border - BevelStyleT bevel; - bevel.highlight = colors->windowShadow; - bevel.shadow = colors->windowHighlight; - bevel.face = bg; - bevel.width = 2; + BevelStyleT bevel = BEVEL_SUNKEN(colors, bg, 2); drawBevel(d, ops, w->x, w->y, w->w, w->h, &bevel); // Clamp scroll position @@ -309,13 +261,7 @@ void widgetListBoxPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitm maxScroll = 0; } - if (w->as.listBox.scrollPos > maxScroll) { - w->as.listBox.scrollPos = maxScroll; - } - - if (w->as.listBox.scrollPos < 0) { - w->as.listBox.scrollPos = 0; - } + w->as.listBox.scrollPos = clampInt(w->as.listBox.scrollPos, 0, maxScroll); // Draw items int32_t innerX = w->x + LISTBOX_BORDER + LISTBOX_PAD; @@ -344,19 +290,11 @@ void widgetListBoxPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitm int32_t sbH = innerH; // Trough - BevelStyleT troughBevel; - troughBevel.highlight = colors->windowShadow; - troughBevel.shadow = colors->windowHighlight; - troughBevel.face = colors->scrollbarTrough; - troughBevel.width = 1; + BevelStyleT troughBevel = BEVEL_TROUGH(colors); drawBevel(d, ops, sbX, sbY, LISTBOX_SB_W, sbH, &troughBevel); // Up arrow button - BevelStyleT btnBevel; - btnBevel.highlight = colors->windowHighlight; - btnBevel.shadow = colors->windowShadow; - btnBevel.face = colors->windowFace; - btnBevel.width = 1; + BevelStyleT btnBevel = BEVEL_RAISED(colors, 1); drawBevel(d, ops, sbX, sbY, LISTBOX_SB_W, LISTBOX_SB_W, &btnBevel); // Up arrow triangle @@ -389,7 +327,7 @@ void widgetListBoxPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bitm if (trackLen > 0) { int32_t thumbPos; int32_t thumbSize; - listBoxScrollbarThumb(trackLen, w->as.listBox.itemCount, visibleRows, w->as.listBox.scrollPos, &thumbPos, &thumbSize); + widgetScrollbarThumb(trackLen, w->as.listBox.itemCount, visibleRows, w->as.listBox.scrollPos, &thumbPos, &thumbSize); drawBevel(d, ops, sbX, sbY + LISTBOX_SB_W + thumbPos, LISTBOX_SB_W, thumbSize, &btnBevel); } diff --git a/dvx/widgets/widgetTreeView.c b/dvx/widgets/widgetTreeView.c index 1ccf484..e3e4931 100644 --- a/dvx/widgets/widgetTreeView.c +++ b/dvx/widgets/widgetTreeView.c @@ -19,8 +19,6 @@ static void treeCalcScrollbarNeeds(WidgetT *w, const BitmapFontT *font, int32_t static WidgetT *treeItemAtY(WidgetT *parent, int32_t targetY, int32_t *curY, const BitmapFontT *font); static int32_t treeItemYPos(WidgetT *treeView, WidgetT *target, const BitmapFontT *font); static int32_t treeItemYPosHelper(WidgetT *parent, WidgetT *target, int32_t *curY, const BitmapFontT *font); -static void treeScrollbarThumb(int32_t trackLen, int32_t totalSize, int32_t innerSize, int32_t scrollPos, int32_t *thumbPos, int32_t *thumbSize); - // ============================================================ // calcTreeItemsHeight @@ -92,19 +90,11 @@ static void drawTreeHScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, con } // Trough background - BevelStyleT troughBevel; - troughBevel.highlight = colors->windowShadow; - troughBevel.shadow = colors->windowHighlight; - troughBevel.face = colors->scrollbarTrough; - troughBevel.width = 1; + BevelStyleT troughBevel = BEVEL_TROUGH(colors); drawBevel(d, ops, sbX, sbY, sbW, TREE_SB_W, &troughBevel); // Left arrow button - BevelStyleT btnBevel; - btnBevel.highlight = colors->windowHighlight; - btnBevel.shadow = colors->windowShadow; - btnBevel.face = colors->windowFace; - btnBevel.width = 1; + BevelStyleT btnBevel = BEVEL_RAISED(colors, 1); drawBevel(d, ops, sbX, sbY, TREE_SB_W, TREE_SB_W, &btnBevel); // Left arrow triangle @@ -139,7 +129,7 @@ static void drawTreeHScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, con if (trackLen > 0 && totalW > 0) { int32_t thumbPos; int32_t thumbSize; - treeScrollbarThumb(trackLen, totalW, innerW, w->as.treeView.scrollPosH, &thumbPos, &thumbSize); + widgetScrollbarThumb(trackLen, totalW, innerW, w->as.treeView.scrollPosH, &thumbPos, &thumbSize); drawBevel(d, ops, sbX + TREE_SB_W + thumbPos, sbY, thumbSize, TREE_SB_W, &btnBevel); } @@ -165,19 +155,11 @@ static void drawTreeVScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, con } // Trough background - BevelStyleT troughBevel; - troughBevel.highlight = colors->windowShadow; - troughBevel.shadow = colors->windowHighlight; - troughBevel.face = colors->scrollbarTrough; - troughBevel.width = 1; + BevelStyleT troughBevel = BEVEL_TROUGH(colors); drawBevel(d, ops, sbX, sbY, TREE_SB_W, sbH, &troughBevel); // Up arrow button - BevelStyleT btnBevel; - btnBevel.highlight = colors->windowHighlight; - btnBevel.shadow = colors->windowShadow; - btnBevel.face = colors->windowFace; - btnBevel.width = 1; + BevelStyleT btnBevel = BEVEL_RAISED(colors, 1); drawBevel(d, ops, sbX, sbY, TREE_SB_W, TREE_SB_W, &btnBevel); // Up arrow triangle @@ -212,7 +194,7 @@ static void drawTreeVScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, con if (trackLen > 0 && totalH > 0) { int32_t thumbPos; int32_t thumbSize; - treeScrollbarThumb(trackLen, totalH, innerH, w->as.treeView.scrollPos, &thumbPos, &thumbSize); + widgetScrollbarThumb(trackLen, totalH, innerH, w->as.treeView.scrollPos, &thumbPos, &thumbSize); drawBevel(d, ops, sbX, sbY + TREE_SB_W + thumbPos, TREE_SB_W, thumbSize, &btnBevel); } @@ -549,32 +531,6 @@ static int32_t treeItemYPosHelper(WidgetT *parent, WidgetT *target, int32_t *cur } -// ============================================================ -// treeScrollbarThumb -// ============================================================ - -static void treeScrollbarThumb(int32_t trackLen, int32_t totalSize, int32_t innerSize, int32_t scrollPos, int32_t *thumbPos, int32_t *thumbSize) { - // Proportional thumb size - *thumbSize = (trackLen * innerSize) / totalSize; - - if (*thumbSize < TREE_SB_W) { - *thumbSize = TREE_SB_W; - } - - if (*thumbSize > trackLen) { - *thumbSize = trackLen; - } - - // Thumb position - int32_t maxScroll = totalSize - innerSize; - - if (maxScroll > 0) { - *thumbPos = ((trackLen - *thumbSize) * scrollPos) / maxScroll; - } else { - *thumbPos = 0; - } -} - // ============================================================ // wgtTreeItem @@ -808,6 +764,11 @@ void widgetTreeViewOnKey(WidgetT *w, int32_t key) { // ============================================================ void widgetTreeViewLayout(WidgetT *w, const BitmapFontT *font) { + // Auto-select first item if nothing is selected + if (!w->as.treeView.selectedItem) { + w->as.treeView.selectedItem = firstVisibleItem(w); + } + int32_t totalH; int32_t totalW; int32_t innerH; @@ -854,21 +815,8 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) maxScrollH = 0; } - if (hit->as.treeView.scrollPos > maxScrollV) { - hit->as.treeView.scrollPos = maxScrollV; - } - - if (hit->as.treeView.scrollPos < 0) { - hit->as.treeView.scrollPos = 0; - } - - if (hit->as.treeView.scrollPosH > maxScrollH) { - hit->as.treeView.scrollPosH = maxScrollH; - } - - if (hit->as.treeView.scrollPosH < 0) { - hit->as.treeView.scrollPosH = 0; - } + hit->as.treeView.scrollPos = clampInt(hit->as.treeView.scrollPos, 0, maxScrollV); + hit->as.treeView.scrollPosH = clampInt(hit->as.treeView.scrollPosH, 0, maxScrollH); // Check if click is on the vertical scrollbar if (needVSb) { @@ -895,7 +843,7 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) // Track area — page up/down based on thumb position int32_t thumbPos; int32_t thumbSize; - treeScrollbarThumb(trackLen, totalH, innerH, hit->as.treeView.scrollPos, &thumbPos, &thumbSize); + widgetScrollbarThumb(trackLen, totalH, innerH, hit->as.treeView.scrollPos, &thumbPos, &thumbSize); int32_t trackRelY = relY - TREE_SB_W; @@ -907,14 +855,7 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) } // Clamp after scroll - if (hit->as.treeView.scrollPos < 0) { - hit->as.treeView.scrollPos = 0; - } - - if (hit->as.treeView.scrollPos > maxScrollV) { - hit->as.treeView.scrollPos = maxScrollV; - } - + hit->as.treeView.scrollPos = clampInt(hit->as.treeView.scrollPos, 0, maxScrollV); return; } } @@ -944,7 +885,7 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) // Track area — page left/right based on thumb position int32_t thumbPos; int32_t thumbSize; - treeScrollbarThumb(trackLen, totalW, innerW, hit->as.treeView.scrollPosH, &thumbPos, &thumbSize); + widgetScrollbarThumb(trackLen, totalW, innerW, hit->as.treeView.scrollPosH, &thumbPos, &thumbSize); int32_t trackRelX = relX - TREE_SB_W; @@ -956,14 +897,7 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) } // Clamp after scroll - if (hit->as.treeView.scrollPosH < 0) { - hit->as.treeView.scrollPosH = 0; - } - - if (hit->as.treeView.scrollPosH > maxScrollH) { - hit->as.treeView.scrollPosH = maxScrollH; - } - + hit->as.treeView.scrollPosH = clampInt(hit->as.treeView.scrollPosH, 0, maxScrollH); return; } } @@ -1017,27 +951,28 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) // Clamp scroll positions if collapsing reduced content size if (!item->as.treeItem.expanded) { - int32_t newTotalH = calcTreeItemsHeight(hit, font); - int32_t newMaxScrlV = newTotalH - innerH; + int32_t newTotalH; + int32_t newTotalW; + int32_t newInnerH; + int32_t newInnerW; + bool newNeedVSb; + bool newNeedHSb; + + treeCalcScrollbarNeeds(hit, font, &newTotalH, &newTotalW, &newInnerH, &newInnerW, &newNeedVSb, &newNeedHSb); + + int32_t newMaxScrlV = newTotalH - newInnerH; + int32_t newMaxScrlH = newTotalW - newInnerW; if (newMaxScrlV < 0) { newMaxScrlV = 0; } - if (hit->as.treeView.scrollPos > newMaxScrlV) { - hit->as.treeView.scrollPos = newMaxScrlV; - } - - int32_t newTotalW = calcTreeItemsMaxWidth(hit, font, 0); - int32_t newMaxScrlH = newTotalW - innerW; - if (newMaxScrlH < 0) { newMaxScrlH = 0; } - if (hit->as.treeView.scrollPosH > newMaxScrlH) { - hit->as.treeView.scrollPosH = newMaxScrlH; - } + hit->as.treeView.scrollPos = clampInt(hit->as.treeView.scrollPos, 0, newMaxScrlV); + hit->as.treeView.scrollPosH = clampInt(hit->as.treeView.scrollPosH, 0, newMaxScrlH); } if (item->onChange) { @@ -1084,28 +1019,11 @@ void widgetTreeViewPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bit maxScrollH = 0; } - if (w->as.treeView.scrollPos > maxScrollV) { - w->as.treeView.scrollPos = maxScrollV; - } - - if (w->as.treeView.scrollPos < 0) { - w->as.treeView.scrollPos = 0; - } - - if (w->as.treeView.scrollPosH > maxScrollH) { - w->as.treeView.scrollPosH = maxScrollH; - } - - if (w->as.treeView.scrollPosH < 0) { - w->as.treeView.scrollPosH = 0; - } + w->as.treeView.scrollPos = clampInt(w->as.treeView.scrollPos, 0, maxScrollV); + w->as.treeView.scrollPosH = clampInt(w->as.treeView.scrollPosH, 0, maxScrollH); // Sunken border - BevelStyleT bevel; - bevel.highlight = colors->windowShadow; - bevel.shadow = colors->windowHighlight; - bevel.face = bg; - bevel.width = 2; + BevelStyleT bevel = BEVEL_SUNKEN(colors, bg, 2); drawBevel(d, ops, w->x, w->y, w->w, w->h, &bevel); // Set clip rect to inner content area (excludes scrollbars) diff --git a/proxy/proxy.c b/proxy/proxy.c index c553ace..525718f 100644 --- a/proxy/proxy.c +++ b/proxy/proxy.c @@ -471,7 +471,7 @@ int main(int argc, char *argv[]) { int rc = secLinkSend(link, clean, cleanLen, CHANNEL_TERMINAL, true, false); while (rc != SECLINK_SUCCESS && sRunning) { secLinkPoll(link); - usleep(1000); + usleep(10000); rc = secLinkSend(link, clean, cleanLen, CHANNEL_TERMINAL, true, false); } }