DVX_GUI/widgets/label/widgetLabel.c

196 lines
5.7 KiB
C

#define DVX_WIDGET_IMPL
// widgetLabel.c -- Label widget
//
// Static text display -- the simplest widget. Not focusable, not interactive.
// Supports accelerator keys via '&' prefix: when the user presses Alt+key,
// focus moves to the next focusable widget after this label. This follows
// the Win3.1 convention where labels act as keyboard shortcuts for adjacent
// controls (e.g., a label "&Name:" before a text input).
//
// The widget owns its text string (strdup'd on set, freed on destroy).
// Callers can pass transient strings safely.
//
// Background is transparent by default (bgColor == 0 means use the parent's
// content background color from the color scheme). The +1 in calcMinH adds a
// pixel of breathing room below the text baseline.
#include "dvxWgtP.h"
static int32_t sTypeId = -1;
typedef struct {
const char *text;
WidgetAlignE textAlign;
} LabelDataT;
// ============================================================
// Prototypes
// ============================================================
static void widgetLabelDestroy(WidgetT *w);
// ============================================================
// widgetLabelCalcMinSize
// ============================================================
void widgetLabelCalcMinSize(WidgetT *w, const BitmapFontT *font) {
LabelDataT *d = (LabelDataT *)w->data;
w->calcMinW = textWidthAccel(font, d->text);
w->calcMinH = font->charHeight + 1;
}
// ============================================================
// widgetLabelDestroy
// ============================================================
static void widgetLabelDestroy(WidgetT *w) {
LabelDataT *d = (LabelDataT *)w->data;
free((void *)d->text);
free(w->data);
w->data = NULL;
}
// ============================================================
// widgetLabelGetText
// ============================================================
const char *widgetLabelGetText(const WidgetT *w) {
LabelDataT *d = (LabelDataT *)w->data;
return d->text;
}
// ============================================================
// widgetLabelPaint
// ============================================================
void widgetLabelPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
LabelDataT *ld = (LabelDataT *)w->data;
int32_t textW = textWidthAccel(font, ld->text);
int32_t textX = w->x;
int32_t textY = w->y + (w->h - font->charHeight) / 2;
if (ld->textAlign == AlignCenterE) {
textX = w->x + (w->w - textW) / 2;
} else if (ld->textAlign == AlignEndE) {
textX = w->x + w->w - textW;
}
if (!w->enabled) {
drawTextAccelEmbossed(d, ops, font, textX, textY, ld->text, colors);
return;
}
uint32_t fg = w->fgColor ? w->fgColor : colors->contentFg;
uint32_t bg = w->bgColor ? w->bgColor : colors->contentBg;
drawTextAccel(d, ops, font, textX, textY, ld->text, fg, bg, false);
}
// ============================================================
// widgetLabelSetText
// ============================================================
void widgetLabelSetText(WidgetT *w, const char *text) {
LabelDataT *d = (LabelDataT *)w->data;
free((void *)d->text);
d->text = text ? strdup(text) : NULL;
w->accelKey = accelParse(text);
}
// ============================================================
// DXE registration
// ============================================================
static const WidgetClassT sClassLabel = {
.version = WGT_CLASS_VERSION,
.flags = WCLASS_FOCUS_FORWARD,
.handlers = {
[WGT_METHOD_PAINT] = (void *)widgetLabelPaint,
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetLabelCalcMinSize,
[WGT_METHOD_DESTROY] = (void *)widgetLabelDestroy,
[WGT_METHOD_GET_TEXT] = (void *)widgetLabelGetText,
[WGT_METHOD_SET_TEXT] = (void *)widgetLabelSetText,
}
};
// ============================================================
// Widget creation functions
// ============================================================
WidgetT *wgtLabel(WidgetT *parent, const char *text) {
WidgetT *w = widgetAlloc(parent, sTypeId);
if (w) {
LabelDataT *d = calloc(1, sizeof(LabelDataT));
w->data = d;
d->text = text ? strdup(text) : NULL;
w->accelKey = accelParse(text);
}
return w;
}
void wgtLabelSetAlign(WidgetT *w, WidgetAlignE align) {
if (w && w->type == sTypeId) {
LabelDataT *d = (LabelDataT *)w->data;
d->textAlign = align;
}
}
int32_t wgtLabelGetAlign(const WidgetT *w) {
if (w && w->type == sTypeId) {
LabelDataT *d = (LabelDataT *)w->data;
return (int32_t)d->textAlign;
}
return 0;
}
// ============================================================
// DXE registration
// ============================================================
static const struct {
WidgetT *(*create)(WidgetT *parent, const char *text);
void (*setAlign)(WidgetT *w, WidgetAlignE align);
} sApi = {
.create = wgtLabel,
.setAlign = wgtLabelSetAlign
};
static const char *sAlignNames[] = { "Left", "Center", "Right", NULL };
static const WgtPropDescT sProps[] = {
{ "Alignment", WGT_IFACE_ENUM, (void *)wgtLabelGetAlign, (void *)wgtLabelSetAlign, sAlignNames }
};
static const WgtIfaceT sIface = {
.basName = "Label",
.props = sProps,
.propCount = 1,
.methods = NULL,
.methodCount = 0,
.events = NULL,
.eventCount = 0,
.createSig = WGT_CREATE_PARENT_TEXT,
.defaultEvent = "Click"
};
void wgtRegister(void) {
sTypeId = wgtRegisterClass(&sClassLabel);
wgtRegisterApi("label", &sApi);
wgtRegisterIface("label", &sIface);
}