mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
doc: MUI framework documentation — whitepaper overview, SDK-derived architecture, layout mockups
- README.md: comprehensive whitepaper-style overview with historical context, paradigm shift analysis, BOOPSI comparison, version history (Stefan Stuntz as sole author 1.0-3.8), licensing model breakdown, parallel evolution timeline (NeXTSTEP/Qt/MUI convergence), community-sourced developer values - 02-architecture.md: complete rewrite from MUI 3.8 SDK sources — object lifecycle state machine, three-level resource binding, method dispatch chain, notification system with sequence diagrams, layout engine internals (3-pass constraint system), input handling, dynamic object linking, rendering model, tag ID namespace - 05-layout-system.md: Mermaid visual mockups for VGroup, HGroup, nested groups, column grids, scrollgroups, file requester real-world example, layout algorithm and resize sequence diagrams - frameworks/README.md: framework index with comparison table - All content in American English
This commit is contained in:
parent
c79d5e8459
commit
94a3ad1614
15 changed files with 4911 additions and 0 deletions
529
09_intuition/frameworks/mui/02-architecture.md
Normal file
529
09_intuition/frameworks/mui/02-architecture.md
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
[← Home](../../../README.md) · [Intuition](../../README.md) · [Frameworks](../README.md) · [MUI](./)
|
||||
|
||||
# Architecture
|
||||
|
||||
This document describes MUI's internal architecture derived from the official MUI 3.8 SDK (`MUIdev.guide`, autodocs, and `libraries/mui.h`).
|
||||
|
||||
---
|
||||
|
||||
## BOOPSI Foundation
|
||||
|
||||
MUI is built on BOOPSI, AmigaOS's Basic Object-Oriented Programming System for Intuition. BOOPSI provides:
|
||||
|
||||
- **Classes** — type definitions containing a dispatcher function and default attributes
|
||||
- **Objects** — instances of classes created with `NewObject()`
|
||||
- **Methods** — operations invoked on objects via `DoMethod()`
|
||||
- **Attributes** — properties set with `SetAttrs()` and read with `GetAttr()`
|
||||
|
||||
MUI extends BOOPSI with its own class hierarchy, layout engine, and notification system while remaining fully compatible with the underlying mechanism. Every MUI object is a valid BOOPSI object; every MUI class is a BOOPSI `IClass`.
|
||||
|
||||
### How MUI Extends BOOPSI
|
||||
|
||||
| BOOPSI Primitive | MUI Extension |
|
||||
|---|---|
|
||||
| `NewObject(class, ...)` | `MUI_NewObject(MUIC_name, ...)` — auto-loads disk-resident classes |
|
||||
| `DoMethod(obj, methodID, ...)` | Same — MUI adds 60+ new method IDs (MUIM_*) |
|
||||
| `SetAttrs(obj, tag, val, ...)` | `set(obj, attr, val)` macro — same mechanism, convenience wrapper |
|
||||
| `GetAttr(attr, obj, &store)` | `get(obj, attr, &store)` macro |
|
||||
| `DisposeObject(obj)` | `MUI_DisposeObject(obj)` — cascading disposal of entire object tree |
|
||||
|
||||
---
|
||||
|
||||
## Class Hierarchy
|
||||
|
||||
The canonical class tree from `libraries/mui.h`:
|
||||
|
||||
```
|
||||
rootclass (BOOPSI's base class)
|
||||
|
|
||||
+-- Notify (implements notification mechanism)
|
||||
| |
|
||||
| +-- Family (handles multiple children)
|
||||
| | |
|
||||
| | +-- Menustrip (describes a complete menu strip)
|
||||
| | +-- Menu (describes a single menu)
|
||||
| | \-- Menuitem (describes a single menu item)
|
||||
| |
|
||||
| +-- Application (main class for all applications)
|
||||
| |
|
||||
| +-- Window (main class for all windows)
|
||||
| | \-- Aboutmui (About window of MUI preferences)
|
||||
| |
|
||||
| +-- Area (base class for all GUI elements)
|
||||
| |
|
||||
| +-- Rectangle (spacing object)
|
||||
| +-- Balance (balancing separator bar)
|
||||
| +-- Image (image display)
|
||||
| +-- Bitmap (draws bitmaps)
|
||||
| | \-- Bodychunk (makes bitmap from ILBM body chunk)
|
||||
| +-- Text (text display)
|
||||
| +-- Gadget (base class for intuition gadgets)
|
||||
| | |
|
||||
| | +-- String (string gadget)
|
||||
| | +-- Boopsi (interface to BOOPSI gadgets)
|
||||
| | \-- Prop (proportional gadget)
|
||||
| |
|
||||
| +-- Gauge (fuel gauge)
|
||||
| +-- Scale (percentage scale)
|
||||
| +-- Colorfield (field with changeable color)
|
||||
| |
|
||||
| +-- List (line-oriented list)
|
||||
| | |
|
||||
| | +-- Floattext (special list with floating text)
|
||||
| | +-- Volumelist (special list with volumes)
|
||||
| | +-- Scrmodelist (special list with screen modes)
|
||||
| | \-- Dirlist (special list with files)
|
||||
| |
|
||||
| +-- Numeric (base class for slider gadgets)
|
||||
| | |
|
||||
| | +-- Knob (turning knob)
|
||||
| | +-- Levelmeter (level display)
|
||||
| | +-- Numericbutton (space saving popup slider)
|
||||
| | \-- Slider (traditional slider)
|
||||
| |
|
||||
| +-- Group (groups other GUI elements)
|
||||
| |
|
||||
| +-- Register (handles page groups with titles)
|
||||
| +-- Virtgroup (handles virtual groups)
|
||||
| +-- Scrollgroup (virtual groups with scrollbars)
|
||||
| +-- Scrollbar (traditional scrollbar)
|
||||
| +-- Listview (listview)
|
||||
| +-- Radio (radio button)
|
||||
| +-- Cycle (cycle gadget)
|
||||
| +-- Coloradjust (several gadgets to adjust a color)
|
||||
| +-- Palette (complete palette gadget)
|
||||
| |
|
||||
| +-- Popstring (base class for popup objects)
|
||||
| |
|
||||
| +-- Popobject (popup anything in a separate window)
|
||||
| | |
|
||||
| | +-- Poplist (popup a simple listview)
|
||||
| | \-- Popscreen (popup a list of public screens)
|
||||
| |
|
||||
| \-- Popasl (popup an asl requester)
|
||||
|
|
||||
+-- Semaphore (semaphore equipped objects)
|
||||
|
|
||||
+-- Applist (private)
|
||||
+-- Dataspace (handles general purpose data spaces)
|
||||
\-- Configdata (private)
|
||||
```
|
||||
|
||||
### Class Role Summary
|
||||
|
||||
| Branch | Root | Responsibility |
|
||||
|---|---|---|
|
||||
| **Notify** | `rootclass → Notify` | Attribute observation, inter-object messaging |
|
||||
| **Application** | `Notify → Application` | Program root, event loop, ARexx, Commodities |
|
||||
| **Window** | `Notify → Window` | Intuition window lifecycle, IDCMP multiplexing |
|
||||
| **Area** | `Notify → Area` | Visual base — sizing, rendering, input, frames |
|
||||
| **Group** | `Area → Group` | Layout container — child arrangement |
|
||||
| **Semaphore** | `Notify → Semaphore` | Thread-safe data containers |
|
||||
|
||||
---
|
||||
|
||||
## Application Object Tree
|
||||
|
||||
A MUI application forms a tree at runtime. Only three class types may have children:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
APP["Application<br/><i>zero or more Window children</i>"]
|
||||
W1["Window 1"]
|
||||
W2["Window 2"]
|
||||
ROOT1["Group<br/><i>root object</i>"]
|
||||
ROOT2["Group<br/><i>root object</i>"]
|
||||
C1["String"]
|
||||
C2["Group"]
|
||||
C3["Text"]
|
||||
C4["List"]
|
||||
C5["Cycle"]
|
||||
|
||||
APP --> W1 & W2
|
||||
W1 --> ROOT1
|
||||
W2 --> ROOT2
|
||||
ROOT1 --> C1 & C2 & C3
|
||||
C2 --> C4 & C5
|
||||
|
||||
style APP fill:#fff3e0,stroke:#ff9800,color:#333
|
||||
style W1 fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
style W2 fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
style ROOT1 fill:#e8f5e9,stroke:#4caf50,color:#333
|
||||
style ROOT2 fill:#e8f5e9,stroke:#4caf50,color:#333
|
||||
```
|
||||
|
||||
| Parent | Allowed Children | Count |
|
||||
|---|---|---|
|
||||
| **Application** | Window objects only | 0..N |
|
||||
| **Window** | Any Area subclass (usually Group) | Exactly 1 |
|
||||
| **Group** | Any Area subclass (including nested Groups) | 1..N |
|
||||
|
||||
Error handling is cascading: if any child creation fails (returns `NULL`), the parent automatically disposes all previously created siblings and returns `NULL` itself. A successful `ApplicationObject` guarantees the entire tree was created. A single `MUI_DisposeObject(app)` destroys everything.
|
||||
|
||||
---
|
||||
|
||||
## Object Lifecycle
|
||||
|
||||
Every MUI object passes through a strict sequence of constructor/destructor pairs. The SDK documents this as the fundamental contract:
|
||||
|
||||
```
|
||||
OM_NEW — parse initial taglist, allocate instance data
|
||||
{
|
||||
MUIM_Setup — display environment known (screen, fonts, DrawInfo)
|
||||
MUIM_AskMinMax — report min/max/default dimensions
|
||||
[ window opens ]
|
||||
{
|
||||
MUIM_Show — object added to window (AddGadget for Intuition types)
|
||||
{
|
||||
MUIM_Draw — render content (may be called multiple times)
|
||||
}
|
||||
MUIM_Hide — object removed from window (RemGadget)
|
||||
}
|
||||
[ window closes ]
|
||||
MUIM_Cleanup — free display-dependent resources
|
||||
}
|
||||
OM_DISPOSE — free all resources, destroy object
|
||||
```
|
||||
|
||||
### Lifecycle as State Machine
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Created: OM_NEW
|
||||
Created --> SetUp: MUIM_Setup
|
||||
SetUp --> Sized: MUIM_AskMinMax
|
||||
Sized --> Visible: MUIM_Show
|
||||
Visible --> Visible: MUIM_Draw (repeated)
|
||||
Visible --> Sized: MUIM_Hide (resize)
|
||||
Sized --> Visible: MUIM_Show (re-layout)
|
||||
Sized --> Created: MUIM_Cleanup
|
||||
Created --> [*]: OM_DISPOSE
|
||||
```
|
||||
|
||||
### Three Levels of Resource Binding
|
||||
|
||||
| Level | Constructor | Destructor | Available Information |
|
||||
|---|---|---|---|
|
||||
| **Object** | `OM_NEW` | `OM_DISPOSE` | Nothing — only taglist parsing |
|
||||
| **Display** | `MUIM_Setup` | `MUIM_Cleanup` | Screen, fonts, DrawInfo, pens |
|
||||
| **Window** | `MUIM_Show` | `MUIM_Hide` | Intuition Window, RastPort, position/size |
|
||||
|
||||
Each level may repeat independently. You may receive multiple Setup/Cleanup cycles (e.g., screen mode change) and multiple Show/Hide cycles within a single Setup (e.g., window resize).
|
||||
|
||||
---
|
||||
|
||||
## Method Dispatch Model
|
||||
|
||||
Every MUI class has a **dispatcher function** — a single entry point that receives all method calls. This is the standard BOOPSI dispatch pattern:
|
||||
|
||||
```c
|
||||
ULONG MyDispatcher(struct IClass *cl, Object *obj, Msg msg)
|
||||
{
|
||||
switch (msg->MethodID)
|
||||
{
|
||||
case OM_NEW : return mNew(cl, obj, (APTR)msg);
|
||||
case OM_DISPOSE : return mDispose(cl, obj, (APTR)msg);
|
||||
case OM_SET : return mSet(cl, obj, (APTR)msg);
|
||||
case OM_GET : return mGet(cl, obj, (APTR)msg);
|
||||
case MUIM_Setup : return mSetup(cl, obj, (APTR)msg);
|
||||
case MUIM_Cleanup : return mCleanup(cl, obj, (APTR)msg);
|
||||
case MUIM_AskMinMax: return mAskMinMax(cl, obj, (APTR)msg);
|
||||
case MUIM_Draw : return mDraw(cl, obj, (APTR)msg);
|
||||
case MUIM_HandleInput: return mHandleInput(cl, obj, (APTR)msg);
|
||||
}
|
||||
|
||||
/* Unknown methods → pass to superclass */
|
||||
return DoSuperMethodA(cl, obj, msg);
|
||||
}
|
||||
```
|
||||
|
||||
### Dispatch Chain
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
CALLER["DoMethod(obj, MUIM_Draw)"] --> DISP_MY["MyClass<br/>Dispatcher"]
|
||||
DISP_MY -->|"handled"| RESULT["Return value"]
|
||||
DISP_MY -->|"DoSuperMethodA()"| DISP_AREA["Area<br/>Dispatcher"]
|
||||
DISP_AREA -->|"DoSuperMethodA()"| DISP_NOTIFY["Notify<br/>Dispatcher"]
|
||||
DISP_NOTIFY -->|"DoSuperMethodA()"| DISP_ROOT["rootclass<br/>Dispatcher"]
|
||||
|
||||
style DISP_MY fill:#e8f5e9,stroke:#4caf50,color:#333
|
||||
style DISP_AREA fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
style DISP_NOTIFY fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
```
|
||||
|
||||
Key rules:
|
||||
- **Always call `DoSuperMethodA()`** for unrecognized methods — MUI sends undocumented internal methods
|
||||
- **Never render in `OM_SET`** — call `MUI_Redraw(obj, flag)` instead; MUI will invoke `MUIM_Draw`
|
||||
- The dispatcher receives `struct IClass *cl` (the class pointer), `Object *obj`, and `Msg msg` in registers `a0`, `a2`, `a1` respectively
|
||||
|
||||
---
|
||||
|
||||
## Notification System
|
||||
|
||||
The central mechanism for controlling a MUI application. Notification creates **declarative reactive bindings** between objects.
|
||||
|
||||
### How It Works
|
||||
|
||||
Every MUI object has attributes that reflect its current state. Attributes change either programmatically (`SetAttrs()`) or through user interaction. Notification watches for these changes and automatically invokes methods on target objects.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Scrollbar as Scrollbar Object
|
||||
participant MUI as MUI Notify Engine
|
||||
participant List as List Object
|
||||
|
||||
User->>Scrollbar: Drags knob
|
||||
Scrollbar->>Scrollbar: MUIA_Prop_First changes
|
||||
Scrollbar->>MUI: Attribute change detected
|
||||
MUI->>MUI: Match against registered notifications
|
||||
MUI->>List: MUIM_Set(MUIA_List_TopPixel, new_value)
|
||||
List->>List: Scrolls to new position
|
||||
```
|
||||
|
||||
### Registration
|
||||
|
||||
```c
|
||||
DoMethod(source, MUIM_Notify,
|
||||
watched_attribute, /* which attribute to observe */
|
||||
trigger_value, /* MUIV_EveryTime or specific value */
|
||||
target_object, /* destination object */
|
||||
param_count, /* number of following parameters */
|
||||
target_method, ...); /* method + arguments to invoke */
|
||||
```
|
||||
|
||||
### Notification Suppression
|
||||
|
||||
When setting attributes programmatically, you may want to suppress notifications to avoid loops:
|
||||
|
||||
```c
|
||||
/* Normal set — triggers any registered notifications */
|
||||
set(slider, MUIA_Slider_Level, 50);
|
||||
|
||||
/* Suppressed set — no notifications fire */
|
||||
SetAttrs(slider, MUIA_NoNotify, TRUE,
|
||||
MUIA_Slider_Level, 50, TAG_DONE);
|
||||
```
|
||||
|
||||
`MUIA_NoNotify` is a one-shot attribute — it only applies to the current `SetAttrs()` call.
|
||||
|
||||
### Deregistration
|
||||
|
||||
```c
|
||||
/* Remove all notifications on a specific attribute */
|
||||
DoMethod(source, MUIM_KillNotify, MUIA_Slider_Level);
|
||||
|
||||
/* Remove notification targeting a specific object */
|
||||
DoMethod(source, MUIM_KillNotifyObj, MUIA_Slider_Level, target);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Layout Engine Internals
|
||||
|
||||
MUI's layout engine uses a **three-pass constraint system** that runs before window open and on every resize.
|
||||
|
||||
### Pass 1: AskMinMax (Bottom-Up)
|
||||
|
||||
Every object reports its minimum, maximum, and default dimensions. Leaf objects (Text, String, etc.) report fixed values based on content and font. Group objects aggregate their children:
|
||||
|
||||
**Horizontal Group:**
|
||||
- Min width = sum of all children's min widths
|
||||
- Max width = sum of all children's max widths
|
||||
- Min height = largest child min height
|
||||
- Max height = smallest child max height
|
||||
|
||||
**Vertical Group:**
|
||||
- Min height = sum of all children's min heights
|
||||
- Max height = sum of all children's max heights
|
||||
- Min width = largest child min width
|
||||
- Max width = smallest child max width
|
||||
|
||||
### Pass 2: Size Distribution (Top-Down)
|
||||
|
||||
Starting from the window's current size, the root group distributes available space among children. Extra space (beyond minimum) is distributed proportionally according to **weight** attributes (`MUIA_Weight`, default 100).
|
||||
|
||||
### Pass 3: Placement
|
||||
|
||||
Each object receives its final rectangle `(left, top, width, height)` and records it in instance data accessible via macros:
|
||||
|
||||
| Macro | Returns |
|
||||
|---|---|
|
||||
| `_mleft(obj)` | Left edge of content area (inside frame) |
|
||||
| `_mtop(obj)` | Top edge of content area |
|
||||
| `_mright(obj)` | Right edge of content area |
|
||||
| `_mbottom(obj)` | Bottom edge of content area |
|
||||
| `_mwidth(obj)` | Content area width |
|
||||
| `_mheight(obj)` | Content area height |
|
||||
| `_rp(obj)` | RastPort pointer for rendering |
|
||||
|
||||
### Layout Flow
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Pass 1: AskMinMax (bottom-up)"
|
||||
LEAF1["Text: min=40, max=200"]
|
||||
LEAF2["Button: min=60, max=120"]
|
||||
GROUP1["HGroup: min=100, max=320"]
|
||||
end
|
||||
|
||||
subgraph "Pass 2: Distribute (top-down)"
|
||||
WINDOW["Window size: 250px wide"]
|
||||
CALC["HGroup: 250px available<br/>Text weight=100, Button weight=100<br/>→ Text=125px, Button=125px"]
|
||||
end
|
||||
|
||||
subgraph "Pass 3: Place"
|
||||
PLACE1["Text: left=5, width=125"]
|
||||
PLACE2["Button: left=130, width=125"]
|
||||
end
|
||||
|
||||
LEAF1 & LEAF2 --> GROUP1
|
||||
GROUP1 --> WINDOW --> CALC
|
||||
CALC --> PLACE1 & PLACE2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Input Handling
|
||||
|
||||
MUI multiplexes Intuition IDCMP messages through the Application object's event loop.
|
||||
|
||||
### Event Flow
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
IDCMP["Intuition IDCMP Port<br/>(mouse, keyboard)"]
|
||||
APP["MUIM_Application_NewInput"]
|
||||
DISPATCH["MUI dispatches to<br/>active/relevant objects"]
|
||||
HANDLE["MUIM_HandleInput<br/>(on each object)"]
|
||||
NOTIFY["Notifications fire<br/>(attribute changes)"]
|
||||
RETURN["Return ID to app loop"]
|
||||
|
||||
IDCMP --> APP --> DISPATCH --> HANDLE --> NOTIFY --> RETURN
|
||||
|
||||
style APP fill:#fff3e0,stroke:#ff9800,color:#333
|
||||
style HANDLE fill:#e8f5e9,stroke:#4caf50,color:#333
|
||||
```
|
||||
|
||||
### IDCMP Subscription
|
||||
|
||||
Custom classes request specific IDCMP events dynamically:
|
||||
|
||||
```c
|
||||
/* During MUIM_HandleInput — request mouse move tracking */
|
||||
MUI_RequestIDCMP(obj, IDCMP_MOUSEMOVE);
|
||||
|
||||
/* Stop tracking when done */
|
||||
MUI_RejectIDCMP(obj, IDCMP_MOUSEMOVE);
|
||||
```
|
||||
|
||||
MUI translates raw IDCMP events into higher-level `MUIKEY_*` constants for keyboard navigation:
|
||||
|
||||
| MUIKEY Constant | Meaning |
|
||||
|---|---|
|
||||
| `MUIKEY_PRESS` | Confirm / activate |
|
||||
| `MUIKEY_TOGGLE` | Toggle selection |
|
||||
| `MUIKEY_UP/DOWN/LEFT/RIGHT` | Directional navigation |
|
||||
| `MUIKEY_PAGEUP/PAGEDOWN` | Page scrolling |
|
||||
| `MUIKEY_TOP/BOTTOM` | Jump to extremes |
|
||||
| `MUIKEY_WORDLEFT/WORDRIGHT` | Word-level navigation |
|
||||
|
||||
---
|
||||
|
||||
## Dynamic Object Linking
|
||||
|
||||
MUI supports **late binding** — adding and removing children after the initial tree is created.
|
||||
|
||||
```c
|
||||
/* Add a window to a running application */
|
||||
DoMethod(app, OM_ADDMEMBER, new_window);
|
||||
set(new_window, MUIA_Window_Open, TRUE);
|
||||
|
||||
/* Remove and dispose when done */
|
||||
set(new_window, MUIA_Window_Open, FALSE);
|
||||
DoMethod(app, OM_REMMEMBER, new_window);
|
||||
MUI_DisposeObject(new_window); /* manual disposal required */
|
||||
```
|
||||
|
||||
For groups, the window must be **closed** before modifying children:
|
||||
|
||||
```c
|
||||
set(window, MUIA_Window_Open, FALSE);
|
||||
DoMethod(group, MUIM_Group_InitChange); /* begin modification */
|
||||
DoMethod(group, OM_ADDMEMBER, new_child);
|
||||
DoMethod(group, MUIM_Group_ExitChange); /* end — triggers re-layout */
|
||||
set(window, MUIA_Window_Open, TRUE);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rendering Model
|
||||
|
||||
MUI uses **retained-mode rendering** — the framework maintains the object tree and handles all damage repair.
|
||||
|
||||
### Draw Flags
|
||||
|
||||
| Flag | Meaning |
|
||||
|---|---|
|
||||
| `MADF_DRAWOBJECT` | Complete redraw of the object |
|
||||
| `MADF_DRAWUPDATE` | Incremental update (optimization) |
|
||||
|
||||
Custom classes call `MUI_Redraw(obj, flag)` to request a redraw. MUI calls `MUIM_Draw` with appropriate flags. Inside `MUIM_Draw`, the class can check which type of redraw is needed:
|
||||
|
||||
```c
|
||||
case MUIM_Draw:
|
||||
{
|
||||
struct MUIP_Draw *msg = (struct MUIP_Draw *)msg;
|
||||
DoSuperMethodA(cl, obj, msg); /* let Area draw background + frame */
|
||||
|
||||
if (msg->flags & MADF_DRAWOBJECT)
|
||||
{
|
||||
/* Full redraw — render everything */
|
||||
}
|
||||
else if (msg->flags & MADF_DRAWUPDATE)
|
||||
{
|
||||
/* Partial update — only changed elements */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Rendering Rules
|
||||
|
||||
1. **Never draw outside `MUIM_Draw`** — not in `OM_SET`, not in `MUIM_HandleInput`
|
||||
2. **Always call `DoSuperMethodA()` first** — Area class draws background and frame
|
||||
3. **Only draw within `_mleft()` / `_mtop()` / `_mright()` / `_mbottom()`** — the content rectangle inside the frame
|
||||
4. **Use `_rp(obj)`** to get the RastPort — never cache it across Show/Hide cycles
|
||||
|
||||
---
|
||||
|
||||
## Tag ID Namespace
|
||||
|
||||
MUI uses the AmigaOS `TagItem` system for all attributes and methods. The namespace is partitioned:
|
||||
|
||||
| Range | Owner |
|
||||
|---|---|
|
||||
| `0x80420000 – 0x8042FFFF` | MUI built-in classes (reserved) |
|
||||
| `TAG_USER \| (serial << 16) \| offset` | Registered third-party classes |
|
||||
|
||||
Each registered MUI developer received a unique serial number. All their class attributes and methods are prefixed with `TAG_USER | (serial << 16)` to avoid tag collisions across the MCC ecosystem.
|
||||
|
||||
---
|
||||
|
||||
## Key Architectural Files
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `libraries/mui.h` | Main header — class names, method IDs, attribute tags, macros, class tree |
|
||||
| `clib/muimaster_protos.h` | C prototypes for `muimaster.library` functions |
|
||||
| `proto/muimaster.h` | Compiler-specific prototype wrappers |
|
||||
| `pragma/muimaster_lib.h` | SAS/C library call pragmas |
|
||||
| `muimaster.library` | Runtime — object creation, layout, event handling, preferences |
|
||||
| `MUI_<Class>.doc` | Per-class autodoc reference (66 files) |
|
||||
| `MUIdev.guide` | Official developer guide — architecture, custom classes, style guide |
|
||||
|
||||
---
|
||||
|
||||
Previous: [Introduction](01-introduction.md)
|
||||
Next: [Getting Started](03-getting-started.md)
|
||||
Loading…
Add table
Add a link
Reference in a new issue