DVX_GUI/sdk/samples/widget/mywgt.c

239 lines
7.4 KiB
C

// mywgt.c -- Sample DVX widget with full BASIC interface
//
// A simple widget that draws a colored rectangle with centered text.
// Demonstrates:
// - Widget class registration (calcMinSize, paint, destroy)
// - Public C API (create function + API struct)
// - BASIC interface (properties, methods, events, WgtIfaceT)
//
// Build:
// i586-pc-msdosdjgpp-gcc -O2 -Wall -I../../include/core -c -o mywgt.o mywgt.c
// dxe3gen -o mywgt.wgt -U mywgt.o
//
// Deploy: copy mywgt.wgt to WIDGETS/<vendor>/MYWGT/ on the target.
// Optionally include MYWGT.DHS (C API docs) and MYWGT.BHS (BASIC docs).
#define DVX_WIDGET_IMPL
#include "dvxWgt.h"
#include "dvxWgtP.h"
#include "dvxDraw.h"
#include "dvxVideo.h"
#include <stdlib.h>
#include <string.h>
// ============================================================
// Widget data
// ============================================================
typedef struct {
char *text;
int32_t style; // 0=flat, 1=raised, 2=sunken
bool bold;
} MyWidgetDataT;
static int32_t sTypeId = -1;
// ============================================================
// Style enum names (for BASIC property panel dropdown)
// ============================================================
static const char *sStyleNames[] = { "Flat", "Raised", "Sunken", NULL };
// ============================================================
// Widget methods (vtable handlers)
// ============================================================
static void myCalcMinSize(WidgetT *w, const BitmapFontT *font) {
w->calcMinW = font->charWidth * 10;
w->calcMinH = font->charHeight + 8;
}
static void myPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
MyWidgetDataT *data = (MyWidgetDataT *)w->data;
uint32_t bg = colors->buttonFace;
uint32_t fg = colors->contentFg;
// Fill background
rectFill(d, ops, w->x, w->y, w->w, w->h, bg);
// Draw border based on style
if (data && data->style == 1) {
BevelStyleT bevel = BEVEL_RAISED(colors, 2);
drawBevel(d, ops, w->x, w->y, w->w, w->h, &bevel);
} else if (data && data->style == 2) {
BevelStyleT bevel = BEVEL_SUNKEN(colors, bg, 2);
drawBevel(d, ops, w->x, w->y, w->w, w->h, &bevel);
}
// Draw text centered
if (data && data->text) {
int32_t textW = textWidth(font, data->text);
int32_t tx = w->x + (w->w - textW) / 2;
int32_t ty = w->y + (w->h - font->charHeight) / 2;
drawText(d, ops, font, tx, ty, data->text, fg, bg, true);
}
}
static void myDestroy(WidgetT *w) {
MyWidgetDataT *data = (MyWidgetDataT *)w->data;
if (data) {
free(data->text);
free(data);
w->data = NULL;
}
}
// ============================================================
// Widget class definition
// ============================================================
static const WidgetClassT sClass = {
.version = WGT_CLASS_VERSION,
.flags = WCLASS_FOCUSABLE,
.handlers = {
[WGT_METHOD_PAINT] = (void *)myPaint,
[WGT_METHOD_CALC_MIN_SIZE] = (void *)myCalcMinSize,
[WGT_METHOD_DESTROY] = (void *)myDestroy,
}
};
// ============================================================
// C API — called by apps via wgtGetApi("mywgt")
// ============================================================
static WidgetT *myWidgetCreate(WidgetT *parent, const char *text) {
WidgetT *w = widgetAlloc(parent, sTypeId);
if (w) {
MyWidgetDataT *data = (MyWidgetDataT *)calloc(1, sizeof(MyWidgetDataT));
if (data) {
data->text = text ? strdup(text) : NULL;
data->style = 0;
data->bold = false;
}
w->data = data;
}
return w;
}
static void myWidgetSetStyle(WidgetT *w, int32_t style) {
MyWidgetDataT *data = (MyWidgetDataT *)w->data;
if (data) {
data->style = style;
wgtInvalidatePaint(w);
}
}
static int32_t myWidgetGetStyle(const WidgetT *w) {
MyWidgetDataT *data = (MyWidgetDataT *)w->data;
return data ? data->style : 0;
}
static void myWidgetSetBold(WidgetT *w, bool bold) {
MyWidgetDataT *data = (MyWidgetDataT *)w->data;
if (data) {
data->bold = bold;
wgtInvalidatePaint(w);
}
}
static bool myWidgetGetBold(const WidgetT *w) {
MyWidgetDataT *data = (MyWidgetDataT *)w->data;
return data ? data->bold : false;
}
static void myWidgetClear(WidgetT *w) {
MyWidgetDataT *data = (MyWidgetDataT *)w->data;
if (data) {
free(data->text);
data->text = NULL;
wgtInvalidatePaint(w);
}
}
static const struct {
WidgetT *(*create)(WidgetT *parent, const char *text);
void (*setStyle)(WidgetT *w, int32_t style);
int32_t (*getStyle)(const WidgetT *w);
void (*setBold)(WidgetT *w, bool bold);
bool (*getBold)(const WidgetT *w);
void (*clear)(WidgetT *w);
} sApi = {
.create = myWidgetCreate,
.setStyle = myWidgetSetStyle,
.getStyle = myWidgetGetStyle,
.setBold = myWidgetSetBold,
.getBold = myWidgetGetBold,
.clear = myWidgetClear,
};
// ============================================================
// BASIC interface — describes properties, methods, and events
// for the form runtime and IDE property panel
// ============================================================
// Properties accessible from BASIC (e.g., MyWidget1.Style = 2)
static const WgtPropDescT sProps[] = {
// String property: Caption (read/write via SET_TEXT/GET_TEXT)
// Common properties like Caption, Left, Top, Width, Height are
// handled automatically by the form runtime. Only list type-specific
// properties here.
// Enum property: Style (Flat=0, Raised=1, Sunken=2)
{ "Style", WGT_IFACE_ENUM, (void *)myWidgetGetStyle, (void *)myWidgetSetStyle, sStyleNames },
// Boolean property: Bold
{ "Bold", WGT_IFACE_BOOL, (void *)myWidgetGetBold, (void *)myWidgetSetBold, NULL },
};
// Methods callable from BASIC (e.g., MyWidget1.Clear)
static const WgtMethodDescT sMethods[] = {
{ "Clear", WGT_SIG_VOID, (void *)myWidgetClear },
};
// Events beyond the common set (Click, DblClick, Change, GotFocus, LostFocus).
// Only list EXTRA events here — common events are wired automatically.
static const WgtEventDescT sEvents[] = {
{ "StyleChange" },
};
static const WgtIfaceT sIface = {
.basName = "MyWidget", // VB-style control name (used in .frm files)
.props = sProps,
.propCount = sizeof(sProps) / sizeof(sProps[0]),
.methods = sMethods,
.methodCount = sizeof(sMethods) / sizeof(sMethods[0]),
.events = sEvents,
.eventCount = sizeof(sEvents) / sizeof(sEvents[0]),
.createSig = WGT_CREATE_PARENT_TEXT, // create(parent, text)
.createArgs = {0}, // no default numeric args
.isContainer = false, // cannot hold child widgets
.defaultEvent = "Click", // double-click in IDE opens this event
.namePrefix = "MyWidget", // auto-names: MyWidget1, MyWidget2, ...
};
// ============================================================
// Registration — called by the loader at startup
// ============================================================
void wgtRegister(void) {
sTypeId = wgtRegisterClass(&sClass);
wgtRegisterApi("mywgt", &sApi);
wgtRegisterIface("mywgt", &sIface);
}