GUI Component Internals
This page describes the internal architecture of the Oidis GUI component system. It is primarily useful when building custom UserControls (components extending GuiCommons or BasePanel), debugging rendering or lifecycle issues, or understanding how the framework manages component state.
For everyday panel and controller development, you do not need this level of detail — see Panels and Controllers instead.
Inheritance Hierarchy
All GUI components trace their lineage back through GuiCommons to BaseObject from io-oidis-commons.
BaseObject (io-oidis-commons)
└── GuiCommons (abstract)
├── BaseGuiObject (abstract)
│ └── AbstractGuiObject
│ └── [standard UserControls: Button, TextField, Label, DropDown, …]
└── FormsObject (abstract)
└── BasePanel (abstract)
└── [custom Panels declared in solution projects]
GuiCommons
GuiCommons is the root of all GUI objects. It carries:
guiId— unique element identifier (auto-generated from class name + counter, or overridden)guiPath— path in the component hierarchyparent/owner— parentGuiCommonselement and theIBaseViewercontroller that owns the elementvisible/enabled— current visual and interaction stateoptions(GuiOptionsManager) — feature flag manager (seeGuiOptionType)events(ElementEventsManager) — local event subscription manager returned by.getEvents()childElements/waitFor— collections of child elements managed by this componentinnerHtmlMap(IGuiElement) — theGuiElementinstance that builds the HTML output- Layout properties:
alignment,fitToParent,widthOfColumn(PropagableNumber),wrappingElement,wrappingContainer - Lifecycle flags:
cached,prepared,completed,loaded,contentLoaded
Key static method: GuiCommons.GuiElementClass($value?) — gets or sets the GuiElement class used for HTML rendering across all components. This is a global setting for the rendering engine.
BaseGuiObject
Extends GuiCommons with:
Title()— lazy-initialized tooltip component (IToolTip)changedflag — tracks whether the component's value has been modified- Static hover event handlers (
onHoverEventHandler,onUnhoverEventHandler) — shared across all GUI objects that support hover state propagation to parent
AbstractGuiObject
Used during development phases. Adds:
- Notification component support
- Size management helpers
Standard UserControls (Button, TextField, etc.) extend AbstractGuiObject.
FormsObject
Base for all components that participate in form submission. Extends GuiCommons with form input handling. BasePanel extends FormsObject.
BasePanel
The primary base class for all panels declared in solution projects. Extends FormsObject with:
verticalScrollBar/horizontalScrollBar— built-in scrollbar components (declared as public fields)loaderIcon/loaderText— loading indicator componentscontentType(PanelContentType) — controls how content is loaded: synchronous, async, or from a URL loaderchildPanelList— registry of child panel viewers managed by this panel- Orientation support (
OrientationType.HORIZONTAL/VERTICAL) - Keyboard navigation (arrow keys for panel focus traversal)
Lifecycle States
GuiCommons tracks component state through four boolean flags. Understanding these is important when building components that react to lifecycle stages.
| Flag | Set when | Cleared when |
|---|---|---|
cached | HTML has been generated and cached | Draw() is called with $force = true |
prepared | Component is ready for rendering (all dependencies resolved) | Reset on reinitialize |
completed | Rendering pipeline has finished | Reset on reinitialize |
loaded | Data has been loaded into the component | Reset on data refresh |
contentLoaded | Inner content (child panels, async content) has loaded | Reset on content refresh |
You can query these via IsLoaded(), IsCompleted(), IsPrepared(), IsCached().
Show/Hide and the Lifecycle
When GuiCommons.Show($element) is called (the static method), it:
- Calls
ElementManager.Show($element.Id())to make the DOM element visible - Fires
EventType.ON_SHOWvia the globalEventsManager - If the element is already loaded, the show event fires immediately
- If not yet loaded, the show event fires after the next
Draw()completes
The reverse applies to GuiCommons.Hide($element).
Rendering Pipeline
All GUI components output HTML through a common pipeline:
component.Draw()
│
▼
GuiElement (innerHtmlMap)
│ builds HTML <div> structure with:
│ - component id
│ - CSS class names (interface, style, container)
│ - layout metadata (data-* attributes)
│ - child element HTML (recursive Draw() calls)
│
▼
HTML string output
│
▼
DOM insertion → ElementEventsManager.Subscribe()
(hooks registered events to DOM element)
GuiElement — The HTML Builder
GuiElement implements IGuiElement and IResponsiveElement. It is the low-level HTML structure builder used by every component. It generates <div> elements with:
- Element
idattribute (mapped fromguiId) - CSS class names from
interfaceClassName,styleClassName,containerClassName - Layout attributes for the responsive grid system
- Nested child element HTML via recursive rendering
The GuiElement class used can be swapped globally via GuiCommons.GuiElementClass($newClass), allowing custom rendering backends.
Async Drawing
Components support async rendering via asyncDrawEnabled. When enabled, the rendering is deferred to avoid blocking the UI thread during complex component trees. The AnimationThreadPool may be involved for animation-dependent renders.
ResponsiveElement Layout System
GuiCommons supports a responsive grid through IResponsiveElement:
| Property | Type | Purpose |
|---|---|---|
Alignment | Alignment enum | LEFT, CENTER, RIGHT, JUSTIFY |
FitToParent | FitToParent enum | How to fill parent container |
WidthOfColumn | PropagableNumber | Column width that propagates to children |
HeightOfRow | PropagableNumber | Row height that propagates to children |
PropagableNumber is a special structure that carries a numeric value and propagates it down the component tree when not overridden at a lower level. This enables responsive percentage-based sizing where child elements inherit layout constraints from their parent unless they define their own.
GuiOptionsManager — Feature Flags
Each component has a GuiOptionsManager (accessible via getOptions()) that manages which optional features are enabled. Feature flags are defined in GuiOptionType:
| Option | Effect |
|---|---|
GuiOptionType.TOOL_TIP | Enables tooltip rendering and the Title() component |
GuiOptionType.NOTIFICATION | Enables notification indicator rendering |
Custom UserControls can define their own GuiOptionType values and check them via getOptions().IsEnabled($type).
Viewer Pattern
The viewer layer (BasePanelViewer, BaseViewer) is part of the legacy GUI system. In the Bootstrap 5 system, BasePanelController<Panel> talks directly to the panel — there is no viewer intermediary.
If you encounter BasePanelViewer or BaseViewer in existing code, do not extend these classes in new code. See Bootstrap 5 vs Legacy for the full picture.
In the legacy system, controllers work through a viewer layer:
BasePanelViewer (legacy controller)
│
└── renders → BasePanel from Primitives/ (legacy, monolithic)
BaseViewer(abstract, legacy) — base for all viewer-based controllers. Manages async drawing and element lifecycle internally.BasePanelViewer(legacy) — viewer that acts as controller + renderer. Ties aBasePanel(Primitives) instance to its rendering context.
In contrast, the Bootstrap 5 pattern has no viewer intermediary:
BasePanelController<MyPanel> ← Bootstrap 5 controller (no viewer)
│
└── manages → MyPanel (extends Bootstrap/Primitives/BasePanel)
BasePanelController<Panel>— the Bootstrap 5 MVC controller. Generic over the Panel type, providingFetchData(),beforeLoad(),resolver()lifecycle hooks and access toHttpManagerandEventsManager.
ImageProcessor
The ImageProcessor module (Io.Oidis.Gui.ImageProcessor) provides canvas-based image manipulation utilities:
ImageFilters— pixel-level operations (brightness, contrast, grayscale, sepia, etc.)ImageTransform— geometric transformations (crop, scale, rotate)
These are used internally by the CropBox and image viewer components. Solution developers interact with these capabilities through those components' APIs rather than calling ImageProcessor directly.
See also: Panels and Controllers | Data Binding | Events System | Page-Panel-Controller