65816-llvm-mos/runtime/include/iigs/uiBuilder.h
Scott Duensing da095402ec Updated
2026-06-02 23:17:57 -05:00

192 lines
7 KiB
C

// iigs/uiBuilder.h - declarative UI scaffolding for desktop demos.
//
// Replaces hand-rolled ">> Menu \N3\r--Item\N250*Xx\r.\r" strings,
// NewWindowParm zero-then-init boilerplate, AlertTemplate/ItemTemplate
// blocks, and the cmd-ID -> handler switch. Each demo previously
// duplicated ~150 lines of this boilerplate; the uiBuilder surface
// folds it to ~30 lines.
//
// Three sub-surfaces:
// 1. uiBuilderMenu() - builds an in-memory Menu Manager byte
// stream from a UiMenuT spec, ready to hand
// to NewMenu().
// 2. uiBuilderWindow() - fills a NewWindowParm with sensible defaults
// + caller overrides + a UiCtlT array of
// controls. Wraps NewWindow + NewControl2.
// 3. uiBuilderAlert() - assembles AlertTemplate + ItemTemplate[]
// from a small spec, runs Alert/StopAlert/...
//
// Plus a single onCmd dispatcher (extends IigsEventCallbacksT) that
// looks up the menu-pick itemID in a (cmdId,handler) table.
//
// ORCA control.h proc constants (simpleProc/checkProc/scrollProc/
// growProc) are ABSTRACT 32-bit codes - NOT bank-E1 ROM addresses;
// the CtlMgr maps them internally. Our cButton/cCheckBox/... mirror
// those abstract values byte-for-byte.
#ifndef IIGS_UI_BUILDER_H
#define IIGS_UI_BUILDER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "iigs/eventLoop.h"
// ---------------------------------------------------------------------------
// Menu builder
// ---------------------------------------------------------------------------
// Per-item flags (bitmask). Mirrors the Menu Manager mini-format
// suffix letters: D=disabled, V=checked-visible, X=xor (hilite-only),
// I=icon, S=item-has-style. Most demos only need MI_DISABLED and
// MI_CHECKED.
#define MI_DISABLED 0x0001 // item starts disabled (D)
#define MI_CHECKED 0x0002 // item starts with checkmark (V)
#define MI_XOR 0x0004 // item hilites via XOR (X)
#define MI_DIVIDER 0x0008 // render this item as a 1-pixel divider line
// Per-menu flags.
#define MN_APPLE 0x0001 // this is the Apple menu (>>@); icon goes in title
#define MN_ALL_DISABLED 0x0002
typedef struct {
uint16_t cmdId; // unique id returned by MenuKey/MenuSelect;
// also the value passed to onCmd().
// Use values >= 256 to avoid collision
// with Apple menu's CDA range.
const char *title; // C string ("Quit"). Builder copies
// it into the byte stream verbatim.
// NULL for divider items.
char keyEquiv; // command-key shortcut letter (0 = none).
// Upper- and lower-case forms are
// emitted as the ORCA *Xx pair.
uint16_t flags; // MI_* bitmask.
} UiMenuItemT;
typedef struct {
uint16_t menuId; // Menu Manager menu ID (matches \N###).
const char *title; // C string ("File"). Apple menu uses
// an icon when MN_APPLE is set;
// the title text is then unused.
uint16_t flags; // MN_* bitmask.
uint16_t numItems;
const UiMenuItemT *items;
} UiMenuT;
// Assemble a single menu's byte stream into `outBuf`. Returns the
// number of bytes written (excluding the NUL terminator some builders
// expect). The output is the exact format NewMenu() expects: a
// pascal-style mini-program with `>>`/`>>@` header, `--Name\N###...`
// lines per item, and a final `.\r` terminator.
//
// outBufSize should be at least 32 + sum(strlen(item.title)+16) bytes.
// The builder bails (returns 0) if it would overflow.
uint16_t uiBuilderMenuBytes(const UiMenuT *spec, char *outBuf, uint16_t outBufSize);
// Install a menu spec via NewMenu()+InsertMenu(). Allocates a
// temporary buffer on the static heap below. Returns the MenuHandle
// from NewMenu (or NULL on overflow). Pass `beforeMenuId=0` to insert
// at the end of the menu bar (Menu Manager convention).
void *uiBuilderInstallMenu(const UiMenuT *spec, uint16_t beforeMenuId);
// Convenience: install N menus in order (left to right), then call
// FixAppleMenu + FixMenuBar + DrawMenuBar. The Apple menu (if
// MN_APPLE-flagged) is detected and its ID passed to FixAppleMenu.
void uiBuilderInstallMenuBar(const UiMenuT *menus, uint16_t numMenus);
// ---------------------------------------------------------------------------
// Window builder
// ---------------------------------------------------------------------------
// Frame-bits convenience. Same values ORCA's window.h uses.
#define UW_TITLE 0x0001
#define UW_CLOSE 0x4000
#define UW_VIS 0x0020
#define UW_MOVE 0x0080
#define UW_GROW 0x0400
#define UW_ZOOM 0x0100
#define UW_PAGE 0x0008
#define UW_INFO 0x0004
#define UW_STD_DOC (UW_TITLE | UW_CLOSE | UW_VIS | UW_MOVE)
#define UW_STD_DOC_GZ (UW_STD_DOC | UW_GROW | UW_ZOOM)
typedef struct {
int16_t v1, h1, v2, h2;
} UiRectT;
typedef struct {
const char *title; // C string title (NULL for untitled)
uint16_t frameBits; // UW_* bitmask
UiRectT position; // window screen position
int16_t maxHeight;
int16_t maxWidth;
uint32_t refCon;
void *contentDefProc; // NULL = default
} UiWindowT;
// Open a window from the spec. Title is converted into the Menu
// Manager's pascal-counted form in a builder-managed buffer. Returns
// the WindowPtr from NewWindow, or NULL on failure.
void *uiBuilderOpenWindow(const UiWindowT *spec);
// ---------------------------------------------------------------------------
// Alert builder
// ---------------------------------------------------------------------------
#define UA_NORMAL 0
#define UA_STOP 1
#define UA_NOTE 2
#define UA_CAUTION 3
// Show a simple message-and-OK alert. `msg` is a C string; the
// builder converts it to pascal-counted form in a scratch buffer.
// Returns the item-ID picked by the user (1 for OK).
uint16_t uiBuilderAlert(uint16_t kind, const char *msg);
// ---------------------------------------------------------------------------
// onCmd dispatch
// ---------------------------------------------------------------------------
typedef struct {
uint16_t cmdId;
void (*handler)(uint16_t cmdId);
} UiCmdHandlerT;
// Drop-in onMenu callback that looks up itemId in a (cmdId, handler)
// table. Wire it into IigsEventCallbacksT.onMenu via:
//
// static void myOnMenu(uint16_t menuId, uint16_t itemId) {
// uiBuilderDispatch(itemId, gCmdTable, gCmdTableLen);
// }
//
// The handler receives the cmdId (which equals itemId here, by
// convention).
void uiBuilderDispatch(uint16_t cmdId,
const UiCmdHandlerT *table,
uint16_t tableLen);
#ifdef __cplusplus
}
#endif
#endif // IIGS_UI_BUILDER_H