Added ScrollPane.
This commit is contained in:
parent
911cd1d123
commit
236f6b4e39
6 changed files with 706 additions and 20 deletions
|
|
@ -32,6 +32,7 @@ WSRCS = widgets/widgetAnsiTerm.c \
|
||||||
widgets/widgetListView.c \
|
widgets/widgetListView.c \
|
||||||
widgets/widgetProgressBar.c \
|
widgets/widgetProgressBar.c \
|
||||||
widgets/widgetRadio.c \
|
widgets/widgetRadio.c \
|
||||||
|
widgets/widgetScrollPane.c \
|
||||||
widgets/widgetSeparator.c \
|
widgets/widgetSeparator.c \
|
||||||
widgets/widgetSlider.c \
|
widgets/widgetSlider.c \
|
||||||
widgets/widgetSpacer.c \
|
widgets/widgetSpacer.c \
|
||||||
|
|
@ -100,6 +101,7 @@ $(WOBJDIR)/widgetListBox.o: widgets/widgetListBox.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetListView.o: widgets/widgetListView.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetListView.o: widgets/widgetListView.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetProgressBar.o: widgets/widgetProgressBar.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetProgressBar.o: widgets/widgetProgressBar.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetRadio.o: widgets/widgetRadio.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetRadio.o: widgets/widgetRadio.c $(WIDGET_DEPS)
|
||||||
|
$(WOBJDIR)/widgetScrollPane.o: widgets/widgetScrollPane.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetSeparator.o: widgets/widgetSeparator.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetSeparator.o: widgets/widgetSeparator.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetSlider.o: widgets/widgetSlider.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetSlider.o: widgets/widgetSlider.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetSpacer.o: widgets/widgetSpacer.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetSpacer.o: widgets/widgetSpacer.c $(WIDGET_DEPS)
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,8 @@ typedef enum {
|
||||||
WidgetCanvasE,
|
WidgetCanvasE,
|
||||||
WidgetAnsiTermE,
|
WidgetAnsiTermE,
|
||||||
WidgetListViewE,
|
WidgetListViewE,
|
||||||
WidgetSpinnerE
|
WidgetSpinnerE,
|
||||||
|
WidgetScrollPaneE
|
||||||
} WidgetTypeE;
|
} WidgetTypeE;
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -441,6 +442,11 @@ typedef struct WidgetT {
|
||||||
int32_t undoCursor;
|
int32_t undoCursor;
|
||||||
bool editing; // true when user is typing
|
bool editing; // true when user is typing
|
||||||
} spinner;
|
} spinner;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int32_t scrollPosV;
|
||||||
|
int32_t scrollPosH;
|
||||||
|
} scrollPane;
|
||||||
} as;
|
} as;
|
||||||
} WidgetT;
|
} WidgetT;
|
||||||
|
|
||||||
|
|
@ -577,6 +583,12 @@ void wgtListViewSetItemSelected(WidgetT *w, int32_t idx, bool selected);
|
||||||
void wgtListViewSelectAll(WidgetT *w);
|
void wgtListViewSelectAll(WidgetT *w);
|
||||||
void wgtListViewClearSelection(WidgetT *w);
|
void wgtListViewClearSelection(WidgetT *w);
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// ScrollPane
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
WidgetT *wgtScrollPane(WidgetT *parent);
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// ImageButton
|
// ImageButton
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,19 @@ static const WidgetClassT sClassAnsiTerm = {
|
||||||
.setText = NULL
|
.setText = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const WidgetClassT sClassScrollPane = {
|
||||||
|
.flags = WCLASS_PAINTS_CHILDREN | WCLASS_NO_HIT_RECURSE,
|
||||||
|
.paint = widgetScrollPanePaint,
|
||||||
|
.paintOverlay = NULL,
|
||||||
|
.calcMinSize = widgetScrollPaneCalcMinSize,
|
||||||
|
.layout = widgetScrollPaneLayout,
|
||||||
|
.onMouse = widgetScrollPaneOnMouse,
|
||||||
|
.onKey = widgetScrollPaneOnKey,
|
||||||
|
.destroy = NULL,
|
||||||
|
.getText = NULL,
|
||||||
|
.setText = NULL
|
||||||
|
};
|
||||||
|
|
||||||
static const WidgetClassT sClassSpinner = {
|
static const WidgetClassT sClassSpinner = {
|
||||||
.flags = WCLASS_FOCUSABLE,
|
.flags = WCLASS_FOCUSABLE,
|
||||||
.paint = widgetSpinnerPaint,
|
.paint = widgetSpinnerPaint,
|
||||||
|
|
@ -416,5 +429,6 @@ const WidgetClassT *widgetClassTable[] = {
|
||||||
[WidgetCanvasE] = &sClassCanvas,
|
[WidgetCanvasE] = &sClassCanvas,
|
||||||
[WidgetAnsiTermE] = &sClassAnsiTerm,
|
[WidgetAnsiTermE] = &sClassAnsiTerm,
|
||||||
[WidgetListViewE] = &sClassListView,
|
[WidgetListViewE] = &sClassListView,
|
||||||
[WidgetSpinnerE] = &sClassSpinner
|
[WidgetSpinnerE] = &sClassSpinner,
|
||||||
|
[WidgetScrollPaneE] = &sClassScrollPane
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,7 @@ bool widgetListViewColBorderHit(const WidgetT *w, int32_t vx, int32_t vy);
|
||||||
void widgetProgressBarPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
void widgetProgressBarPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||||
void widgetRadioPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
void widgetRadioPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||||
void widgetSeparatorPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
void widgetSeparatorPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||||
|
void widgetScrollPanePaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||||
void widgetSliderPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
void widgetSliderPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||||
void widgetSpinnerPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
void widgetSpinnerPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||||
void widgetStatusBarPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
void widgetStatusBarPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||||
|
|
@ -197,6 +198,7 @@ void widgetListViewCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetProgressBarCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
void widgetProgressBarCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetRadioCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
void widgetRadioCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetSeparatorCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
void widgetSeparatorCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
|
void widgetScrollPaneCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetSliderCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
void widgetSliderCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetSpinnerCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
void widgetSpinnerCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetSpacerCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
void widgetSpacerCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
|
|
@ -209,6 +211,7 @@ void widgetTreeViewCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
// Per-widget layout functions (for special containers)
|
// Per-widget layout functions (for special containers)
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
|
void widgetScrollPaneLayout(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetTabControlLayout(WidgetT *w, const BitmapFontT *font);
|
void widgetTabControlLayout(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetTreeViewLayout(WidgetT *w, const BitmapFontT *font);
|
void widgetTreeViewLayout(WidgetT *w, const BitmapFontT *font);
|
||||||
|
|
||||||
|
|
@ -277,6 +280,8 @@ void widgetListViewOnKey(WidgetT *w, int32_t key, int32_t mod);
|
||||||
void widgetListViewOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
void widgetListViewOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
||||||
void widgetRadioOnKey(WidgetT *w, int32_t key, int32_t mod);
|
void widgetRadioOnKey(WidgetT *w, int32_t key, int32_t mod);
|
||||||
void widgetRadioOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
void widgetRadioOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
||||||
|
void widgetScrollPaneOnKey(WidgetT *w, int32_t key, int32_t mod);
|
||||||
|
void widgetScrollPaneOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
||||||
void widgetSliderOnKey(WidgetT *w, int32_t key, int32_t mod);
|
void widgetSliderOnKey(WidgetT *w, int32_t key, int32_t mod);
|
||||||
void widgetSliderOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
void widgetSliderOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
||||||
void widgetSpinnerOnKey(WidgetT *w, int32_t key, int32_t mod);
|
void widgetSpinnerOnKey(WidgetT *w, int32_t key, int32_t mod);
|
||||||
|
|
|
||||||
617
dvx/widgets/widgetScrollPane.c
Normal file
617
dvx/widgets/widgetScrollPane.c
Normal file
|
|
@ -0,0 +1,617 @@
|
||||||
|
// widgetScrollPane.c — ScrollPane container widget
|
||||||
|
|
||||||
|
#include "widgetInternal.h"
|
||||||
|
|
||||||
|
#define SP_BORDER 2
|
||||||
|
#define SP_SB_W 14
|
||||||
|
#define SP_PAD 0
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Prototypes
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
static void drawSPHScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t sbX, int32_t sbY, int32_t sbW, int32_t totalW, int32_t visibleW);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// drawSPHScrollbar
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
static void drawSPHScrollbar(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t sbX, int32_t sbY, int32_t sbW, int32_t totalW, int32_t visibleW) {
|
||||||
|
if (sbW < SP_SB_W * 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fg = colors->contentFg;
|
||||||
|
|
||||||
|
// Trough
|
||||||
|
BevelStyleT troughBevel = BEVEL_TROUGH(colors);
|
||||||
|
drawBevel(d, ops, sbX, sbY, sbW, SP_SB_W, &troughBevel);
|
||||||
|
|
||||||
|
// Left arrow button
|
||||||
|
BevelStyleT btnBevel = BEVEL_RAISED(colors, 1);
|
||||||
|
drawBevel(d, ops, sbX, sbY, SP_SB_W, SP_SB_W, &btnBevel);
|
||||||
|
|
||||||
|
{
|
||||||
|
int32_t cx = sbX + SP_SB_W / 2;
|
||||||
|
int32_t cy = sbY + SP_SB_W / 2;
|
||||||
|
|
||||||
|
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 - SP_SB_W;
|
||||||
|
drawBevel(d, ops, rightX, sbY, SP_SB_W, SP_SB_W, &btnBevel);
|
||||||
|
|
||||||
|
{
|
||||||
|
int32_t cx = rightX + SP_SB_W / 2;
|
||||||
|
int32_t cy = sbY + SP_SB_W / 2;
|
||||||
|
|
||||||
|
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 - SP_SB_W * 2;
|
||||||
|
|
||||||
|
if (trackLen > 0 && totalW > 0) {
|
||||||
|
int32_t thumbPos;
|
||||||
|
int32_t thumbSize;
|
||||||
|
widgetScrollbarThumb(trackLen, totalW, visibleW, w->as.scrollPane.scrollPosH, &thumbPos, &thumbSize);
|
||||||
|
drawBevel(d, ops, sbX + SP_SB_W + thumbPos, sbY, thumbSize, SP_SB_W, &btnBevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// drawSPVScrollbar
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (sbH < SP_SB_W * 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fg = colors->contentFg;
|
||||||
|
|
||||||
|
// Trough
|
||||||
|
BevelStyleT troughBevel = BEVEL_TROUGH(colors);
|
||||||
|
drawBevel(d, ops, sbX, sbY, SP_SB_W, sbH, &troughBevel);
|
||||||
|
|
||||||
|
// Up arrow button
|
||||||
|
BevelStyleT btnBevel = BEVEL_RAISED(colors, 1);
|
||||||
|
drawBevel(d, ops, sbX, sbY, SP_SB_W, SP_SB_W, &btnBevel);
|
||||||
|
|
||||||
|
{
|
||||||
|
int32_t cx = sbX + SP_SB_W / 2;
|
||||||
|
int32_t cy = sbY + SP_SB_W / 2;
|
||||||
|
|
||||||
|
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 - SP_SB_W;
|
||||||
|
drawBevel(d, ops, sbX, downY, SP_SB_W, SP_SB_W, &btnBevel);
|
||||||
|
|
||||||
|
{
|
||||||
|
int32_t cx = sbX + SP_SB_W / 2;
|
||||||
|
int32_t cy = downY + SP_SB_W / 2;
|
||||||
|
|
||||||
|
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 - SP_SB_W * 2;
|
||||||
|
|
||||||
|
if (trackLen > 0 && totalH > 0) {
|
||||||
|
int32_t thumbPos;
|
||||||
|
int32_t thumbSize;
|
||||||
|
widgetScrollbarThumb(trackLen, totalH, visibleH, w->as.scrollPane.scrollPosV, &thumbPos, &thumbSize);
|
||||||
|
drawBevel(d, ops, sbX, sbY + SP_SB_W + thumbPos, SP_SB_W, thumbSize, &btnBevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// spCalcNeeds — determine scrollbar needs and inner dimensions
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
static void spCalcNeeds(WidgetT *w, const BitmapFontT *font, int32_t *contentMinW, int32_t *contentMinH, int32_t *innerW, int32_t *innerH, bool *needVSb, bool *needHSb) {
|
||||||
|
// Measure children
|
||||||
|
int32_t totalMinW = 0;
|
||||||
|
int32_t totalMinH = 0;
|
||||||
|
int32_t pad = wgtResolveSize(w->padding, 0, font->charWidth);
|
||||||
|
int32_t gap = wgtResolveSize(w->spacing, 0, font->charWidth);
|
||||||
|
int32_t count = 0;
|
||||||
|
|
||||||
|
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
||||||
|
if (!c->visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalMinH += c->calcMinH;
|
||||||
|
totalMinW = DVX_MAX(totalMinW, c->calcMinW);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1) {
|
||||||
|
totalMinH += gap * (count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
totalMinW += pad * 2;
|
||||||
|
totalMinH += pad * 2;
|
||||||
|
|
||||||
|
*contentMinW = totalMinW;
|
||||||
|
*contentMinH = totalMinH;
|
||||||
|
|
||||||
|
// Available inner area
|
||||||
|
*innerW = w->w - SP_BORDER * 2;
|
||||||
|
*innerH = w->h - SP_BORDER * 2;
|
||||||
|
|
||||||
|
// Determine scrollbar needs (two-pass for mutual dependency)
|
||||||
|
*needVSb = (totalMinH > *innerH);
|
||||||
|
*needHSb = false;
|
||||||
|
|
||||||
|
if (*needVSb) {
|
||||||
|
*innerW -= SP_SB_W;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalMinW > *innerW) {
|
||||||
|
*needHSb = true;
|
||||||
|
*innerH -= SP_SB_W;
|
||||||
|
|
||||||
|
if (!*needVSb && totalMinH > *innerH) {
|
||||||
|
*needVSb = true;
|
||||||
|
*innerW -= SP_SB_W;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*innerW < 0) {
|
||||||
|
*innerW = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*innerH < 0) {
|
||||||
|
*innerH = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// widgetScrollPaneCalcMinSize
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
void widgetScrollPaneCalcMinSize(WidgetT *w, const BitmapFontT *font) {
|
||||||
|
// Recursively measure children so they have valid calcMinW/H
|
||||||
|
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
||||||
|
widgetCalcMinSizeTree(c, font);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The scroll pane's own min size is small — the whole point is scrolling
|
||||||
|
w->calcMinW = SP_SB_W * 3 + SP_BORDER * 2;
|
||||||
|
w->calcMinH = SP_SB_W * 3 + SP_BORDER * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// widgetScrollPaneLayout
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
void widgetScrollPaneLayout(WidgetT *w, const BitmapFontT *font) {
|
||||||
|
int32_t contentMinW;
|
||||||
|
int32_t contentMinH;
|
||||||
|
int32_t innerW;
|
||||||
|
int32_t innerH;
|
||||||
|
bool needVSb;
|
||||||
|
bool needHSb;
|
||||||
|
|
||||||
|
spCalcNeeds(w, font, &contentMinW, &contentMinH, &innerW, &innerH, &needVSb, &needHSb);
|
||||||
|
|
||||||
|
// Clamp scroll positions
|
||||||
|
int32_t maxScrollV = contentMinH - innerH;
|
||||||
|
int32_t maxScrollH = contentMinW - innerW;
|
||||||
|
|
||||||
|
if (maxScrollV < 0) {
|
||||||
|
maxScrollV = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScrollH < 0) {
|
||||||
|
maxScrollH = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
w->as.scrollPane.scrollPosV = clampInt(w->as.scrollPane.scrollPosV, 0, maxScrollV);
|
||||||
|
w->as.scrollPane.scrollPosH = clampInt(w->as.scrollPane.scrollPosH, 0, maxScrollH);
|
||||||
|
|
||||||
|
// Layout children as a vertical box at virtual size
|
||||||
|
int32_t pad = wgtResolveSize(w->padding, 0, font->charWidth);
|
||||||
|
int32_t gap = wgtResolveSize(w->spacing, 0, font->charWidth);
|
||||||
|
int32_t virtualW = DVX_MAX(innerW, contentMinW);
|
||||||
|
int32_t virtualH = DVX_MAX(innerH, contentMinH);
|
||||||
|
int32_t baseX = w->x + SP_BORDER - w->as.scrollPane.scrollPosH;
|
||||||
|
int32_t baseY = w->y + SP_BORDER - w->as.scrollPane.scrollPosV;
|
||||||
|
int32_t childW = virtualW - pad * 2;
|
||||||
|
int32_t pos = baseY + pad;
|
||||||
|
|
||||||
|
if (childW < 0) {
|
||||||
|
childW = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum min sizes and weights for distribution
|
||||||
|
int32_t totalMin = 0;
|
||||||
|
int32_t totalWeight = 0;
|
||||||
|
|
||||||
|
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
||||||
|
if (!c->visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalMin += c->calcMinH;
|
||||||
|
totalWeight += c->weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t count = widgetCountVisibleChildren(w);
|
||||||
|
int32_t totalGap = (count > 1) ? gap * (count - 1) : 0;
|
||||||
|
int32_t availMain = virtualH - pad * 2 - totalGap;
|
||||||
|
int32_t extraSpace = availMain - totalMin;
|
||||||
|
|
||||||
|
if (extraSpace < 0) {
|
||||||
|
extraSpace = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
||||||
|
if (!c->visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t mainSize = c->calcMinH;
|
||||||
|
|
||||||
|
if (totalWeight > 0 && c->weight > 0 && extraSpace > 0) {
|
||||||
|
mainSize += (extraSpace * c->weight) / totalWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->x = baseX + pad;
|
||||||
|
c->y = pos;
|
||||||
|
c->w = childW;
|
||||||
|
c->h = mainSize;
|
||||||
|
|
||||||
|
if (c->maxW) {
|
||||||
|
int32_t maxPx = wgtResolveSize(c->maxW, childW, font->charWidth);
|
||||||
|
|
||||||
|
if (c->w > maxPx) {
|
||||||
|
c->w = maxPx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->maxH) {
|
||||||
|
int32_t maxPx = wgtResolveSize(c->maxH, mainSize, font->charWidth);
|
||||||
|
|
||||||
|
if (c->h > maxPx) {
|
||||||
|
c->h = maxPx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += mainSize + gap;
|
||||||
|
|
||||||
|
// Recurse into child containers
|
||||||
|
widgetLayoutChildren(c, font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// widgetScrollPaneOnKey
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
void widgetScrollPaneOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
|
(void)mod;
|
||||||
|
|
||||||
|
AppContextT *ctx = (AppContextT *)w->window->widgetRoot->userData;
|
||||||
|
const BitmapFontT *font = &ctx->font;
|
||||||
|
|
||||||
|
int32_t contentMinW;
|
||||||
|
int32_t contentMinH;
|
||||||
|
int32_t innerW;
|
||||||
|
int32_t innerH;
|
||||||
|
bool needVSb;
|
||||||
|
bool needHSb;
|
||||||
|
|
||||||
|
spCalcNeeds(w, font, &contentMinW, &contentMinH, &innerW, &innerH, &needVSb, &needHSb);
|
||||||
|
|
||||||
|
int32_t maxScrollV = contentMinH - innerH;
|
||||||
|
int32_t maxScrollH = contentMinW - innerW;
|
||||||
|
|
||||||
|
if (maxScrollV < 0) {
|
||||||
|
maxScrollV = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScrollH < 0) {
|
||||||
|
maxScrollH = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t step = font->charHeight;
|
||||||
|
|
||||||
|
if (key == (0x48 | 0x100)) {
|
||||||
|
// Up
|
||||||
|
w->as.scrollPane.scrollPosV -= step;
|
||||||
|
} else if (key == (0x50 | 0x100)) {
|
||||||
|
// Down
|
||||||
|
w->as.scrollPane.scrollPosV += step;
|
||||||
|
} else if (key == (0x49 | 0x100)) {
|
||||||
|
// Page Up
|
||||||
|
w->as.scrollPane.scrollPosV -= innerH;
|
||||||
|
} else if (key == (0x51 | 0x100)) {
|
||||||
|
// Page Down
|
||||||
|
w->as.scrollPane.scrollPosV += innerH;
|
||||||
|
} else if (key == (0x47 | 0x100)) {
|
||||||
|
// Home
|
||||||
|
w->as.scrollPane.scrollPosV = 0;
|
||||||
|
} else if (key == (0x4F | 0x100)) {
|
||||||
|
// End
|
||||||
|
w->as.scrollPane.scrollPosV = maxScrollV;
|
||||||
|
} else if (key == (0x4B | 0x100)) {
|
||||||
|
// Left
|
||||||
|
w->as.scrollPane.scrollPosH -= font->charWidth;
|
||||||
|
} else if (key == (0x4D | 0x100)) {
|
||||||
|
// Right
|
||||||
|
w->as.scrollPane.scrollPosH += font->charWidth;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
w->as.scrollPane.scrollPosV = clampInt(w->as.scrollPane.scrollPosV, 0, maxScrollV);
|
||||||
|
w->as.scrollPane.scrollPosH = clampInt(w->as.scrollPane.scrollPosH, 0, maxScrollH);
|
||||||
|
wgtInvalidatePaint(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// widgetScrollPaneOnMouse
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
void widgetScrollPaneOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) {
|
||||||
|
AppContextT *ctx = (AppContextT *)root->userData;
|
||||||
|
const BitmapFontT *font = &ctx->font;
|
||||||
|
|
||||||
|
int32_t contentMinW;
|
||||||
|
int32_t contentMinH;
|
||||||
|
int32_t innerW;
|
||||||
|
int32_t innerH;
|
||||||
|
bool needVSb;
|
||||||
|
bool needHSb;
|
||||||
|
|
||||||
|
spCalcNeeds(hit, font, &contentMinW, &contentMinH, &innerW, &innerH, &needVSb, &needHSb);
|
||||||
|
|
||||||
|
// Clamp scroll positions
|
||||||
|
int32_t maxScrollV = contentMinH - innerH;
|
||||||
|
int32_t maxScrollH = contentMinW - innerW;
|
||||||
|
|
||||||
|
if (maxScrollV < 0) {
|
||||||
|
maxScrollV = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScrollH < 0) {
|
||||||
|
maxScrollH = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hit->as.scrollPane.scrollPosV = clampInt(hit->as.scrollPane.scrollPosV, 0, maxScrollV);
|
||||||
|
hit->as.scrollPane.scrollPosH = clampInt(hit->as.scrollPane.scrollPosH, 0, maxScrollH);
|
||||||
|
|
||||||
|
// Check vertical scrollbar
|
||||||
|
if (needVSb) {
|
||||||
|
int32_t sbX = hit->x + hit->w - SP_BORDER - SP_SB_W;
|
||||||
|
|
||||||
|
if (vx >= sbX && vy >= hit->y + SP_BORDER && vy < hit->y + SP_BORDER + innerH) {
|
||||||
|
int32_t sbY = hit->y + SP_BORDER;
|
||||||
|
int32_t sbH = innerH;
|
||||||
|
int32_t relY = vy - sbY;
|
||||||
|
int32_t trackLen = sbH - SP_SB_W * 2;
|
||||||
|
int32_t pageSize = innerH - font->charHeight;
|
||||||
|
|
||||||
|
if (pageSize < font->charHeight) {
|
||||||
|
pageSize = font->charHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relY < SP_SB_W) {
|
||||||
|
hit->as.scrollPane.scrollPosV -= font->charHeight;
|
||||||
|
} else if (relY >= sbH - SP_SB_W) {
|
||||||
|
hit->as.scrollPane.scrollPosV += font->charHeight;
|
||||||
|
} else if (trackLen > 0) {
|
||||||
|
int32_t thumbPos;
|
||||||
|
int32_t thumbSize;
|
||||||
|
widgetScrollbarThumb(trackLen, contentMinH, innerH, hit->as.scrollPane.scrollPosV, &thumbPos, &thumbSize);
|
||||||
|
|
||||||
|
int32_t trackRelY = relY - SP_SB_W;
|
||||||
|
|
||||||
|
if (trackRelY < thumbPos) {
|
||||||
|
hit->as.scrollPane.scrollPosV -= pageSize;
|
||||||
|
} else if (trackRelY >= thumbPos + thumbSize) {
|
||||||
|
hit->as.scrollPane.scrollPosV += pageSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hit->as.scrollPane.scrollPosV = clampInt(hit->as.scrollPane.scrollPosV, 0, maxScrollV);
|
||||||
|
wgtInvalidatePaint(hit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check horizontal scrollbar
|
||||||
|
if (needHSb) {
|
||||||
|
int32_t sbY = hit->y + hit->h - SP_BORDER - SP_SB_W;
|
||||||
|
|
||||||
|
if (vy >= sbY && vx >= hit->x + SP_BORDER && vx < hit->x + SP_BORDER + innerW) {
|
||||||
|
int32_t sbX = hit->x + SP_BORDER;
|
||||||
|
int32_t sbW = innerW;
|
||||||
|
int32_t relX = vx - sbX;
|
||||||
|
int32_t trackLen = sbW - SP_SB_W * 2;
|
||||||
|
int32_t pageSize = innerW - font->charWidth;
|
||||||
|
|
||||||
|
if (pageSize < font->charWidth) {
|
||||||
|
pageSize = font->charWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relX < SP_SB_W) {
|
||||||
|
hit->as.scrollPane.scrollPosH -= font->charWidth;
|
||||||
|
} else if (relX >= sbW - SP_SB_W) {
|
||||||
|
hit->as.scrollPane.scrollPosH += font->charWidth;
|
||||||
|
} else if (trackLen > 0) {
|
||||||
|
int32_t thumbPos;
|
||||||
|
int32_t thumbSize;
|
||||||
|
widgetScrollbarThumb(trackLen, contentMinW, innerW, hit->as.scrollPane.scrollPosH, &thumbPos, &thumbSize);
|
||||||
|
|
||||||
|
int32_t trackRelX = relX - SP_SB_W;
|
||||||
|
|
||||||
|
if (trackRelX < thumbPos) {
|
||||||
|
hit->as.scrollPane.scrollPosH -= pageSize;
|
||||||
|
} else if (trackRelX >= thumbPos + thumbSize) {
|
||||||
|
hit->as.scrollPane.scrollPosH += pageSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hit->as.scrollPane.scrollPosH = clampInt(hit->as.scrollPane.scrollPosH, 0, maxScrollH);
|
||||||
|
wgtInvalidatePaint(hit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dead corner
|
||||||
|
if (needVSb && needHSb) {
|
||||||
|
int32_t cornerX = hit->x + hit->w - SP_BORDER - SP_SB_W;
|
||||||
|
int32_t cornerY = hit->y + hit->h - SP_BORDER - SP_SB_W;
|
||||||
|
|
||||||
|
if (vx >= cornerX && vy >= cornerY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click on content area — forward to child widgets
|
||||||
|
// Children are already positioned at scroll-adjusted coordinates
|
||||||
|
WidgetT *child = NULL;
|
||||||
|
|
||||||
|
for (WidgetT *c = hit->firstChild; c; c = c->nextSibling) {
|
||||||
|
WidgetT *ch = widgetHitTest(c, vx, vy);
|
||||||
|
|
||||||
|
if (ch) {
|
||||||
|
child = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child && child->enabled && child->wclass && child->wclass->onMouse) {
|
||||||
|
// Clear old focus
|
||||||
|
if (sFocusedWidget && sFocusedWidget != child) {
|
||||||
|
sFocusedWidget->focused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->wclass->onMouse(child, root, vx, vy);
|
||||||
|
|
||||||
|
if (child->focused) {
|
||||||
|
sFocusedWidget = child;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hit->focused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wgtInvalidatePaint(hit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// widgetScrollPanePaint
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
void widgetScrollPanePaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
|
||||||
|
uint32_t bg = w->bgColor ? w->bgColor : colors->contentBg;
|
||||||
|
|
||||||
|
int32_t contentMinW;
|
||||||
|
int32_t contentMinH;
|
||||||
|
int32_t innerW;
|
||||||
|
int32_t innerH;
|
||||||
|
bool needVSb;
|
||||||
|
bool needHSb;
|
||||||
|
|
||||||
|
spCalcNeeds(w, font, &contentMinW, &contentMinH, &innerW, &innerH, &needVSb, &needHSb);
|
||||||
|
|
||||||
|
// Clamp scroll
|
||||||
|
int32_t maxScrollV = contentMinH - innerH;
|
||||||
|
int32_t maxScrollH = contentMinW - innerW;
|
||||||
|
|
||||||
|
if (maxScrollV < 0) {
|
||||||
|
maxScrollV = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScrollH < 0) {
|
||||||
|
maxScrollH = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
w->as.scrollPane.scrollPosV = clampInt(w->as.scrollPane.scrollPosV, 0, maxScrollV);
|
||||||
|
w->as.scrollPane.scrollPosH = clampInt(w->as.scrollPane.scrollPosH, 0, maxScrollH);
|
||||||
|
|
||||||
|
// Sunken border
|
||||||
|
BevelStyleT bevel = BEVEL_SUNKEN(colors, bg, SP_BORDER);
|
||||||
|
drawBevel(d, ops, w->x, w->y, w->w, w->h, &bevel);
|
||||||
|
|
||||||
|
// Clip to content area and paint children
|
||||||
|
int32_t oldClipX = d->clipX;
|
||||||
|
int32_t oldClipY = d->clipY;
|
||||||
|
int32_t oldClipW = d->clipW;
|
||||||
|
int32_t oldClipH = d->clipH;
|
||||||
|
setClipRect(d, w->x + SP_BORDER, w->y + SP_BORDER, innerW, innerH);
|
||||||
|
|
||||||
|
// Fill background
|
||||||
|
rectFill(d, ops, w->x + SP_BORDER, w->y + SP_BORDER, innerW, innerH, bg);
|
||||||
|
|
||||||
|
// Paint children (already positioned by layout with scroll offset)
|
||||||
|
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
||||||
|
widgetPaintOne(c, d, ops, font, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
setClipRect(d, oldClipX, oldClipY, oldClipW, oldClipH);
|
||||||
|
|
||||||
|
// Draw scrollbars
|
||||||
|
if (needVSb) {
|
||||||
|
int32_t sbX = w->x + w->w - SP_BORDER - SP_SB_W;
|
||||||
|
int32_t sbY = w->y + SP_BORDER;
|
||||||
|
drawSPVScrollbar(w, d, ops, colors, sbX, sbY, innerH, contentMinH, innerH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needHSb) {
|
||||||
|
int32_t sbX = w->x + SP_BORDER;
|
||||||
|
int32_t sbY = w->y + w->h - SP_BORDER - SP_SB_W;
|
||||||
|
drawSPHScrollbar(w, d, ops, colors, sbX, sbY, innerW, contentMinW, innerW);
|
||||||
|
|
||||||
|
if (needVSb) {
|
||||||
|
rectFill(d, ops, sbX + innerW, sbY, SP_SB_W, SP_SB_W, colors->windowFace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w->focused) {
|
||||||
|
uint32_t fg = w->fgColor ? w->fgColor : colors->contentFg;
|
||||||
|
drawFocusRect(d, ops, w->x + 1, w->y + 1, w->w - 2, w->h - 2, fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// wgtScrollPane
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
WidgetT *wgtScrollPane(WidgetT *parent) {
|
||||||
|
WidgetT *w = widgetAlloc(parent, WidgetScrollPaneE);
|
||||||
|
|
||||||
|
if (w) {
|
||||||
|
w->as.scrollPane.scrollPosV = 0;
|
||||||
|
w->as.scrollPane.scrollPosH = 0;
|
||||||
|
w->weight = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
@ -481,10 +481,46 @@ static void setupControlsWindow(AppContextT *ctx) {
|
||||||
wgtListViewSetMultiSelect(lv, true);
|
wgtListViewSetMultiSelect(lv, true);
|
||||||
lv->weight = 100;
|
lv->weight = 100;
|
||||||
|
|
||||||
// --- Tab 4: Toolbar (ImageButtons + VSeparator) ---
|
// --- Tab 4: ScrollPane ---
|
||||||
WidgetT *page4 = wgtTabPage(tabs, "Tool&bar");
|
WidgetT *page4sp = wgtTabPage(tabs, "&Scroll");
|
||||||
|
|
||||||
WidgetT *tb = wgtToolbar(page4);
|
WidgetT *sp = wgtScrollPane(page4sp);
|
||||||
|
sp->weight = 100;
|
||||||
|
sp->padding = wgtPixels(4);
|
||||||
|
sp->spacing = wgtPixels(4);
|
||||||
|
|
||||||
|
wgtLabel(sp, "ScrollPane Demo:");
|
||||||
|
wgtHSeparator(sp);
|
||||||
|
|
||||||
|
static const char *spItems[] = {
|
||||||
|
"Item &1", "Item &2", "Item &3", "Item &4",
|
||||||
|
"Item &5", "Item &6", "Item &7", "Item &8"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < 8; i++) {
|
||||||
|
wgtCheckbox(sp, spItems[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wgtHSeparator(sp);
|
||||||
|
wgtLabel(sp, "More widgets below:");
|
||||||
|
|
||||||
|
WidgetT *spRg = wgtRadioGroup(sp);
|
||||||
|
static const char *spRadios[] = {
|
||||||
|
"Radio 1", "Radio 2", "Radio 3", "Radio 4", "Radio 5"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < 5; i++) {
|
||||||
|
wgtRadio(spRg, spRadios[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wgtHSeparator(sp);
|
||||||
|
wgtLabel(sp, "Bottom of scroll area");
|
||||||
|
wgtButton(sp, "Scrolled &Button");
|
||||||
|
|
||||||
|
// --- Tab 5: Toolbar (ImageButtons + VSeparator) ---
|
||||||
|
WidgetT *page5tb = wgtTabPage(tabs, "Tool&bar");
|
||||||
|
|
||||||
|
WidgetT *tb = wgtToolbar(page5tb);
|
||||||
|
|
||||||
int32_t imgW;
|
int32_t imgW;
|
||||||
int32_t imgH;
|
int32_t imgH;
|
||||||
|
|
@ -515,18 +551,18 @@ static void setupControlsWindow(AppContextT *ctx) {
|
||||||
WidgetT *btnHelp = wgtButton(tb, "&Help");
|
WidgetT *btnHelp = wgtButton(tb, "&Help");
|
||||||
btnHelp->onClick = onToolbarClick;
|
btnHelp->onClick = onToolbarClick;
|
||||||
|
|
||||||
wgtLabel(page4, "ImageButtons with VSeparator.");
|
wgtLabel(page5tb, "ImageButtons with VSeparator.");
|
||||||
|
|
||||||
// --- Tab 5: Media (Image, ImageFromFile) ---
|
// --- Tab 6: Media (Image, ImageFromFile) ---
|
||||||
WidgetT *page5 = wgtTabPage(tabs, "&Media");
|
WidgetT *page6m = wgtTabPage(tabs, "&Media");
|
||||||
|
|
||||||
wgtLabel(page5, "ImageFromFile (sample.bmp):");
|
wgtLabel(page6m, "ImageFromFile (sample.bmp):");
|
||||||
wgtImageFromFile(page5, "sample.bmp");
|
wgtImageFromFile(page6m, "sample.bmp");
|
||||||
|
|
||||||
wgtHSeparator(page5);
|
wgtHSeparator(page6m);
|
||||||
|
|
||||||
wgtLabel(page5, "Image (logo.bmp):");
|
wgtLabel(page6m, "Image (logo.bmp):");
|
||||||
WidgetT *imgRow = wgtHBox(page5);
|
WidgetT *imgRow = wgtHBox(page6m);
|
||||||
uint8_t *logoData = loadBmpPixels(ctx, "logo.bmp", &imgW, &imgH, &imgPitch);
|
uint8_t *logoData = loadBmpPixels(ctx, "logo.bmp", &imgW, &imgH, &imgPitch);
|
||||||
if (logoData) {
|
if (logoData) {
|
||||||
wgtImage(imgRow, logoData, imgW, imgH, imgPitch);
|
wgtImage(imgRow, logoData, imgW, imgH, imgPitch);
|
||||||
|
|
@ -534,19 +570,19 @@ static void setupControlsWindow(AppContextT *ctx) {
|
||||||
wgtVSeparator(imgRow);
|
wgtVSeparator(imgRow);
|
||||||
wgtLabel(imgRow, "32x32 DV/X logo");
|
wgtLabel(imgRow, "32x32 DV/X logo");
|
||||||
|
|
||||||
// --- Tab 6: Editor (TextArea, Canvas) ---
|
// --- Tab 7: Editor (TextArea, Canvas) ---
|
||||||
WidgetT *page6 = wgtTabPage(tabs, "&Editor");
|
WidgetT *page7e = wgtTabPage(tabs, "&Editor");
|
||||||
|
|
||||||
wgtLabel(page6, "TextArea:");
|
wgtLabel(page7e, "TextArea:");
|
||||||
WidgetT *ta = wgtTextArea(page6, 512);
|
WidgetT *ta = wgtTextArea(page7e, 512);
|
||||||
ta->weight = 100;
|
ta->weight = 100;
|
||||||
wgtSetText(ta, "Multi-line text editor.\n\nFeatures:\n- Word wrap\n- Selection\n- Copy/Paste\n- Undo (Ctrl+Z)");
|
wgtSetText(ta, "Multi-line text editor.\n\nFeatures:\n- Word wrap\n- Selection\n- Copy/Paste\n- Undo (Ctrl+Z)");
|
||||||
|
|
||||||
wgtHSeparator(page6);
|
wgtHSeparator(page7e);
|
||||||
|
|
||||||
wgtLabel(page6, "Canvas (draw with mouse):");
|
wgtLabel(page7e, "Canvas (draw with mouse):");
|
||||||
const DisplayT *d = dvxGetDisplay(ctx);
|
const DisplayT *d = dvxGetDisplay(ctx);
|
||||||
WidgetT *cv = wgtCanvas(page6, 280, 80);
|
WidgetT *cv = wgtCanvas(page7e, 280, 80);
|
||||||
wgtCanvasSetPenColor(cv, packColor(d, 200, 0, 0));
|
wgtCanvasSetPenColor(cv, packColor(d, 200, 0, 0));
|
||||||
wgtCanvasDrawRect(cv, 5, 5, 50, 35);
|
wgtCanvasDrawRect(cv, 5, 5, 50, 35);
|
||||||
wgtCanvasSetPenColor(cv, packColor(d, 0, 0, 200));
|
wgtCanvasSetPenColor(cv, packColor(d, 0, 0, 200));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue