Compare commits
No commits in common. "93b912d932a591d8c1cad666e39e032bdeca9e05" and "7bc92549f715418930c220be7d1a31d8c597e95d" have entirely different histories.
93b912d932
...
7bc92549f7
20 changed files with 75 additions and 541 deletions
|
|
@ -33,8 +33,6 @@
|
||||||
#include "shellInfo.h"
|
#include "shellInfo.h"
|
||||||
#include "dvxResource.h"
|
#include "dvxResource.h"
|
||||||
#include "widgetImageButton.h"
|
#include "widgetImageButton.h"
|
||||||
#include "widgetScrollPane.h"
|
|
||||||
#include "widgetWrapBox.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
@ -44,16 +42,18 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "dvxMem.h"
|
#include "dvxMem.h"
|
||||||
#include "stb_ds_wrap.h"
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Constants
|
// Constants
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
|
// 64 entries is generous; limited by screen real estate before this cap
|
||||||
|
#define MAX_APP_FILES 64
|
||||||
// DOS 8.3 paths are short, but long names under DJGPP can reach ~260
|
// DOS 8.3 paths are short, but long names under DJGPP can reach ~260
|
||||||
#define MAX_PATH_LEN 260
|
#define MAX_PATH_LEN 260
|
||||||
// Grid layout for app buttons: 4 columns, rows created dynamically
|
// Grid layout for app buttons: 4 columns, rows created dynamically
|
||||||
#define PM_TOOLTIP_LEN 128
|
#define PM_TOOLTIP_LEN 128
|
||||||
|
#define PM_GRID_COLS 4
|
||||||
#define PM_BTN_W 100
|
#define PM_BTN_W 100
|
||||||
#define PM_BTN_H 24
|
#define PM_BTN_H 24
|
||||||
#define PM_CELL_W 80
|
#define PM_CELL_W 80
|
||||||
|
|
@ -102,7 +102,7 @@ static WidgetT *sStatusLabel = NULL;
|
||||||
static PrefsHandleT *sPrefs = NULL;
|
static PrefsHandleT *sPrefs = NULL;
|
||||||
static bool sMinOnRun = false;
|
static bool sMinOnRun = false;
|
||||||
static bool sRestoreAlone = false;
|
static bool sRestoreAlone = false;
|
||||||
static AppEntryT *sAppFiles = NULL; // stb_ds dynamic array
|
static AppEntryT sAppFiles[MAX_APP_FILES];
|
||||||
static int32_t sAppCount = 0;
|
static int32_t sAppCount = 0;
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -196,19 +196,18 @@ static void buildPmWindow(void) {
|
||||||
if (sAppCount == 0) {
|
if (sAppCount == 0) {
|
||||||
wgtLabel(appFrame, "(No applications found in apps/ directory)");
|
wgtLabel(appFrame, "(No applications found in apps/ directory)");
|
||||||
} else {
|
} else {
|
||||||
// ScrollPane provides scrollbars when icons overflow.
|
// Build grid of app icons. Each cell is a VBox with an image
|
||||||
// WrapBox inside flows cells left-to-right, wrapping to
|
// button (or text button if no icon) and a label underneath.
|
||||||
// the next row when the window width is exceeded.
|
WidgetT *hbox = NULL;
|
||||||
WidgetT *scroll = wgtScrollPane(appFrame);
|
|
||||||
scroll->weight = 100;
|
|
||||||
|
|
||||||
WidgetT *wrap = wgtWrapBox(scroll);
|
|
||||||
wrap->weight = 100;
|
|
||||||
wrap->spacing = wgtPixels(PM_GRID_SPACING);
|
|
||||||
wrap->align = AlignCenterE;
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < sAppCount; i++) {
|
for (int32_t i = 0; i < sAppCount; i++) {
|
||||||
WidgetT *cell = wgtVBox(wrap);
|
if (i % PM_GRID_COLS == 0) {
|
||||||
|
hbox = wgtHBox(appFrame);
|
||||||
|
hbox->spacing = wgtPixels(PM_GRID_SPACING);
|
||||||
|
hbox->align = AlignCenterE;
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetT *cell = wgtVBox(hbox);
|
||||||
cell->align = AlignCenterE;
|
cell->align = AlignCenterE;
|
||||||
cell->minW = wgtPixels(PM_CELL_W);
|
cell->minW = wgtPixels(PM_CELL_W);
|
||||||
cell->minH = wgtPixels(PM_CELL_H);
|
cell->minH = wgtPixels(PM_CELL_H);
|
||||||
|
|
@ -233,8 +232,8 @@ static void buildPmWindow(void) {
|
||||||
btn->prefH = wgtPixels(PM_BTN_H);
|
btn->prefH = wgtPixels(PM_BTN_H);
|
||||||
}
|
}
|
||||||
|
|
||||||
btn->userData = &sAppFiles[i];
|
btn->userData = &sAppFiles[i];
|
||||||
btn->onClick = onAppButtonClick;
|
btn->onClick = onAppButtonClick;
|
||||||
|
|
||||||
if (sAppFiles[i].tooltip[0]) {
|
if (sAppFiles[i].tooltip[0]) {
|
||||||
wgtSetTooltip(btn, sAppFiles[i].tooltip);
|
wgtSetTooltip(btn, sAppFiles[i].tooltip);
|
||||||
|
|
@ -253,6 +252,10 @@ static void buildPmWindow(void) {
|
||||||
sStatusLabel->weight = 100;
|
sStatusLabel->weight = 100;
|
||||||
updateStatusText();
|
updateStatusText();
|
||||||
|
|
||||||
|
// dvxFitWindow sizes the window to tightly fit the widget tree,
|
||||||
|
// honoring preferred sizes. Without this, the window would use the
|
||||||
|
// initial dimensions from dvxCreateWindow even if widgets don't fit.
|
||||||
|
dvxFitWindow(sAc, sPmWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -380,13 +383,6 @@ static void onPmMenu(WindowT *win, int32_t menuId) {
|
||||||
// The apps/ path is relative to the working directory, which the shell sets
|
// The apps/ path is relative to the working directory, which the shell sets
|
||||||
// to the root of the DVX install before loading any apps.
|
// to the root of the DVX install before loading any apps.
|
||||||
static void scanAppsDir(void) {
|
static void scanAppsDir(void) {
|
||||||
// Free icons from previous scan
|
|
||||||
for (int32_t i = 0; i < sAppCount; i++) {
|
|
||||||
free(sAppFiles[i].iconData);
|
|
||||||
}
|
|
||||||
|
|
||||||
arrfree(sAppFiles);
|
|
||||||
sAppFiles = NULL;
|
|
||||||
sAppCount = 0;
|
sAppCount = 0;
|
||||||
scanAppsDirRecurse("apps");
|
scanAppsDirRecurse("apps");
|
||||||
dvxLog("Progman: found %ld app(s)", (long)sAppCount);
|
dvxLog("Progman: found %ld app(s)", (long)sAppCount);
|
||||||
|
|
@ -410,7 +406,7 @@ static void scanAppsDirRecurse(const char *dirPath) {
|
||||||
|
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
|
|
||||||
while ((ent = readdir(dir)) != NULL) {
|
while ((ent = readdir(dir)) != NULL && sAppCount < MAX_APP_FILES) {
|
||||||
// Skip . and ..
|
// Skip . and ..
|
||||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
|
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -436,18 +432,20 @@ static void scanAppsDirRecurse(const char *dirPath) {
|
||||||
// Check for .app extension (case-insensitive)
|
// Check for .app extension (case-insensitive)
|
||||||
const char *ext = ent->d_name + len - 4;
|
const char *ext = ent->d_name + len - 4;
|
||||||
|
|
||||||
if (strcasecmp(ext, ".app") != 0) {
|
if (strcmp(ext, ".app") != 0 && strcmp(ext, ".APP") != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip ourselves
|
// Skip ourselves
|
||||||
if (strcasecmp(ent->d_name, "progman.app") == 0) {
|
if (strcmp(ent->d_name, "progman.app") == 0 || strcmp(ent->d_name, "PROGMAN.APP") == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AppEntryT newEntry;
|
AppEntryT *entry = &sAppFiles[sAppCount];
|
||||||
memset(&newEntry, 0, sizeof(newEntry));
|
|
||||||
snprintf(newEntry.path, sizeof(newEntry.path), "%s", fullPath);
|
snprintf(entry->path, sizeof(entry->path), "%s", fullPath);
|
||||||
|
entry->iconData = NULL;
|
||||||
|
entry->tooltip[0] = '\0';
|
||||||
|
|
||||||
// Default name from filename (without .app extension)
|
// Default name from filename (without .app extension)
|
||||||
int32_t nameLen = len - 4;
|
int32_t nameLen = len - 4;
|
||||||
|
|
@ -456,28 +454,25 @@ static void scanAppsDirRecurse(const char *dirPath) {
|
||||||
nameLen = SHELL_APP_NAME_MAX - 1;
|
nameLen = SHELL_APP_NAME_MAX - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(newEntry.name, ent->d_name, nameLen);
|
memcpy(entry->name, ent->d_name, nameLen);
|
||||||
newEntry.name[nameLen] = '\0';
|
entry->name[nameLen] = '\0';
|
||||||
|
|
||||||
if (newEntry.name[0] >= 'a' && newEntry.name[0] <= 'z') {
|
if (entry->name[0] >= 'a' && entry->name[0] <= 'z') {
|
||||||
newEntry.name[0] -= 32;
|
entry->name[0] -= 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override from embedded resources if available
|
// Override from embedded resources if available
|
||||||
newEntry.iconData = dvxResLoadIcon(sAc, fullPath, "icon32", &newEntry.iconW, &newEntry.iconH, &newEntry.iconPitch);
|
entry->iconData = dvxResLoadIcon(sAc, fullPath, "icon32", &entry->iconW, &entry->iconH, &entry->iconPitch);
|
||||||
|
|
||||||
if (!newEntry.iconData) {
|
if (!entry->iconData) {
|
||||||
dvxLog("Progman: no icon32 resource in %s", ent->d_name);
|
dvxLog("Progman: no icon32 resource in %s", ent->d_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
dvxResLoadText(fullPath, "name", newEntry.name, SHELL_APP_NAME_MAX);
|
dvxResLoadText(fullPath, "name", entry->name, SHELL_APP_NAME_MAX);
|
||||||
dvxResLoadText(fullPath, "description", newEntry.tooltip, sizeof(newEntry.tooltip));
|
dvxResLoadText(fullPath, "description", entry->tooltip, sizeof(entry->tooltip));
|
||||||
|
|
||||||
dvxLog("Progman: found %s (%s) icon=%s", newEntry.name, ent->d_name, newEntry.iconData ? "yes" : "no");
|
dvxLog("Progman: found %s (%s) icon=%s", entry->name, ent->d_name, entry->iconData ? "yes" : "no");
|
||||||
arrput(sAppFiles, newEntry);
|
sAppCount++;
|
||||||
sAppCount = (int32_t)arrlen(sAppFiles);
|
|
||||||
|
|
||||||
dvxUpdate(sAc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
|
||||||
|
|
@ -4063,20 +4063,6 @@ void dvxFitWindow(AppContextT *ctx, WindowT *win) {
|
||||||
int32_t newW = win->widgetRoot->calcMinW + CHROME_TOTAL_SIDE * 2;
|
int32_t newW = win->widgetRoot->calcMinW + CHROME_TOTAL_SIDE * 2;
|
||||||
int32_t newH = win->widgetRoot->calcMinH + topChrome + CHROME_TOTAL_BOTTOM;
|
int32_t newH = win->widgetRoot->calcMinH + topChrome + CHROME_TOTAL_BOTTOM;
|
||||||
|
|
||||||
// Ensure the window is at least as wide/tall as the WM minimum
|
|
||||||
// (accounts for menu bar width, title bar gadgets, etc.)
|
|
||||||
int32_t wmMinW;
|
|
||||||
int32_t wmMinH;
|
|
||||||
wmMinWindowSize(win, &wmMinW, &wmMinH);
|
|
||||||
|
|
||||||
if (newW < wmMinW) {
|
|
||||||
newW = wmMinW;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newH < wmMinH) {
|
|
||||||
newH = wmMinH;
|
|
||||||
}
|
|
||||||
|
|
||||||
dvxResizeWindow(ctx, win, newW, newH);
|
dvxResizeWindow(ctx, win, newW, newH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,7 @@ typedef enum {
|
||||||
// Flags encode static properties checked by the framework.
|
// Flags encode static properties checked by the framework.
|
||||||
// Widgets set these in their WidgetClassT definition.
|
// Widgets set these in their WidgetClassT definition.
|
||||||
#define WCLASS_FOCUSABLE 0x00000001
|
#define WCLASS_FOCUSABLE 0x00000001
|
||||||
|
#define WCLASS_BOX_CONTAINER 0x00000002
|
||||||
#define WCLASS_HORIZ_CONTAINER 0x00000004
|
#define WCLASS_HORIZ_CONTAINER 0x00000004
|
||||||
#define WCLASS_PAINTS_CHILDREN 0x00000008
|
#define WCLASS_PAINTS_CHILDREN 0x00000008
|
||||||
#define WCLASS_NO_HIT_RECURSE 0x00000010
|
#define WCLASS_NO_HIT_RECURSE 0x00000010
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ WidgetT *widgetFindByAccel(WidgetT *root, char key);
|
||||||
int32_t widgetCountVisibleChildren(const WidgetT *w);
|
int32_t widgetCountVisibleChildren(const WidgetT *w);
|
||||||
int32_t widgetFrameBorderWidth(const WidgetT *w);
|
int32_t widgetFrameBorderWidth(const WidgetT *w);
|
||||||
bool widgetIsFocusable(int32_t type);
|
bool widgetIsFocusable(int32_t type);
|
||||||
|
bool widgetIsBoxContainer(int32_t type);
|
||||||
bool widgetIsHorizContainer(int32_t type);
|
bool widgetIsHorizContainer(int32_t type);
|
||||||
int32_t multiClickDetect(int32_t vx, int32_t vy);
|
int32_t multiClickDetect(int32_t vx, int32_t vy);
|
||||||
|
|
||||||
|
|
|
||||||
32
core/dvxWm.c
32
core/dvxWm.c
|
|
@ -101,7 +101,7 @@ static void drawTitleBar(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *fo
|
||||||
static void drawTitleGadget(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t x, int32_t y, int32_t size);
|
static void drawTitleGadget(DisplayT *d, const BlitOpsT *ops, const ColorSchemeT *colors, int32_t x, int32_t y, int32_t size);
|
||||||
// wmMinimizedIconPos declared in dvxWm.h
|
// wmMinimizedIconPos declared in dvxWm.h
|
||||||
static int32_t scrollbarThumbInfo(const ScrollbarT *sb, int32_t *thumbPos, int32_t *thumbSize);
|
static int32_t scrollbarThumbInfo(const ScrollbarT *sb, int32_t *thumbPos, int32_t *thumbSize);
|
||||||
void wmMinWindowSize(const WindowT *win, int32_t *minW, int32_t *minH);
|
static void wmMinWindowSize(const WindowT *win, int32_t *minW, int32_t *minH);
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -1957,7 +1957,7 @@ int32_t wmMinimizedIconHit(const WindowStackT *stack, const DisplayT *d, int32_t
|
||||||
// This function is called on every resize move event, so it must be cheap.
|
// This function is called on every resize move event, so it must be cheap.
|
||||||
// No allocations, no string operations -- just arithmetic on cached values.
|
// No allocations, no string operations -- just arithmetic on cached values.
|
||||||
|
|
||||||
void wmMinWindowSize(const WindowT *win, int32_t *minW, int32_t *minH) {
|
static void wmMinWindowSize(const WindowT *win, int32_t *minW, int32_t *minH) {
|
||||||
int32_t gadgetS = CHROME_TITLE_HEIGHT - GADGET_INSET * 2;
|
int32_t gadgetS = CHROME_TITLE_HEIGHT - GADGET_INSET * 2;
|
||||||
int32_t gadgetPad = GADGET_PAD;
|
int32_t gadgetPad = GADGET_PAD;
|
||||||
int32_t charW = FONT_CHAR_WIDTH;
|
int32_t charW = FONT_CHAR_WIDTH;
|
||||||
|
|
@ -1970,32 +1970,10 @@ void wmMinWindowSize(const WindowT *win, int32_t *minW, int32_t *minH) {
|
||||||
|
|
||||||
*minW = titleMinW + CHROME_BORDER_WIDTH * 2;
|
*minW = titleMinW + CHROME_BORDER_WIDTH * 2;
|
||||||
|
|
||||||
// Menu bar width: compute directly from label text (don't rely on
|
// Menu bar width: ensure window is wide enough to show all menu labels
|
||||||
// cached barX/barW which may not be computed yet before first paint).
|
|
||||||
if (win->menuBar && win->menuBar->menuCount > 0) {
|
if (win->menuBar && win->menuBar->menuCount > 0) {
|
||||||
int32_t menuW = CHROME_TOTAL_SIDE;
|
MenuT *last = &win->menuBar->menus[win->menuBar->menuCount - 1];
|
||||||
|
int32_t menuW = last->barX + last->barW + CHROME_TOTAL_SIDE;
|
||||||
for (int32_t i = 0; i < win->menuBar->menuCount; i++) {
|
|
||||||
// Count visible characters (skip & accelerator prefix)
|
|
||||||
const char *lbl = win->menuBar->menus[i].label;
|
|
||||||
int32_t visChars = 0;
|
|
||||||
|
|
||||||
for (const char *c = lbl; *c; c++) {
|
|
||||||
if (*c == '&' && *(c + 1) != '&' && *(c + 1) != '\0') {
|
|
||||||
continue; // skip accelerator marker
|
|
||||||
}
|
|
||||||
|
|
||||||
visChars++;
|
|
||||||
}
|
|
||||||
|
|
||||||
menuW += visChars * charW + CHROME_TITLE_PAD * 2;
|
|
||||||
|
|
||||||
if (i < win->menuBar->menuCount - 1) {
|
|
||||||
menuW += MENU_BAR_GAP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
menuW += CHROME_TOTAL_SIDE;
|
|
||||||
|
|
||||||
if (menuW > *minW) {
|
if (menuW > *minW) {
|
||||||
*minW = menuW;
|
*minW = menuW;
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,6 @@ MenuBarT *wmAddMenuBar(WindowT *win);
|
||||||
// Free the menu bar and reclaim the content area.
|
// Free the menu bar and reclaim the content area.
|
||||||
void wmDestroyMenuBar(WindowT *win);
|
void wmDestroyMenuBar(WindowT *win);
|
||||||
|
|
||||||
// Get the minimum window size (accounts for chrome, gadgets, and menu bar).
|
|
||||||
void wmMinWindowSize(const WindowT *win, int32_t *minW, int32_t *minH);
|
|
||||||
|
|
||||||
// Append a dropdown menu to the menu bar. Returns the MenuT to populate
|
// Append a dropdown menu to the menu bar. Returns the MenuT to populate
|
||||||
// with items. The label supports & accelerator markers (e.g. "&File").
|
// with items. The label supports & accelerator markers (e.g. "&File").
|
||||||
MenuT *wmAddMenu(MenuBarT *bar, const char *label);
|
MenuT *wmAddMenu(MenuBarT *bar, const char *label);
|
||||||
|
|
|
||||||
|
|
@ -527,6 +527,21 @@ bool widgetIsFocusable(int32_t type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// widgetIsBoxContainer
|
||||||
|
// ============================================================
|
||||||
|
//
|
||||||
|
// Returns true for widget types that use the generic box layout.
|
||||||
|
|
||||||
|
bool widgetIsBoxContainer(int32_t type) {
|
||||||
|
if (type < 0 || type >= arrlen(widgetClassTable) || !widgetClassTable[type]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (widgetClassTable[type]->flags & WCLASS_BOX_CONTAINER) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// widgetIsHorizContainer
|
// widgetIsHorizContainer
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,9 @@ void widgetCalcMinSizeBox(WidgetT *w, const BitmapFontT *font) {
|
||||||
// size calculation. Hints only increase the minimum, never shrink it.
|
// size calculation. Hints only increase the minimum, never shrink it.
|
||||||
|
|
||||||
void widgetCalcMinSizeTree(WidgetT *w, const BitmapFontT *font) {
|
void widgetCalcMinSizeTree(WidgetT *w, const BitmapFontT *font) {
|
||||||
if (wclsHas(w, WGT_METHOD_CALC_MIN_SIZE)) {
|
if (widgetIsBoxContainer(w->type)) {
|
||||||
|
widgetCalcMinSizeBox(w, font);
|
||||||
|
} else if (wclsHas(w, WGT_METHOD_CALC_MIN_SIZE)) {
|
||||||
wclsCalcMinSize(w, font);
|
wclsCalcMinSize(w, font);
|
||||||
} else {
|
} else {
|
||||||
w->calcMinW = 0;
|
w->calcMinW = 0;
|
||||||
|
|
@ -355,7 +357,9 @@ void widgetLayoutBox(WidgetT *w, const BitmapFontT *font) {
|
||||||
// do nothing (they have no children to lay out).
|
// do nothing (they have no children to lay out).
|
||||||
|
|
||||||
void widgetLayoutChildren(WidgetT *w, const BitmapFontT *font) {
|
void widgetLayoutChildren(WidgetT *w, const BitmapFontT *font) {
|
||||||
if (wclsHas(w, WGT_METHOD_LAYOUT)) {
|
if (widgetIsBoxContainer(w->type)) {
|
||||||
|
widgetLayoutBox(w, font);
|
||||||
|
} else if (wclsHas(w, WGT_METHOD_LAYOUT)) {
|
||||||
wclsLayout(w, font);
|
wclsLayout(w, font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -505,27 +505,6 @@ static void writeBmp(const char *path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void drawWrapbox(void) {
|
|
||||||
clear(192, 192, 192);
|
|
||||||
box(2, 2, 20, 20, 0, 0, 180);
|
|
||||||
// Row 1: three small boxes
|
|
||||||
rect(4, 4, 5, 4, 200, 200, 255);
|
|
||||||
box(4, 4, 5, 4, 0, 0, 180);
|
|
||||||
rect(10, 4, 5, 4, 200, 200, 255);
|
|
||||||
box(10, 4, 5, 4, 0, 0, 180);
|
|
||||||
rect(16, 4, 5, 4, 200, 200, 255);
|
|
||||||
box(16, 4, 5, 4, 0, 0, 180);
|
|
||||||
// Row 2: two boxes (wrapped)
|
|
||||||
rect(4, 10, 5, 4, 200, 200, 255);
|
|
||||||
box(4, 10, 5, 4, 0, 0, 180);
|
|
||||||
rect(10, 10, 5, 4, 200, 200, 255);
|
|
||||||
box(10, 10, 5, 4, 0, 0, 180);
|
|
||||||
// Row 3: one box
|
|
||||||
rect(4, 16, 5, 4, 200, 200, 255);
|
|
||||||
box(4, 16, 5, 4, 0, 0, 180);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
fprintf(stderr, "Usage: mkwgticon <output.bmp> <type>\n");
|
fprintf(stderr, "Usage: mkwgticon <output.bmp> <type>\n");
|
||||||
|
|
@ -565,7 +544,6 @@ int main(int argc, char **argv) {
|
||||||
{"separator", drawSeparator},
|
{"separator", drawSeparator},
|
||||||
{"spacer", drawSpacer},
|
{"spacer", drawSpacer},
|
||||||
{"terminal", drawTerminal},
|
{"terminal", drawTerminal},
|
||||||
{"wrapbox", drawWrapbox},
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,7 @@ WIDGETS = \
|
||||||
textinpt:textInput:widgetTextInput:textinpt \
|
textinpt:textInput:widgetTextInput:textinpt \
|
||||||
timer:timer:widgetTimer:timer \
|
timer:timer:widgetTimer:timer \
|
||||||
toolbar:toolbar:widgetToolbar:toolbar \
|
toolbar:toolbar:widgetToolbar:toolbar \
|
||||||
treeview:treeView:widgetTreeView:treeview \
|
treeview:treeView:widgetTreeView:treeview
|
||||||
wrapbox:wrapBox:widgetWrapBox:wrapbox
|
|
||||||
|
|
||||||
# Extract lists
|
# Extract lists
|
||||||
WGT_NAMES = $(foreach w,$(WIDGETS),$(word 1,$(subst :, ,$w)))
|
WGT_NAMES = $(foreach w,$(WIDGETS),$(word 1,$(subst :, ,$w)))
|
||||||
|
|
|
||||||
|
|
@ -141,31 +141,21 @@ void widgetFrameDestroy(WidgetT *w) {
|
||||||
|
|
||||||
static const WidgetClassT sClassVBox = {
|
static const WidgetClassT sClassVBox = {
|
||||||
.version = WGT_CLASS_VERSION,
|
.version = WGT_CLASS_VERSION,
|
||||||
.flags = 0,
|
.flags = WCLASS_BOX_CONTAINER,
|
||||||
.handlers = {
|
|
||||||
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCalcMinSizeBox,
|
|
||||||
[WGT_METHOD_LAYOUT] = (void *)widgetLayoutBox,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const WidgetClassT sClassHBox = {
|
static const WidgetClassT sClassHBox = {
|
||||||
.version = WGT_CLASS_VERSION,
|
.version = WGT_CLASS_VERSION,
|
||||||
.flags = WCLASS_HORIZ_CONTAINER,
|
.flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER,
|
||||||
.handlers = {
|
|
||||||
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCalcMinSizeBox,
|
|
||||||
[WGT_METHOD_LAYOUT] = (void *)widgetLayoutBox,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const WidgetClassT sClassFrame = {
|
static const WidgetClassT sClassFrame = {
|
||||||
.version = WGT_CLASS_VERSION,
|
.version = WGT_CLASS_VERSION,
|
||||||
.flags = WCLASS_FOCUS_FORWARD,
|
.flags = WCLASS_BOX_CONTAINER | WCLASS_FOCUS_FORWARD,
|
||||||
.handlers = {
|
.handlers = {
|
||||||
[WGT_METHOD_PAINT] = (void *)widgetFramePaint,
|
[WGT_METHOD_PAINT] = (void *)widgetFramePaint,
|
||||||
[WGT_METHOD_DESTROY] = (void *)widgetFrameDestroy,
|
[WGT_METHOD_DESTROY] = (void *)widgetFrameDestroy,
|
||||||
[WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetFrameGetLayoutMetrics,
|
[WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetFrameGetLayoutMetrics,
|
||||||
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCalcMinSizeBox,
|
|
||||||
[WGT_METHOD_LAYOUT] = (void *)widgetLayoutBox,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -310,11 +310,9 @@ void widgetRadioSetText(WidgetT *w, const char *text) {
|
||||||
|
|
||||||
static const WidgetClassT sClassRadioGroup = {
|
static const WidgetClassT sClassRadioGroup = {
|
||||||
.version = WGT_CLASS_VERSION,
|
.version = WGT_CLASS_VERSION,
|
||||||
.flags = 0,
|
.flags = WCLASS_BOX_CONTAINER,
|
||||||
.handlers = {
|
.handlers = {
|
||||||
[WGT_METHOD_DESTROY] = (void *)widgetRadioGroupDestroy,
|
[WGT_METHOD_DESTROY] = (void *)widgetRadioGroupDestroy,
|
||||||
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCalcMinSizeBox,
|
|
||||||
[WGT_METHOD_LAYOUT] = (void *)widgetLayoutBox,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -381,73 +381,6 @@ void widgetScrollPaneLayout(WidgetT *w, const BitmapFontT *font) {
|
||||||
// Recurse into child containers
|
// Recurse into child containers
|
||||||
widgetLayoutChildren(c, font);
|
widgetLayoutChildren(c, font);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Children with custom layout (e.g., WrapBox) may have updated
|
|
||||||
// their calcMinH after layout. Re-check if scrollbars are needed.
|
|
||||||
{
|
|
||||||
int32_t newMinW2;
|
|
||||||
int32_t newMinH2;
|
|
||||||
int32_t newInnerW2;
|
|
||||||
int32_t newInnerH2;
|
|
||||||
bool newNeedV2;
|
|
||||||
bool newNeedH2;
|
|
||||||
|
|
||||||
spCalcNeeds(w, font, &newMinW2, &newMinH2, &newInnerW2, &newInnerH2, &newNeedV2, &newNeedH2);
|
|
||||||
|
|
||||||
if (newNeedV2 != needVSb || newNeedH2 != needHSb) {
|
|
||||||
// Scrollbar needs changed — redo layout with updated sizes
|
|
||||||
contentMinH = newMinH2;
|
|
||||||
contentMinW = newMinW2;
|
|
||||||
innerW = newInnerW2;
|
|
||||||
innerH = newInnerH2;
|
|
||||||
|
|
||||||
maxScrollV = contentMinH - innerH;
|
|
||||||
maxScrollH = contentMinW - innerW;
|
|
||||||
|
|
||||||
if (maxScrollV < 0) {
|
|
||||||
maxScrollV = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxScrollH < 0) {
|
|
||||||
maxScrollH = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sp->scrollPosV = clampInt(sp->scrollPosV, 0, maxScrollV);
|
|
||||||
sp->scrollPosH = clampInt(sp->scrollPosH, 0, maxScrollH);
|
|
||||||
|
|
||||||
virtualW = DVX_MAX(innerW, contentMinW);
|
|
||||||
virtualH = DVX_MAX(innerH, contentMinH);
|
|
||||||
baseX = w->x + SP_BORDER - sp->scrollPosH;
|
|
||||||
baseY = w->y + SP_BORDER - sp->scrollPosV;
|
|
||||||
childW = virtualW - pad * 2;
|
|
||||||
|
|
||||||
if (childW < 0) {
|
|
||||||
childW = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = baseY + pad;
|
|
||||||
|
|
||||||
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
|
||||||
if (!c->visible) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t ms = c->calcMinH;
|
|
||||||
|
|
||||||
if (totalWeight > 0 && c->weight > 0 && extraSpace > 0) {
|
|
||||||
ms += (extraSpace * c->weight) / totalWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->x = baseX + pad;
|
|
||||||
c->y = pos;
|
|
||||||
c->w = childW;
|
|
||||||
c->h = ms;
|
|
||||||
pos += ms + gap;
|
|
||||||
|
|
||||||
widgetLayoutChildren(c, font);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,12 +72,10 @@ void widgetStatusBarGetLayoutMetrics(const WidgetT *w, const BitmapFontT *font,
|
||||||
|
|
||||||
static const WidgetClassT sClassStatusBar = {
|
static const WidgetClassT sClassStatusBar = {
|
||||||
.version = WGT_CLASS_VERSION,
|
.version = WGT_CLASS_VERSION,
|
||||||
.flags = WCLASS_HORIZ_CONTAINER,
|
.flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER,
|
||||||
.handlers = {
|
.handlers = {
|
||||||
[WGT_METHOD_PAINT] = (void *)widgetStatusBarPaint,
|
[WGT_METHOD_PAINT] = (void *)widgetStatusBarPaint,
|
||||||
[WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetStatusBarGetLayoutMetrics,
|
[WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetStatusBarGetLayoutMetrics,
|
||||||
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCalcMinSizeBox,
|
|
||||||
[WGT_METHOD_LAYOUT] = (void *)widgetLayoutBox,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -596,12 +596,10 @@ static const WidgetClassT sClassTabControl = {
|
||||||
|
|
||||||
static const WidgetClassT sClassTabPage = {
|
static const WidgetClassT sClassTabPage = {
|
||||||
.version = WGT_CLASS_VERSION,
|
.version = WGT_CLASS_VERSION,
|
||||||
.flags = WCLASS_ACCEL_WHEN_HIDDEN,
|
.flags = WCLASS_BOX_CONTAINER | WCLASS_ACCEL_WHEN_HIDDEN,
|
||||||
.handlers = {
|
.handlers = {
|
||||||
[WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetTabPageAccelActivate,
|
[WGT_METHOD_ON_ACCEL_ACTIVATE] = (void *)widgetTabPageAccelActivate,
|
||||||
[WGT_METHOD_DESTROY] = (void *)widgetTabPageDestroy,
|
[WGT_METHOD_DESTROY] = (void *)widgetTabPageDestroy,
|
||||||
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCalcMinSizeBox,
|
|
||||||
[WGT_METHOD_LAYOUT] = (void *)widgetLayoutBox,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,12 +64,10 @@ void widgetToolbarGetLayoutMetrics(const WidgetT *w, const BitmapFontT *font, in
|
||||||
|
|
||||||
static const WidgetClassT sClassToolbar = {
|
static const WidgetClassT sClassToolbar = {
|
||||||
.version = WGT_CLASS_VERSION,
|
.version = WGT_CLASS_VERSION,
|
||||||
.flags = WCLASS_HORIZ_CONTAINER,
|
.flags = WCLASS_BOX_CONTAINER | WCLASS_HORIZ_CONTAINER,
|
||||||
.handlers = {
|
.handlers = {
|
||||||
[WGT_METHOD_PAINT] = (void *)widgetToolbarPaint,
|
[WGT_METHOD_PAINT] = (void *)widgetToolbarPaint,
|
||||||
[WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetToolbarGetLayoutMetrics,
|
[WGT_METHOD_GET_LAYOUT_METRICS] = (void *)widgetToolbarGetLayoutMetrics,
|
||||||
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetCalcMinSizeBox,
|
|
||||||
[WGT_METHOD_LAYOUT] = (void *)widgetLayoutBox,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
// widgetWrapBox.h -- Flow/wrap layout container
|
|
||||||
//
|
|
||||||
// Lays out children left-to-right, wrapping to the next row when
|
|
||||||
// the available width is exceeded.
|
|
||||||
|
|
||||||
#ifndef WIDGET_WRAPBOX_H
|
|
||||||
#define WIDGET_WRAPBOX_H
|
|
||||||
|
|
||||||
#include "dvxWidget.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
WidgetT *(*create)(WidgetT *parent);
|
|
||||||
} WrapBoxApiT;
|
|
||||||
|
|
||||||
static inline const WrapBoxApiT *dvxWrapBoxApi(void) {
|
|
||||||
return (const WrapBoxApiT *)wgtGetApi("wrapbox");
|
|
||||||
}
|
|
||||||
|
|
||||||
#define wgtWrapBox(parent) dvxWrapBoxApi()->create(parent)
|
|
||||||
|
|
||||||
#endif // WIDGET_WRAPBOX_H
|
|
||||||
|
|
@ -1,306 +0,0 @@
|
||||||
#define DVX_WIDGET_IMPL
|
|
||||||
// widgetWrapBox.c -- Flow/wrap layout container
|
|
||||||
//
|
|
||||||
// Lays out children left-to-right, wrapping to the next row when
|
|
||||||
// the available width is exceeded. Each row's height is the max
|
|
||||||
// child height in that row. Supports spacing between items and
|
|
||||||
// rows. Supports per-row alignment (center, right) for short rows.
|
|
||||||
|
|
||||||
#include "dvxWidgetPlugin.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Constants
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
#define DEFAULT_PAD 2
|
|
||||||
#define DEFAULT_GAP 4
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Type ID and per-instance data
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
static int32_t sTypeId = -1;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int32_t wrappedH; // actual height from last layout pass (-1 = not yet computed)
|
|
||||||
} WrapBoxDataT;
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// widgetWrapBoxCalcMinSize
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
void widgetWrapBoxCalcMinSize(WidgetT *w, const BitmapFontT *font) {
|
|
||||||
int32_t pad = wgtResolveSize(w->padding, 0, font->charWidth);
|
|
||||||
int32_t maxChildW = 0;
|
|
||||||
int32_t maxChildH = 0;
|
|
||||||
|
|
||||||
if (pad == 0) {
|
|
||||||
pad = DEFAULT_PAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
|
||||||
if (!c->visible) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
widgetCalcMinSizeTree(c, font);
|
|
||||||
|
|
||||||
if (c->calcMinW > maxChildW) {
|
|
||||||
maxChildW = c->calcMinW;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->calcMinH > maxChildH) {
|
|
||||||
maxChildH = c->calcMinH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w->calcMinW = maxChildW + pad * 2;
|
|
||||||
|
|
||||||
WrapBoxDataT *d = (WrapBoxDataT *)w->data;
|
|
||||||
|
|
||||||
if (d && d->wrappedH > 0) {
|
|
||||||
w->calcMinH = d->wrappedH;
|
|
||||||
} else {
|
|
||||||
w->calcMinH = maxChildH + pad * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// widgetWrapBoxLayout
|
|
||||||
// ============================================================
|
|
||||||
//
|
|
||||||
// Three-pass layout:
|
|
||||||
// 1. Place children left-to-right with wrapping
|
|
||||||
// 2. Apply per-row alignment offsets
|
|
||||||
// 3. Recurse into child containers (so children see final positions)
|
|
||||||
|
|
||||||
void widgetWrapBoxLayout(WidgetT *w, const BitmapFontT *font) {
|
|
||||||
int32_t pad = wgtResolveSize(w->padding, 0, font->charWidth);
|
|
||||||
int32_t gap = wgtResolveSize(w->spacing, 0, font->charWidth);
|
|
||||||
|
|
||||||
if (pad == 0) {
|
|
||||||
pad = DEFAULT_PAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gap == 0) {
|
|
||||||
gap = DEFAULT_GAP;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t availW = w->w - pad * 2;
|
|
||||||
int32_t baseX = w->x + pad;
|
|
||||||
|
|
||||||
// Pass 1: position children left-aligned with wrapping
|
|
||||||
int32_t curX = baseX;
|
|
||||||
int32_t curY = w->y + pad;
|
|
||||||
int32_t rowH = 0;
|
|
||||||
|
|
||||||
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
|
||||||
if (!c->visible) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t childW = c->calcMinW;
|
|
||||||
int32_t childH = c->calcMinH;
|
|
||||||
|
|
||||||
if (curX > baseX && (curX - baseX) + childW > availW) {
|
|
||||||
curX = baseX;
|
|
||||||
curY += rowH + gap;
|
|
||||||
rowH = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->x = curX;
|
|
||||||
c->y = curY;
|
|
||||||
c->w = childW;
|
|
||||||
c->h = childH;
|
|
||||||
|
|
||||||
if (childH > rowH) {
|
|
||||||
rowH = childH;
|
|
||||||
}
|
|
||||||
|
|
||||||
curX += childW + gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass 2: apply alignment offsets per row
|
|
||||||
if (w->align == AlignCenterE || w->align == AlignEndE) {
|
|
||||||
WidgetT *rowStart = NULL;
|
|
||||||
int32_t rowY = -1;
|
|
||||||
int32_t rowEndX = 0;
|
|
||||||
|
|
||||||
for (WidgetT *c = w->firstChild; ; c = c ? c->nextSibling : NULL) {
|
|
||||||
bool newRow = false;
|
|
||||||
|
|
||||||
if (!c) {
|
|
||||||
newRow = (rowStart != NULL);
|
|
||||||
} else if (c->visible && c->y != rowY && rowStart != NULL) {
|
|
||||||
newRow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newRow) {
|
|
||||||
int32_t rowW = rowEndX - baseX;
|
|
||||||
int32_t slack = availW - rowW;
|
|
||||||
|
|
||||||
if (slack > 0) {
|
|
||||||
int32_t offset = (w->align == AlignCenterE) ? slack / 2 : slack;
|
|
||||||
|
|
||||||
for (WidgetT *r = rowStart; r != c; r = r->nextSibling) {
|
|
||||||
if (r->visible && r->y == rowY) {
|
|
||||||
r->x += offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rowStart = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!c) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!c->visible) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rowStart == NULL || c->y != rowY) {
|
|
||||||
rowStart = c;
|
|
||||||
rowY = c->y;
|
|
||||||
}
|
|
||||||
|
|
||||||
rowEndX = c->x + c->w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass 3: recurse into child containers AFTER alignment
|
|
||||||
// so children see their parent's final position.
|
|
||||||
for (WidgetT *c = w->firstChild; c; c = c->nextSibling) {
|
|
||||||
if (c->visible) {
|
|
||||||
widgetLayoutChildren(c, font);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store actual wrapped height for subsequent measure passes.
|
|
||||||
int32_t usedH = (curY + rowH + pad) - w->y;
|
|
||||||
WrapBoxDataT *d = (WrapBoxDataT *)w->data;
|
|
||||||
|
|
||||||
if (d) {
|
|
||||||
d->wrappedH = usedH;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usedH > w->calcMinH) {
|
|
||||||
w->calcMinH = usedH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// widgetWrapBoxPaint
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
void widgetWrapBoxPaint(WidgetT *w, DisplayT *disp, const BlitOpsT *ops, const BitmapFontT *font, const ColorSchemeT *colors) {
|
|
||||||
(void)w;
|
|
||||||
(void)disp;
|
|
||||||
(void)ops;
|
|
||||||
(void)font;
|
|
||||||
(void)colors;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// DXE registration
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// BASIC-facing accessors
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
static int32_t wrapBoxGetAlign(const WidgetT *w) {
|
|
||||||
return (int32_t)w->align;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wrapBoxSetAlign(WidgetT *w, int32_t align) {
|
|
||||||
w->align = (WidgetAlignE)align;
|
|
||||||
wgtInvalidate(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const char *sAlignNames[] = { "Left", "Center", "Right", NULL };
|
|
||||||
|
|
||||||
static const WgtPropDescT sProps[] = {
|
|
||||||
{ "Alignment", WGT_IFACE_ENUM, (void *)wrapBoxGetAlign, (void *)wrapBoxSetAlign, sAlignNames }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// DXE registration
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
static void wrapBoxDestroy(WidgetT *w) {
|
|
||||||
free(w->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const WidgetClassT sClass = {
|
|
||||||
.version = WGT_CLASS_VERSION,
|
|
||||||
.flags = 0,
|
|
||||||
.handlers = {
|
|
||||||
[WGT_METHOD_PAINT] = (void *)widgetWrapBoxPaint,
|
|
||||||
[WGT_METHOD_CALC_MIN_SIZE] = (void *)widgetWrapBoxCalcMinSize,
|
|
||||||
[WGT_METHOD_LAYOUT] = (void *)widgetWrapBoxLayout,
|
|
||||||
[WGT_METHOD_DESTROY] = (void *)wrapBoxDestroy,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static WidgetT *wrapBoxCreate(WidgetT *parent) {
|
|
||||||
if (!parent) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
WidgetT *w = widgetAlloc(parent, sTypeId);
|
|
||||||
|
|
||||||
if (w) {
|
|
||||||
WrapBoxDataT *d = (WrapBoxDataT *)calloc(1, sizeof(WrapBoxDataT));
|
|
||||||
|
|
||||||
if (d) {
|
|
||||||
d->wrappedH = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
w->data = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const struct {
|
|
||||||
WidgetT *(*create)(WidgetT *parent);
|
|
||||||
} sApi = {
|
|
||||||
.create = wrapBoxCreate
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const WgtIfaceT sIface = {
|
|
||||||
.basName = "WrapBox",
|
|
||||||
.props = sProps,
|
|
||||||
.propCount = 1,
|
|
||||||
.methods = NULL,
|
|
||||||
.methodCount = 0,
|
|
||||||
.events = NULL,
|
|
||||||
.eventCount = 0,
|
|
||||||
.createSig = WGT_CREATE_PARENT,
|
|
||||||
.isContainer = true,
|
|
||||||
.defaultEvent = "Click",
|
|
||||||
.namePrefix = "WrapBox"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void wgtRegister(void) {
|
|
||||||
sTypeId = wgtRegisterClass(&sClass);
|
|
||||||
wgtRegisterApi("wrapbox", &sApi);
|
|
||||||
wgtRegisterIface("wrapbox", &sIface);
|
|
||||||
}
|
|
||||||
BIN
widgets/wrapBox/wrapbox.bmp
(Stored with Git LFS)
BIN
widgets/wrapBox/wrapbox.bmp
(Stored with Git LFS)
Binary file not shown.
|
|
@ -1,5 +0,0 @@
|
||||||
icon24 icon wrapbox.bmp
|
|
||||||
name text "WrapBox"
|
|
||||||
author text "DVX Project"
|
|
||||||
description text "Flow/wrap layout container"
|
|
||||||
version text "1.0"
|
|
||||||
Loading…
Add table
Reference in a new issue