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
|
resizable windows, dropdown menus, scrollbars, and a declarative widget/layout
|
||||||
system with buttons, checkboxes, radios, text inputs, dropdowns, combo boxes,
|
system with buttons, checkboxes, radios, text inputs, dropdowns, combo boxes,
|
||||||
sliders, progress bars, tab controls, tree views, toolbars, status bars,
|
sliders, progress bars, tab controls, tree views, toolbars, status bars,
|
||||||
images, and drawable canvases.
|
images, image buttons, and drawable canvases.
|
||||||
|
|
||||||
## Building
|
## 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
|
stb_image and converts to the display pixel format. Set `onClick` to
|
||||||
make the image clickable.
|
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
|
### Canvas
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ WSRCS = widgets/widgetCore.c \
|
||||||
widgets/widgetDropdown.c \
|
widgets/widgetDropdown.c \
|
||||||
widgets/widgetCanvas.c \
|
widgets/widgetCanvas.c \
|
||||||
widgets/widgetImage.c \
|
widgets/widgetImage.c \
|
||||||
|
widgets/widgetImageButton.c \
|
||||||
widgets/widgetLabel.c \
|
widgets/widgetLabel.c \
|
||||||
widgets/widgetListBox.c \
|
widgets/widgetListBox.c \
|
||||||
widgets/widgetProgressBar.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)/widgetComboBox.o: widgets/widgetComboBox.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetDropdown.o: widgets/widgetDropdown.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetDropdown.o: widgets/widgetDropdown.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetImage.o: widgets/widgetImage.c $(WIDGET_DEPS) thirdparty/stb_image.h
|
$(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)/widgetLabel.o: widgets/widgetLabel.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetListBox.o: widgets/widgetListBox.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetListBox.o: widgets/widgetListBox.c $(WIDGET_DEPS)
|
||||||
$(WOBJDIR)/widgetProgressBar.o: widgets/widgetProgressBar.c $(WIDGET_DEPS)
|
$(WOBJDIR)/widgetProgressBar.o: widgets/widgetProgressBar.c $(WIDGET_DEPS)
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ typedef enum {
|
||||||
WidgetTreeViewE,
|
WidgetTreeViewE,
|
||||||
WidgetTreeItemE,
|
WidgetTreeItemE,
|
||||||
WidgetImageE,
|
WidgetImageE,
|
||||||
|
WidgetImageButtonE,
|
||||||
WidgetCanvasE
|
WidgetCanvasE
|
||||||
} WidgetTypeE;
|
} WidgetTypeE;
|
||||||
|
|
||||||
|
|
@ -264,6 +265,14 @@ typedef struct WidgetT {
|
||||||
bool pressed;
|
bool pressed;
|
||||||
} image;
|
} image;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t *data; // pixel buffer in display format
|
||||||
|
int32_t imgW;
|
||||||
|
int32_t imgH;
|
||||||
|
int32_t imgPitch;
|
||||||
|
bool pressed;
|
||||||
|
} imageButton;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t *data; // pixel buffer in display format
|
uint8_t *data; // pixel buffer in display format
|
||||||
int32_t canvasW;
|
int32_t canvasW;
|
||||||
|
|
@ -379,6 +388,17 @@ WidgetT *wgtTreeItem(WidgetT *parent, const char *text);
|
||||||
void wgtTreeItemSetExpanded(WidgetT *w, bool expanded);
|
void wgtTreeItemSetExpanded(WidgetT *w, bool expanded);
|
||||||
bool wgtTreeItemIsExpanded(const WidgetT *w);
|
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
|
// Image
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ void widgetDestroyChildren(WidgetT *w) {
|
||||||
free(child->as.image.data);
|
free(child->as.image.data);
|
||||||
} else if (child->type == WidgetCanvasE) {
|
} else if (child->type == WidgetCanvasE) {
|
||||||
free(child->as.canvas.data);
|
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
|
// 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
|
// Handle button press release
|
||||||
if (sPressedButton && !(buttons & 1)) {
|
if (sPressedButton && !(buttons & 1)) {
|
||||||
|
if (sPressedButton->type == WidgetImageButtonE) {
|
||||||
|
sPressedButton->as.imageButton.pressed = false;
|
||||||
|
} else {
|
||||||
sPressedButton->as.button.pressed = false;
|
sPressedButton->as.button.pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Fire onClick if released over the same button in the same window
|
// Fire onClick if released over the same button in the same window
|
||||||
if (sPressedButton->window == win) {
|
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);
|
vy >= sPressedButton->y && vy < sPressedButton->y + sPressedButton->h);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (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;
|
sPressedButton->as.button.pressed = over;
|
||||||
|
}
|
||||||
|
|
||||||
wgtInvalidate(sPressedButton);
|
wgtInvalidate(sPressedButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -499,6 +512,10 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) {
|
||||||
widgetImageOnMouse(hit);
|
widgetImageOnMouse(hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hit->type == WidgetImageButtonE && hit->enabled) {
|
||||||
|
widgetImageButtonOnMouse(hit);
|
||||||
|
}
|
||||||
|
|
||||||
if (hit->type == WidgetCanvasE && hit->enabled) {
|
if (hit->type == WidgetCanvasE && hit->enabled) {
|
||||||
widgetCanvasOnMouse(hit, vx, vy);
|
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 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 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 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);
|
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 widgetButtonCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
|
void widgetImageButtonCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetCanvasCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
void widgetCanvasCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetCheckboxCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
void widgetCheckboxCalcMinSize(WidgetT *w, const BitmapFontT *font);
|
||||||
void widgetComboBoxCalcMinSize(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 widgetButtonOnMouse(WidgetT *hit);
|
||||||
|
void widgetImageButtonOnMouse(WidgetT *hit);
|
||||||
void widgetCanvasOnMouse(WidgetT *hit, int32_t vx, int32_t vy);
|
void widgetCanvasOnMouse(WidgetT *hit, int32_t vx, int32_t vy);
|
||||||
void widgetCheckboxOnMouse(WidgetT *hit);
|
void widgetCheckboxOnMouse(WidgetT *hit);
|
||||||
void widgetComboBoxOnMouse(WidgetT *hit, WidgetT *root, int32_t vx);
|
void widgetComboBoxOnMouse(WidgetT *hit, WidgetT *root, int32_t vx);
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,9 @@ void widgetCalcMinSizeTree(WidgetT *w, const BitmapFontT *font) {
|
||||||
case WidgetImageE:
|
case WidgetImageE:
|
||||||
widgetImageCalcMinSize(w, font);
|
widgetImageCalcMinSize(w, font);
|
||||||
break;
|
break;
|
||||||
|
case WidgetImageButtonE:
|
||||||
|
widgetImageButtonCalcMinSize(w, font);
|
||||||
|
break;
|
||||||
case WidgetCanvasE:
|
case WidgetCanvasE:
|
||||||
widgetCanvasCalcMinSize(w, font);
|
widgetCanvasCalcMinSize(w, font);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,10 @@ void widgetPaintOne(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFo
|
||||||
widgetImagePaint(w, d, ops, font, colors);
|
widgetImagePaint(w, d, ops, font, colors);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WidgetImageButtonE:
|
||||||
|
widgetImageButtonPaint(w, d, ops, font, colors);
|
||||||
|
break;
|
||||||
|
|
||||||
case WidgetCanvasE:
|
case WidgetCanvasE:
|
||||||
widgetCanvasPaint(w, d, ops, font, colors);
|
widgetCanvasPaint(w, d, ops, font, colors);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue