From 685c8041c10b744ea94741af0321a9dae86acfc9 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Tue, 10 Mar 2026 18:40:00 -0500 Subject: [PATCH] Tabgroup and treeview bugs fixed. --- dvx/dvxWidget.h | 1 + dvx/widgets/widgetCore.c | 5 + dvx/widgets/widgetInternal.h | 2 + dvx/widgets/widgetTabControl.c | 4 +- dvx/widgets/widgetTreeView.c | 476 ++++++++++++++++++++++++++++++++- dvxdemo/demo.c | 31 ++- 6 files changed, 503 insertions(+), 16 deletions(-) diff --git a/dvx/dvxWidget.h b/dvx/dvxWidget.h index 26695b9..4a25803 100644 --- a/dvx/dvxWidget.h +++ b/dvx/dvxWidget.h @@ -248,6 +248,7 @@ typedef struct WidgetT { struct { int32_t scrollPos; + int32_t scrollPosH; } treeView; struct { diff --git a/dvx/widgets/widgetCore.c b/dvx/widgets/widgetCore.c index 7fd47be..e0d1aed 100644 --- a/dvx/widgets/widgetCore.c +++ b/dvx/widgets/widgetCore.c @@ -190,6 +190,11 @@ WidgetT *widgetHitTest(WidgetT *w, int32_t x, int32_t y) { return NULL; } + // TreeView manages its own children — don't recurse + if (w->type == WidgetTreeViewE) { + return w; + } + // Check children — take the last match (topmost in Z-order) WidgetT *hit = NULL; diff --git a/dvx/widgets/widgetInternal.h b/dvx/widgets/widgetInternal.h index b3f7c34..2d3b402 100644 --- a/dvx/widgets/widgetInternal.h +++ b/dvx/widgets/widgetInternal.h @@ -37,6 +37,8 @@ #define TREE_EXPAND_SIZE 9 #define TREE_ICON_GAP 4 #define TREE_BORDER 2 +#define TREE_SB_W 14 +#define TREE_MIN_ROWS 4 // ============================================================ // Shared state (defined in widgetCore.c) diff --git a/dvx/widgets/widgetTabControl.c b/dvx/widgets/widgetTabControl.c index 62ebf7b..f8ca926 100644 --- a/dvx/widgets/widgetTabControl.c +++ b/dvx/widgets/widgetTabControl.c @@ -114,9 +114,11 @@ void widgetTabControlLayout(WidgetT *w, const BitmapFontT *font) { c->w = contentW; c->h = contentH; - // Only layout the active page if (idx == w->as.tabControl.activeTab) { + c->visible = true; widgetLayoutChildren(c, font); + } else { + c->visible = false; } idx++; diff --git a/dvx/widgets/widgetTreeView.c b/dvx/widgets/widgetTreeView.c index fb9c983..ae1c853 100644 --- a/dvx/widgets/widgetTreeView.c +++ b/dvx/widgets/widgetTreeView.c @@ -8,9 +8,13 @@ static int32_t calcTreeItemsHeight(WidgetT *parent, const BitmapFontT *font); static int32_t calcTreeItemsMaxWidth(WidgetT *parent, const BitmapFontT *font, int32_t depth); +static void drawTreeHScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t totalW, int32_t innerW, bool hasVSb); +static void drawTreeVScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t totalH, int32_t innerH); static void layoutTreeItems(WidgetT *parent, const BitmapFontT *font, int32_t x, int32_t *y, int32_t width, int32_t depth); static void paintTreeItems(WidgetT *parent, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors, int32_t baseX, int32_t *itemY, int32_t depth, int32_t clipTop, int32_t clipBottom); +static void treeCalcScrollbarNeeds(WidgetT *w, const BitmapFontT *font, int32_t *outTotalH, int32_t *outTotalW, int32_t *outInnerH, int32_t *outInnerW, bool *outNeedVSb, bool *outNeedHSb); static WidgetT *treeItemAtY(WidgetT *parent, int32_t targetY, 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); // ============================================================ @@ -69,6 +73,147 @@ static int32_t calcTreeItemsMaxWidth(WidgetT *parent, const BitmapFontT *font, i } +// ============================================================ +// drawTreeHScrollbar +// ============================================================ + +static void drawTreeHScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t totalW, int32_t innerW, bool hasVSb) { + int32_t sbX = w->x + TREE_BORDER; + int32_t sbY = w->y + w->h - TREE_BORDER - TREE_SB_W; + int32_t sbW = innerW; + + if (sbW < TREE_SB_W * 3) { + return; + } + + // Trough background + BevelStyleT troughBevel; + troughBevel.highlight = colors->windowShadow; + troughBevel.shadow = colors->windowHighlight; + troughBevel.face = colors->scrollbarTrough; + troughBevel.width = 1; + 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; + drawBevel(d, ops, sbX, sbY, TREE_SB_W, TREE_SB_W, &btnBevel); + + // Left arrow triangle + { + int32_t cx = sbX + TREE_SB_W / 2; + int32_t cy = sbY + TREE_SB_W / 2; + uint32_t fg = colors->contentFg; + + for (int32_t i = 0; i < 4; i++) { + drawVLine(d, ops, cx - 2 + i, cy - i, 1 + i * 2, fg); + } + } + + // Right arrow button + int32_t rightX = sbX + sbW - TREE_SB_W; + drawBevel(d, ops, rightX, sbY, TREE_SB_W, TREE_SB_W, &btnBevel); + + // Right arrow triangle + { + int32_t cx = rightX + TREE_SB_W / 2; + int32_t cy = sbY + TREE_SB_W / 2; + uint32_t fg = colors->contentFg; + + for (int32_t i = 0; i < 4; i++) { + drawVLine(d, ops, cx + 2 - i, cy - i, 1 + i * 2, fg); + } + } + + // Thumb + int32_t trackLen = sbW - TREE_SB_W * 2; + + if (trackLen > 0 && totalW > 0) { + int32_t thumbPos; + int32_t thumbSize; + treeScrollbarThumb(trackLen, totalW, innerW, w->as.treeView.scrollPosH, &thumbPos, &thumbSize); + + drawBevel(d, ops, sbX + TREE_SB_W + thumbPos, sbY, thumbSize, TREE_SB_W, &btnBevel); + } + + // Fill dead corner when both scrollbars present + if (hasVSb) { + rectFill(d, ops, sbX + sbW, sbY, TREE_SB_W, TREE_SB_W, colors->windowFace); + } +} + + +// ============================================================ +// drawTreeVScrollbar +// ============================================================ + +static void drawTreeVScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t totalH, int32_t innerH) { + int32_t sbX = w->x + w->w - TREE_BORDER - TREE_SB_W; + int32_t sbY = w->y + TREE_BORDER; + int32_t sbH = innerH; + + if (sbH < TREE_SB_W * 3) { + return; + } + + // Trough background + BevelStyleT troughBevel; + troughBevel.highlight = colors->windowShadow; + troughBevel.shadow = colors->windowHighlight; + troughBevel.face = colors->scrollbarTrough; + troughBevel.width = 1; + 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; + drawBevel(d, ops, sbX, sbY, TREE_SB_W, TREE_SB_W, &btnBevel); + + // Up arrow triangle + { + int32_t cx = sbX + TREE_SB_W / 2; + int32_t cy = sbY + TREE_SB_W / 2; + uint32_t fg = colors->contentFg; + + for (int32_t i = 0; i < 4; i++) { + drawHLine(d, ops, cx - i, cy - 2 + i, 1 + i * 2, fg); + } + } + + // Down arrow button + int32_t downY = sbY + sbH - TREE_SB_W; + drawBevel(d, ops, sbX, downY, TREE_SB_W, TREE_SB_W, &btnBevel); + + // Down arrow triangle + { + int32_t cx = sbX + TREE_SB_W / 2; + int32_t cy = downY + TREE_SB_W / 2; + uint32_t fg = colors->contentFg; + + for (int32_t i = 0; i < 4; i++) { + drawHLine(d, ops, cx - i, cy + 2 - i, 1 + i * 2, fg); + } + } + + // Thumb + int32_t trackLen = sbH - TREE_SB_W * 2; + + if (trackLen > 0 && totalH > 0) { + int32_t thumbPos; + int32_t thumbSize; + treeScrollbarThumb(trackLen, totalH, innerH, w->as.treeView.scrollPos, &thumbPos, &thumbSize); + + drawBevel(d, ops, sbX, sbY + TREE_SB_W + thumbPos, TREE_SB_W, thumbSize, &btnBevel); + } +} + + // ============================================================ // layoutTreeItems // ============================================================ @@ -164,6 +309,49 @@ static void paintTreeItems(WidgetT *parent, DisplayT *d, const BlitOpsT *ops, co } +// ============================================================ +// treeCalcScrollbarNeeds +// ============================================================ +// +// Compute content dimensions and determine which scrollbars are +// needed, accounting for the mutual space dependency between them. + +static void treeCalcScrollbarNeeds(WidgetT *w, const BitmapFontT *font, int32_t *outTotalH, int32_t *outTotalW, int32_t *outInnerH, int32_t *outInnerW, bool *outNeedVSb, bool *outNeedHSb) { + int32_t totalH = calcTreeItemsHeight(w, font); + int32_t totalW = calcTreeItemsMaxWidth(w, font, 0); + int32_t innerH = w->h - TREE_BORDER * 2; + int32_t innerW = w->w - TREE_BORDER * 2; + bool needVSb = (totalH > innerH); + bool needHSb = (totalW > innerW); + + // V scrollbar reduces available width — may trigger H scrollbar + if (needVSb) { + innerW -= TREE_SB_W; + + if (!needHSb && totalW > innerW) { + needHSb = true; + } + } + + // H scrollbar reduces available height — may trigger V scrollbar + if (needHSb) { + innerH -= TREE_SB_W; + + if (!needVSb && totalH > innerH) { + needVSb = true; + innerW -= TREE_SB_W; + } + } + + *outTotalH = totalH; + *outTotalW = totalW; + *outInnerH = innerH; + *outInnerW = innerW; + *outNeedVSb = needVSb; + *outNeedHSb = needHSb; +} + + // ============================================================ // treeItemAtY // ============================================================ @@ -195,6 +383,33 @@ static WidgetT *treeItemAtY(WidgetT *parent, int32_t targetY, int32_t *curY, con } +// ============================================================ +// 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 // ============================================================ @@ -257,11 +472,10 @@ WidgetT *wgtTreeView(WidgetT *parent) { // ============================================================ void widgetTreeViewCalcMinSize(WidgetT *w, const BitmapFontT *font) { - int32_t totalH = calcTreeItemsHeight(w, font); - int32_t maxW = calcTreeItemsMaxWidth(w, font, 0); + int32_t minContentW = TREE_INDENT + TREE_EXPAND_SIZE + TREE_ICON_GAP + 6 * font->charWidth; - w->calcMinW = maxW + TREE_BORDER * 2; - w->calcMinH = totalH + TREE_BORDER * 2; + w->calcMinW = minContentW + TREE_BORDER * 2 + TREE_SB_W; + w->calcMinH = TREE_MIN_ROWS * font->charHeight + TREE_BORDER * 2; } @@ -270,11 +484,20 @@ void widgetTreeViewCalcMinSize(WidgetT *w, const BitmapFontT *font) { // ============================================================ void widgetTreeViewLayout(WidgetT *w, const BitmapFontT *font) { + int32_t totalH; + int32_t totalW; + int32_t innerH; + int32_t innerW; + bool needVSb; + bool needHSb; + + treeCalcScrollbarNeeds(w, font, &totalH, &totalW, &innerH, &innerW, &needVSb, &needHSb); + + int32_t itemW = innerW > totalW ? innerW : totalW; int32_t innerX = w->x + TREE_BORDER; int32_t innerY = w->y + TREE_BORDER; - int32_t innerW = w->w - TREE_BORDER * 2; - layoutTreeItems(w, font, innerX, &innerY, innerW, 0); + layoutTreeItems(w, font, innerX, &innerY, itemW, 0); } @@ -285,7 +508,154 @@ void widgetTreeViewLayout(WidgetT *w, const BitmapFontT *font) { void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) { AppContextT *ctx = (AppContextT *)root->userData; const BitmapFontT *font = &ctx->font; - int32_t curY = hit->y + TREE_BORDER; + + int32_t totalH; + int32_t totalW; + int32_t innerH; + int32_t innerW; + bool needVSb; + bool needHSb; + + treeCalcScrollbarNeeds(hit, font, &totalH, &totalW, &innerH, &innerW, &needVSb, &needHSb); + + // Clamp scroll positions + int32_t maxScrollV = totalH - innerH; + int32_t maxScrollH = totalW - innerW; + + if (maxScrollV < 0) { + maxScrollV = 0; + } + + if (maxScrollH < 0) { + 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; + } + + // Check if click is on the vertical scrollbar + if (needVSb) { + int32_t sbX = hit->x + hit->w - TREE_BORDER - TREE_SB_W; + + if (vx >= sbX && vy < hit->y + TREE_BORDER + innerH) { + int32_t sbY = hit->y + TREE_BORDER; + int32_t sbH = innerH; + int32_t relY = vy - sbY; + int32_t trackLen = sbH - TREE_SB_W * 2; + int32_t pageSize = innerH - font->charHeight; + + if (pageSize < font->charHeight) { + pageSize = font->charHeight; + } + + if (relY < TREE_SB_W) { + // Up arrow — scroll up one row + hit->as.treeView.scrollPos -= font->charHeight; + } else if (relY >= sbH - TREE_SB_W) { + // Down arrow — scroll down one row + hit->as.treeView.scrollPos += font->charHeight; + } else if (trackLen > 0) { + // 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); + + int32_t trackRelY = relY - TREE_SB_W; + + if (trackRelY < thumbPos) { + hit->as.treeView.scrollPos -= pageSize; + } else if (trackRelY >= thumbPos + thumbSize) { + hit->as.treeView.scrollPos += pageSize; + } + } + + // 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; + } + + return; + } + } + + // Check if click is on the horizontal scrollbar + if (needHSb) { + int32_t sbY = hit->y + hit->h - TREE_BORDER - TREE_SB_W; + + if (vy >= sbY && vx < hit->x + TREE_BORDER + innerW) { + int32_t sbX = hit->x + TREE_BORDER; + int32_t sbW = innerW; + int32_t relX = vx - sbX; + int32_t trackLen = sbW - TREE_SB_W * 2; + int32_t pageSize = innerW - font->charWidth; + + if (pageSize < font->charWidth) { + pageSize = font->charWidth; + } + + if (relX < TREE_SB_W) { + // Left arrow — scroll left + hit->as.treeView.scrollPosH -= font->charWidth; + } else if (relX >= sbW - TREE_SB_W) { + // Right arrow — scroll right + hit->as.treeView.scrollPosH += font->charWidth; + } else if (trackLen > 0) { + // 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); + + int32_t trackRelX = relX - TREE_SB_W; + + if (trackRelX < thumbPos) { + hit->as.treeView.scrollPosH -= pageSize; + } else if (trackRelX >= thumbPos + thumbSize) { + hit->as.treeView.scrollPosH += pageSize; + } + } + + // 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; + } + + return; + } + } + + // Click in dead corner (both scrollbars present) — ignore + if (needVSb && needHSb) { + int32_t cornerX = hit->x + hit->w - TREE_BORDER - TREE_SB_W; + int32_t cornerY = hit->y + hit->h - TREE_BORDER - TREE_SB_W; + + if (vx >= cornerX && vy >= cornerY) { + return; + } + } + + // Tree item click — adjust for scroll offsets + int32_t curY = hit->y + TREE_BORDER - hit->as.treeView.scrollPos; WidgetT *item = treeItemAtY(hit, vy, &curY, font); @@ -313,11 +683,36 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) p = p->parent; } - int32_t iconX = hit->x + TREE_BORDER + depth * TREE_INDENT; + int32_t iconX = hit->x + TREE_BORDER + depth * TREE_INDENT - hit->as.treeView.scrollPosH; if (vx >= iconX && vx < iconX + TREE_EXPAND_SIZE) { item->as.treeItem.expanded = !item->as.treeItem.expanded; + // Clamp scroll positions if collapsing reduced content size + if (!item->as.treeItem.expanded) { + int32_t newTotalH = calcTreeItemsHeight(hit, font); + int32_t newMaxScrlV = newTotalH - innerH; + + 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; + } + } + if (item->onChange) { item->onChange(item); } @@ -341,6 +736,43 @@ void widgetTreeViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) void widgetTreeViewPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) { uint32_t bg = w->bgColor ? w->bgColor : colors->contentBg; + int32_t totalH; + int32_t totalW; + int32_t innerH; + int32_t innerW; + bool needVSb; + bool needHSb; + + treeCalcScrollbarNeeds(w, font, &totalH, &totalW, &innerH, &innerW, &needVSb, &needHSb); + + // Clamp scroll positions + int32_t maxScrollV = totalH - innerH; + int32_t maxScrollH = totalW - innerW; + + if (maxScrollV < 0) { + maxScrollV = 0; + } + + if (maxScrollH < 0) { + 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; + } + // Sunken border BevelStyleT bevel; bevel.highlight = colors->windowShadow; @@ -349,10 +781,30 @@ void widgetTreeViewPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bit bevel.width = 2; drawBevel(d, ops, w->x, w->y, w->w, w->h, &bevel); - // Paint tree items - int32_t itemY = w->y + TREE_BORDER; + // Set clip rect to inner content area (excludes scrollbars) + int32_t oldClipX = d->clipX; + int32_t oldClipY = d->clipY; + int32_t oldClipW = d->clipW; + int32_t oldClipH = d->clipH; + setClipRect(d, w->x + TREE_BORDER, w->y + TREE_BORDER, innerW, innerH); + + // Paint tree items offset by both scroll positions + int32_t itemY = w->y + TREE_BORDER - w->as.treeView.scrollPos; + int32_t baseX = w->x + TREE_BORDER - w->as.treeView.scrollPosH; paintTreeItems(w, d, ops, font, colors, - w->x + TREE_BORDER, &itemY, 0, - w->y + TREE_BORDER, w->y + w->h - TREE_BORDER); + baseX, &itemY, 0, + w->y + TREE_BORDER, w->y + TREE_BORDER + innerH); + + // Restore clip rect + setClipRect(d, oldClipX, oldClipY, oldClipW, oldClipH); + + // Draw scrollbars + if (needVSb) { + drawTreeVScrollbar(w, d, ops, colors, totalH, innerH); + } + + if (needHSb) { + drawTreeHScrollbar(w, d, ops, colors, totalW, innerW, needVSb); + } } diff --git a/dvxdemo/demo.c b/dvxdemo/demo.c index 3d8cf41..89c3353 100644 --- a/dvxdemo/demo.c +++ b/dvxdemo/demo.c @@ -24,6 +24,7 @@ static void onCloseCb(WindowT *win); static void onMenuCb(WindowT *win, int32_t menuId); static void onOkClick(WidgetT *w); static void onPaintColor(WindowT *win, RectT *dirtyArea); +static void onToolbarClick(WidgetT *w); static void onPaintPattern(WindowT *win, RectT *dirtyArea); static void onPaintText(WindowT *win, RectT *dirtyArea); static void setupWidgetDemo2(AppContextT *ctx); @@ -85,6 +86,26 @@ static void onOkClick(WidgetT *w) { } +// ============================================================ +// onToolbarClick +// ============================================================ + +static void onToolbarClick(WidgetT *w) { + WidgetT *root = w; + + while (root->parent) { + root = root->parent; + } + + WidgetT *status = wgtFind(root, "advStatus"); + + if (status) { + wgtSetText(status, wgtGetText(w)); + wgtInvalidate(status); + } +} + + // ============================================================ // onPaintColor // ============================================================ @@ -320,9 +341,12 @@ static void setupWidgetDemo2(AppContextT *ctx) { WidgetT *page3 = wgtTabPage(tabs, "Toolbar"); WidgetT *tb = wgtToolbar(page3); - wgtButton(tb, "New"); - wgtButton(tb, "Open"); - wgtButton(tb, "Save"); + WidgetT *btnNew = wgtButton(tb, "New"); + WidgetT *btnOpen = wgtButton(tb, "Open"); + WidgetT *btnSave = wgtButton(tb, "Save"); + btnNew->onClick = onToolbarClick; + btnOpen->onClick = onToolbarClick; + btnSave->onClick = onToolbarClick; wgtLabel(page3, "Toolbar with buttons above."); @@ -330,6 +354,7 @@ static void setupWidgetDemo2(AppContextT *ctx) { WidgetT *sb = wgtStatusBar(root); WidgetT *sbLabel = wgtLabel(sb, "Ready"); sbLabel->weight = 100; + strncpy(sbLabel->name, "advStatus", MAX_WIDGET_NAME); wgtLabel(sb, "Line 1, Col 1"); wgtInvalidate(root);