151 lines
4.2 KiB
C
151 lines
4.2 KiB
C
#define DVX_WIDGET_IMPL
|
|
// widgetSeparator.c -- Separator widget (horizontal and vertical)
|
|
//
|
|
// A purely decorative widget that draws a 2px etched line (shadow +
|
|
// highlight pair) to visually divide groups of widgets. The etched
|
|
// line technique (dark line followed by light line offset by 1px)
|
|
// creates a subtle 3D groove that matches the Motif/Win3.1 aesthetic.
|
|
//
|
|
// Separate constructors (wgtHSeparator/wgtVSeparator) rather than a
|
|
// runtime orientation parameter because separators are always fixed
|
|
// orientation at construction time.
|
|
//
|
|
// The min size in the cross-axis is SEPARATOR_THICKNESS (2px), while
|
|
// the main axis min is 0 -- the separator stretches to fill the
|
|
// available width/height in its parent layout. This makes separators
|
|
// work correctly in both HBox and VBox containers without explicit
|
|
// sizing.
|
|
//
|
|
// No mouse/key handlers -- purely decorative, non-focusable.
|
|
|
|
#include "dvxWidgetPlugin.h"
|
|
|
|
#define SEPARATOR_THICKNESS 2
|
|
|
|
static int32_t sTypeId = -1;
|
|
|
|
typedef struct {
|
|
bool vertical;
|
|
} SeparatorDataT;
|
|
|
|
|
|
// ============================================================
|
|
// Prototypes
|
|
// ============================================================
|
|
|
|
static void widgetSeparatorDestroy(WidgetT *w);
|
|
|
|
|
|
// ============================================================
|
|
// widgetSeparatorCalcMinSize
|
|
// ============================================================
|
|
|
|
void widgetSeparatorCalcMinSize(WidgetT *w, const BitmapFontT *font) {
|
|
(void)font;
|
|
SeparatorDataT *d = (SeparatorDataT *)w->data;
|
|
|
|
if (d->vertical) {
|
|
w->calcMinW = SEPARATOR_THICKNESS;
|
|
w->calcMinH = 0;
|
|
} else {
|
|
w->calcMinW = 0;
|
|
w->calcMinH = SEPARATOR_THICKNESS;
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// widgetSeparatorDestroy
|
|
// ============================================================
|
|
|
|
static void widgetSeparatorDestroy(WidgetT *w) {
|
|
free(w->data);
|
|
w->data = NULL;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// widgetSeparatorPaint
|
|
// ============================================================
|
|
|
|
void widgetSeparatorPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
|
|
(void)font;
|
|
SeparatorDataT *sd = (SeparatorDataT *)w->data;
|
|
|
|
if (sd->vertical) {
|
|
int32_t cx = w->x + w->w / 2;
|
|
drawVLine(d, ops, cx, w->y, w->h, colors->windowShadow);
|
|
drawVLine(d, ops, cx + 1, w->y, w->h, colors->windowHighlight);
|
|
} else {
|
|
int32_t cy = w->y + w->h / 2;
|
|
drawHLine(d, ops, w->x, cy, w->w, colors->windowShadow);
|
|
drawHLine(d, ops, w->x, cy + 1, w->w, colors->windowHighlight);
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// DXE registration
|
|
// ============================================================
|
|
|
|
|
|
static const WidgetClassT sClassSeparator = {
|
|
.flags = 0,
|
|
.paint = widgetSeparatorPaint,
|
|
.paintOverlay = NULL,
|
|
.calcMinSize = widgetSeparatorCalcMinSize,
|
|
.layout = NULL,
|
|
.onMouse = NULL,
|
|
.onKey = NULL,
|
|
.destroy = widgetSeparatorDestroy,
|
|
.getText = NULL,
|
|
.setText = NULL
|
|
};
|
|
|
|
// ============================================================
|
|
// Widget creation functions
|
|
// ============================================================
|
|
|
|
|
|
WidgetT *wgtHSeparator(WidgetT *parent) {
|
|
WidgetT *w = widgetAlloc(parent, sTypeId);
|
|
|
|
if (w) {
|
|
SeparatorDataT *d = calloc(1, sizeof(SeparatorDataT));
|
|
w->data = d;
|
|
}
|
|
|
|
return w;
|
|
}
|
|
|
|
|
|
WidgetT *wgtVSeparator(WidgetT *parent) {
|
|
WidgetT *w = widgetAlloc(parent, sTypeId);
|
|
|
|
if (w) {
|
|
SeparatorDataT *d = calloc(1, sizeof(SeparatorDataT));
|
|
w->data = d;
|
|
d->vertical = true;
|
|
}
|
|
|
|
return w;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// DXE registration
|
|
// ============================================================
|
|
|
|
|
|
static const struct {
|
|
WidgetT *(*hSeparator)(WidgetT *parent);
|
|
WidgetT *(*vSeparator)(WidgetT *parent);
|
|
} sApi = {
|
|
.hSeparator = wgtHSeparator,
|
|
.vSeparator = wgtVSeparator
|
|
};
|
|
|
|
void wgtRegister(void) {
|
|
sTypeId = wgtRegisterClass(&sClassSeparator);
|
|
wgtRegisterApi("separator", &sApi);
|
|
}
|