// 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
