239 lines
7.4 KiB
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 -E _wgtRegister -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);
|
|
}
|