DVX_GUI/dvx/widgets/widgetDropdown.c

186 lines
5.9 KiB
C

// widgetDropdown.c — Dropdown (select) widget
#include "widgetInternal.h"
// ============================================================
// wgtDropdown
// ============================================================
WidgetT *wgtDropdown(WidgetT *parent) {
WidgetT *w = widgetAlloc(parent, WidgetDropdownE);
if (w) {
w->as.dropdown.selectedIdx = -1;
w->as.dropdown.hoverIdx = -1;
}
return w;
}
// ============================================================
// wgtDropdownGetSelected
// ============================================================
int32_t wgtDropdownGetSelected(const WidgetT *w) {
if (!w || w->type != WidgetDropdownE) {
return -1;
}
return w->as.dropdown.selectedIdx;
}
// ============================================================
// wgtDropdownSetItems
// ============================================================
void wgtDropdownSetItems(WidgetT *w, const char **items, int32_t count) {
if (!w || w->type != WidgetDropdownE) {
return;
}
w->as.dropdown.items = items;
w->as.dropdown.itemCount = count;
if (w->as.dropdown.selectedIdx >= count) {
w->as.dropdown.selectedIdx = -1;
}
}
// ============================================================
// wgtDropdownSetSelected
// ============================================================
void wgtDropdownSetSelected(WidgetT *w, int32_t idx) {
if (!w || w->type != WidgetDropdownE) {
return;
}
w->as.dropdown.selectedIdx = idx;
}
// ============================================================
// widgetDropdownCalcMinSize
// ============================================================
void widgetDropdownCalcMinSize(WidgetT *w, const BitmapFontT *font) {
// Width: widest item + button width + border
int32_t maxItemW = font->charWidth * 8;
for (int32_t i = 0; i < w->as.dropdown.itemCount; i++) {
int32_t iw = (int32_t)strlen(w->as.dropdown.items[i]) * font->charWidth;
if (iw > maxItemW) {
maxItemW = iw;
}
}
w->calcMinW = maxItemW + DROPDOWN_BTN_WIDTH + TEXT_INPUT_PAD * 2 + 4;
w->calcMinH = font->charHeight + TEXT_INPUT_PAD * 2;
}
// ============================================================
// widgetDropdownOnMouse
// ============================================================
void widgetDropdownOnMouse(WidgetT *hit) {
hit->as.dropdown.open = !hit->as.dropdown.open;
hit->as.dropdown.hoverIdx = hit->as.dropdown.selectedIdx;
sOpenPopup = hit->as.dropdown.open ? hit : NULL;
}
// ============================================================
// widgetDropdownPaint
// ============================================================
void widgetDropdownPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
uint32_t fg = w->fgColor ? w->fgColor : colors->contentFg;
uint32_t bg = w->bgColor ? w->bgColor : colors->contentBg;
// Sunken text area
int32_t textAreaW = w->w - DROPDOWN_BTN_WIDTH;
BevelStyleT bevel;
bevel.highlight = colors->windowShadow;
bevel.shadow = colors->windowHighlight;
bevel.face = bg;
bevel.width = 2;
drawBevel(d, ops, w->x, w->y, textAreaW, w->h, &bevel);
// Draw selected item text
if (w->as.dropdown.selectedIdx >= 0 && w->as.dropdown.selectedIdx < w->as.dropdown.itemCount) {
drawText(d, ops, font, w->x + TEXT_INPUT_PAD,
w->y + (w->h - font->charHeight) / 2,
w->as.dropdown.items[w->as.dropdown.selectedIdx], fg, bg, true);
}
// Drop button
BevelStyleT btnBevel;
btnBevel.highlight = w->as.dropdown.open ? colors->windowShadow : colors->windowHighlight;
btnBevel.shadow = w->as.dropdown.open ? colors->windowHighlight : colors->windowShadow;
btnBevel.face = colors->buttonFace;
btnBevel.width = 2;
drawBevel(d, ops, w->x + textAreaW, w->y, DROPDOWN_BTN_WIDTH, w->h, &btnBevel);
// Down arrow in button
int32_t arrowX = w->x + textAreaW + DROPDOWN_BTN_WIDTH / 2;
int32_t arrowY = w->y + w->h / 2 - 1;
for (int32_t i = 0; i < 4; i++) {
drawHLine(d, ops, arrowX - 3 + i, arrowY + i, 7 - i * 2, colors->contentFg);
}
}
// ============================================================
// widgetDropdownPaintPopup
// ============================================================
void widgetDropdownPaintPopup(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
int32_t popX;
int32_t popY;
int32_t popW;
int32_t popH;
widgetDropdownPopupRect(w, font, d->clipH, &popX, &popY, &popW, &popH);
// Draw popup border
BevelStyleT bevel;
bevel.highlight = colors->windowHighlight;
bevel.shadow = colors->windowShadow;
bevel.face = colors->contentBg;
bevel.width = 2;
drawBevel(d, ops, popX, popY, popW, popH, &bevel);
// Draw items
int32_t itemCount = w->as.dropdown.itemCount;
const char **items = w->as.dropdown.items;
int32_t selIdx = w->as.dropdown.selectedIdx;
int32_t hoverIdx = w->as.dropdown.hoverIdx;
int32_t scrollPos = w->as.dropdown.scrollPos;
int32_t visibleItems = popH / font->charHeight;
int32_t textX = popX + TEXT_INPUT_PAD;
int32_t textY = popY + 2;
int32_t textW = popW - TEXT_INPUT_PAD * 2 - 4;
for (int32_t i = 0; i < visibleItems && (scrollPos + i) < itemCount; i++) {
int32_t idx = scrollPos + i;
int32_t iy = textY + i * font->charHeight;
uint32_t ifg = colors->contentFg;
uint32_t ibg = colors->contentBg;
if (idx == hoverIdx || idx == selIdx) {
ifg = colors->menuHighlightFg;
ibg = colors->menuHighlightBg;
rectFill(d, ops, popX + 2, iy, textW + TEXT_INPUT_PAD * 2, font->charHeight, ibg);
}
drawText(d, ops, font, textX, iy, items[idx], ifg, ibg, idx == hoverIdx || idx == selIdx);
}
}