New ImageButton widget.
This commit is contained in:
parent
b6c5ee3cf3
commit
856cc194b2
9 changed files with 174 additions and 4 deletions
21
README.md
21
README.md
|
|
@ -7,7 +7,7 @@ Motif-style beveled chrome, dirty-rectangle compositing, draggable and
|
|||
resizable windows, dropdown menus, scrollbars, and a declarative widget/layout
|
||||
system with buttons, checkboxes, radios, text inputs, dropdowns, combo boxes,
|
||||
sliders, progress bars, tab controls, tree views, toolbars, status bars,
|
||||
images, and drawable canvases.
|
||||
images, image buttons, and drawable canvases.
|
||||
|
||||
## Building
|
||||
|
||||
|
|
@ -573,6 +573,25 @@ Display a bitmap image. `wgtImage` takes ownership of the pixel buffer
|
|||
stb_image and converts to the display pixel format. Set `onClick` to
|
||||
make the image clickable.
|
||||
|
||||
### ImageButton
|
||||
|
||||
```c
|
||||
WidgetT *wgtImageButton(WidgetT *parent, uint8_t *data,
|
||||
int32_t w, int32_t h, int32_t pitch);
|
||||
void wgtImageButtonSetData(WidgetT *w, uint8_t *data,
|
||||
int32_t imgW, int32_t imgH, int32_t pitch);
|
||||
```
|
||||
Push button that displays an image instead of a text caption. Behaves
|
||||
identically to `wgtButton` -- visually depresses on mouse-down, tracks the
|
||||
cursor while held, and fires `onClick` on release if still over the button.
|
||||
The image is centered on the button face with a 2px bevel border and no
|
||||
extra padding. When pressed, the image shifts 1px down and right.
|
||||
|
||||
`wgtImageButton` takes ownership of the pixel buffer (freed on destroy).
|
||||
`wgtImageButtonSetData` replaces the image data, freeing the previous buffer.
|
||||
The pixel buffer must be in display pixel format (use `packColor()` and the
|
||||
display's `bytesPerPixel` to prepare it).
|
||||
|
||||
### Canvas
|
||||
|
||||
```c
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ WSRCS = widgets/widgetCore.c \
|
|||
widgets/widgetDropdown.c \
|
||||
widgets/widgetCanvas.c \
|
||||
widgets/widgetImage.c \
|
||||
widgets/widgetImageButton.c \
|
||||
widgets/widgetLabel.c \
|
||||
widgets/widgetListBox.c \
|
||||
widgets/widgetProgressBar.c \
|
||||
|
|
@ -86,6 +87,7 @@ $(WOBJDIR)/widgetCheckbox.o: widgets/widgetCheckbox.c $(WIDGET_DEPS)
|
|||
$(WOBJDIR)/widgetComboBox.o: widgets/widgetComboBox.c $(WIDGET_DEPS)
|
||||
$(WOBJDIR)/widgetDropdown.o: widgets/widgetDropdown.c $(WIDGET_DEPS)
|
||||
$(WOBJDIR)/widgetImage.o: widgets/widgetImage.c $(WIDGET_DEPS) thirdparty/stb_image.h
|
||||
$(WOBJDIR)/widgetImageButton.o: widgets/widgetImageButton.c $(WIDGET_DEPS)
|
||||
$(WOBJDIR)/widgetLabel.o: widgets/widgetLabel.c $(WIDGET_DEPS)
|
||||
$(WOBJDIR)/widgetListBox.o: widgets/widgetListBox.c $(WIDGET_DEPS)
|
||||
$(WOBJDIR)/widgetProgressBar.o: widgets/widgetProgressBar.c $(WIDGET_DEPS)
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ typedef enum {
|
|||
WidgetTreeViewE,
|
||||
WidgetTreeItemE,
|
||||
WidgetImageE,
|
||||
WidgetImageButtonE,
|
||||
WidgetCanvasE
|
||||
} WidgetTypeE;
|
||||
|
||||
|
|
@ -264,6 +265,14 @@ typedef struct WidgetT {
|
|||
bool pressed;
|
||||
} image;
|
||||
|
||||
struct {
|
||||
uint8_t *data; // pixel buffer in display format
|
||||
int32_t imgW;
|
||||
int32_t imgH;
|
||||
int32_t imgPitch;
|
||||
bool pressed;
|
||||
} imageButton;
|
||||
|
||||
struct {
|
||||
uint8_t *data; // pixel buffer in display format
|
||||
int32_t canvasW;
|
||||
|
|
@ -379,6 +388,17 @@ WidgetT *wgtTreeItem(WidgetT *parent, const char *text);
|
|||
void wgtTreeItemSetExpanded(WidgetT *w, bool expanded);
|
||||
bool wgtTreeItemIsExpanded(const WidgetT *w);
|
||||
|
||||
// ============================================================
|
||||
// ImageButton
|
||||
// ============================================================
|
||||
|
||||
// Create an image button from raw pixel data (display format).
|
||||
// Takes ownership of the data buffer (freed on destroy).
|
||||
WidgetT *wgtImageButton(WidgetT *parent, uint8_t *data, int32_t w, int32_t h, int32_t pitch);
|
||||
|
||||
// Replace the image data. Takes ownership of the new buffer.
|
||||
void wgtImageButtonSetData(WidgetT *w, uint8_t *data, int32_t imgW, int32_t imgH, int32_t pitch);
|
||||
|
||||
// ============================================================
|
||||
// Image
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ void widgetDestroyChildren(WidgetT *w) {
|
|||
free(child->as.image.data);
|
||||
} else if (child->type == WidgetCanvasE) {
|
||||
free(child->as.canvas.data);
|
||||
} else if (child->type == WidgetImageButtonE) {
|
||||
free(child->as.imageButton.data);
|
||||
}
|
||||
|
||||
// Clear popup/drag references if they point to destroyed widgets
|
||||
|
|
|
|||
|
|
@ -330,7 +330,11 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
|||
|
||||
// Handle button press release
|
||||
if (sPressedButton && !(buttons & 1)) {
|
||||
sPressedButton->as.button.pressed = false;
|
||||
if (sPressedButton->type == WidgetImageButtonE) {
|
||||
sPressedButton->as.imageButton.pressed = false;
|
||||
} else {
|
||||
sPressedButton->as.button.pressed = false;
|
||||
}
|
||||
|
||||
// Fire onClick if released over the same button in the same window
|
||||
if (sPressedButton->window == win) {
|
||||
|
|
@ -366,8 +370,17 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
|||
vy >= sPressedButton->y && vy < sPressedButton->y + sPressedButton->h);
|
||||
}
|
||||
|
||||
if (sPressedButton->as.button.pressed != over) {
|
||||
sPressedButton->as.button.pressed = over;
|
||||
bool curPressed = (sPressedButton->type == WidgetImageButtonE)
|
||||
? sPressedButton->as.imageButton.pressed
|
||||
: sPressedButton->as.button.pressed;
|
||||
|
||||
if (curPressed != over) {
|
||||
if (sPressedButton->type == WidgetImageButtonE) {
|
||||
sPressedButton->as.imageButton.pressed = over;
|
||||
} else {
|
||||
sPressedButton->as.button.pressed = over;
|
||||
}
|
||||
|
||||
wgtInvalidate(sPressedButton);
|
||||
}
|
||||
|
||||
|
|
@ -499,6 +512,10 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
|||
widgetImageOnMouse(hit);
|
||||
}
|
||||
|
||||
if (hit->type == WidgetImageButtonE && hit->enabled) {
|
||||
widgetImageButtonOnMouse(hit);
|
||||
}
|
||||
|
||||
if (hit->type == WidgetCanvasE && hit->enabled) {
|
||||
widgetCanvasOnMouse(hit, vx, vy);
|
||||
}
|
||||
|
|
|
|||
100
dvx/widgets/widgetImageButton.c
Normal file
100
dvx/widgets/widgetImageButton.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// widgetImageButton.c — Image button widget (button with image instead of text)
|
||||
|
||||
#include "widgetInternal.h"
|
||||
|
||||
|
||||
// ============================================================
|
||||
// wgtImageButton
|
||||
// ============================================================
|
||||
|
||||
WidgetT *wgtImageButton(WidgetT *parent, uint8_t *data, int32_t w, int32_t h, int32_t pitch) {
|
||||
if (!parent || !data || w <= 0 || h <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WidgetT *wgt = widgetAlloc(parent, WidgetImageButtonE);
|
||||
|
||||
if (wgt) {
|
||||
wgt->as.imageButton.data = data;
|
||||
wgt->as.imageButton.imgW = w;
|
||||
wgt->as.imageButton.imgH = h;
|
||||
wgt->as.imageButton.imgPitch = pitch;
|
||||
wgt->as.imageButton.pressed = false;
|
||||
} else {
|
||||
free(data);
|
||||
}
|
||||
|
||||
return wgt;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// wgtImageButtonSetData
|
||||
// ============================================================
|
||||
|
||||
void wgtImageButtonSetData(WidgetT *w, uint8_t *data, int32_t imgW, int32_t imgH, int32_t pitch) {
|
||||
if (!w || w->type != WidgetImageButtonE) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(w->as.imageButton.data);
|
||||
w->as.imageButton.data = data;
|
||||
w->as.imageButton.imgW = imgW;
|
||||
w->as.imageButton.imgH = imgH;
|
||||
w->as.imageButton.imgPitch = pitch;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// widgetImageButtonCalcMinSize
|
||||
// ============================================================
|
||||
|
||||
void widgetImageButtonCalcMinSize(WidgetT *w, const BitmapFontT *font) {
|
||||
(void)font;
|
||||
|
||||
// Bevel border only, no extra padding
|
||||
w->calcMinW = w->as.imageButton.imgW + 4;
|
||||
w->calcMinH = w->as.imageButton.imgH + 4;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// widgetImageButtonOnMouse
|
||||
// ============================================================
|
||||
|
||||
void widgetImageButtonOnMouse(WidgetT *hit) {
|
||||
hit->as.imageButton.pressed = true;
|
||||
sPressedButton = hit;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// widgetImageButtonPaint
|
||||
// ============================================================
|
||||
|
||||
void widgetImageButtonPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
|
||||
(void)font;
|
||||
|
||||
uint32_t bgFace = w->bgColor ? w->bgColor : colors->buttonFace;
|
||||
|
||||
BevelStyleT bevel;
|
||||
bevel.highlight = w->as.imageButton.pressed ? colors->windowShadow : colors->windowHighlight;
|
||||
bevel.shadow = w->as.imageButton.pressed ? colors->windowHighlight : colors->windowShadow;
|
||||
bevel.face = bgFace;
|
||||
bevel.width = 2;
|
||||
drawBevel(d, ops, w->x, w->y, w->w, w->h, &bevel);
|
||||
|
||||
if (w->as.imageButton.data) {
|
||||
int32_t imgX = w->x + (w->w - w->as.imageButton.imgW) / 2;
|
||||
int32_t imgY = w->y + (w->h - w->as.imageButton.imgH) / 2;
|
||||
|
||||
if (w->as.imageButton.pressed) {
|
||||
imgX++;
|
||||
imgY++;
|
||||
}
|
||||
|
||||
rectCopy(d, ops, imgX, imgY,
|
||||
w->as.imageButton.data, w->as.imageButton.imgPitch,
|
||||
0, 0, w->as.imageButton.imgW, w->as.imageButton.imgH);
|
||||
}
|
||||
}
|
||||
|
|
@ -98,6 +98,7 @@ void widgetPaintOverlays(WidgetT *root, DisplayT *d, const BlitOpsT *ops, const
|
|||
// ============================================================
|
||||
|
||||
void widgetButtonPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||
void widgetImageButtonPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||
void widgetCanvasPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||
void widgetCheckboxPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||
void widgetComboBoxPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors);
|
||||
|
|
@ -122,6 +123,7 @@ void widgetTreeViewPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const Bit
|
|||
// ============================================================
|
||||
|
||||
void widgetButtonCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||
void widgetImageButtonCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||
void widgetCanvasCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||
void widgetCheckboxCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||
void widgetComboBoxCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||
|
|
@ -148,6 +150,7 @@ void widgetTreeViewLayout(WidgetT *w, const BitmapFontT *font);
|
|||
// ============================================================
|
||||
|
||||
void widgetButtonOnMouse(WidgetT *hit);
|
||||
void widgetImageButtonOnMouse(WidgetT *hit);
|
||||
void widgetCanvasOnMouse(WidgetT *hit, int32_t vx, int32_t vy);
|
||||
void widgetCheckboxOnMouse(WidgetT *hit);
|
||||
void widgetComboBoxOnMouse(WidgetT *hit, WidgetT *root, int32_t vx);
|
||||
|
|
|
|||
|
|
@ -121,6 +121,9 @@ void widgetCalcMinSizeTree(WidgetT *w, const BitmapFontT *font) {
|
|||
case WidgetImageE:
|
||||
widgetImageCalcMinSize(w, font);
|
||||
break;
|
||||
case WidgetImageButtonE:
|
||||
widgetImageButtonCalcMinSize(w, font);
|
||||
break;
|
||||
case WidgetCanvasE:
|
||||
widgetCanvasCalcMinSize(w, font);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ void widgetPaintOne(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFo
|
|||
widgetImagePaint(w, d, ops, font, colors);
|
||||
break;
|
||||
|
||||
case WidgetImageButtonE:
|
||||
widgetImageButtonPaint(w, d, ops, font, colors);
|
||||
break;
|
||||
|
||||
case WidgetCanvasE:
|
||||
widgetCanvasPaint(w, d, ops, font, colors);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue