#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 text pointer is stored directly (not copied) -- the caller must ensure // the string remains valid for the widget's lifetime, or use widgetLabelSetText // to update it. This avoids unnecessary allocations for the common case of // literal string labels. // // 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 "dvxWidgetPlugin.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) { 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; d->text = text; w->accelKey = accelParse(text); } // ============================================================ // DXE registration // ============================================================ static const WidgetClassT sClassLabel = { .flags = WCLASS_FOCUS_FORWARD, .paint = widgetLabelPaint, .paintOverlay = NULL, .calcMinSize = widgetLabelCalcMinSize, .layout = NULL, .onMouse = NULL, .onKey = NULL, .destroy = widgetLabelDestroy, .getText = widgetLabelGetText, .setText = 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; 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; } } // ============================================================ // DXE registration // ============================================================ static const struct { WidgetT *(*create)(WidgetT *parent, const char *text); void (*setAlign)(WidgetT *w, WidgetAlignE align); } sApi = { .create = wgtLabel, .setAlign = wgtLabelSetAlign }; void wgtRegister(void) { sTypeId = wgtRegisterClass(&sClassLabel); wgtRegisterApi("label", &sApi); }