// 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//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 #include // ============================================================ // 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); }