196 lines
5.7 KiB
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);
|
|
}
|