Phase 2 complete. Core infrastructure, all main gadgets, scrollbars, and three sample applications are working.
Point— Immutable 2D point with arithmetic helpers (plus, minus, min, max)Rect— Rectangle (top-left origin + width/height); intersect, union, contains, growDuple<X, Y>— Immutable typed pair; implementsequals/hashCodeso it can be used as a map or cache keyTriple<X, Y, Z>— Immutable typed triplet; implementsequals/hashCode(viaObjects.hash) so it can be used as a map or cache key; companion toDupleCache<K, V>— Bounded FIFO cache backed by aLinkedHashMapwithremoveEldestEntry; configurablemaxSize; operations:get,put,contains,size,maxSize,clearTexHelper— Static helper that parses text-mode TeX strings and lays them out as cachedTeXIconobjects via JLaTeXMath. Input is plain text with optional\math{...}inline math blocks; newlines produce line breaks. Conversion pipeline:toLatex()wraps text in\text{...}and emits math verbatim inside\begin{array}{l}...\end{array}. Icons are stored in a staticCache<Duple<String,Float>, TeXIcon>(FIFO, 32 entries) keyed by(text, fontSize)— color-independent; color is applied viaTeXIcon.setForegroundat paint time. Public API:getOrCreateIcon(text, fontSize),measure(text, fontSize),clearCache().
Event— Base event:whattype constant,EV_NOTHINGsentinelEventMouse— Mouse event:where(Point), button mask, modifiers;withOffset(dx,dy)for coordinate translationEventKeyboard— Keyboard event: key code, char, modifiersEventCommand— Command event:commandIdfor routing UI actions up the hierarchyEventLwjglAdapter— Converts GLFW raw input callbacks → S.W.O.R.DEventMouse/EventKeyboard
ScreenArea— Root of the visual hierarchy:fatherreference, status bitmask flags (SF_VISIBLE,SF_SELECTED,SF_MOUSE_IN,SF_DOWN,SF_FOCUSED,SF_MODIFIED), virtual event handlers (mouseLDown,mouseMove,keyDown,command, …), drawing area withbounds,clipRect,draw()/paint(),getAbsolutePosition(),contains()Widget— Extends ScreenArea; addsenabledboolean (isEnabled()/setEnabled())Canvas— Transparent container for Widget children stored inLinkedList<Widget>; dispatches events in reverse (topmost first) z-orderWindow— Overlapping window: left sidebar (drag grip + optional close button), outer resize border; internalCanvas;bringToFront()/remove(). Options:setResizable(bool)(thick border + resize handles vs. 1-px outline),setClosable(bool)(show/hide × button),setPalette(WindowPalette)(colour scheme for this window and all its widgets).setOnResize(Runnable)callback fired on resize.draw()injects the window's palette into thePaintContextbefore delegating tosuper.draw(),canvas.draw(), anddrawOverlay()so the entire hierarchy uses the same palette automatically.Screen— Plain class (not aScreenArea): managesLinkedList<Window>with z-ordering; dispatches events topmost-first; routes unhandled commands to the registeredIntPredicatecommand handler. Windows hold a directscreenreference (Window.getScreen()) set byScreen.add();Screenis never in theScreenArea.fatherchain. Application-level commands (those not consumed by any window) are queued inpendingCommandsand drained byprocessPendingCommands()from the main loop — outside GLFW callbacks — so that modal handlers likeexecDialog()can safely pump the GLFW event loop.WindowPalette— Set of five coordinated colours (black,dark,medium,face,white) that defines the visual appearance of a window and all its widgets. Three pre-built instances:STANDARD(neutral grays, default),GREEN(slightly green-tinted, used by Menu/MenuChoice),BLUE(slightly blue-tinted, used by Dialog). Assigned viaWindow.setPalette(); injected intoPaintContextbyWindow.draw()and propagated automatically throughwithOrigin().PaintContext—Graphics2Dwrapper with local-coordinate translation viawithOrigin(Point), palette propagation viawithPalette(WindowPalette), font-size propagation viawithFontSize(float), and HiDPI support viawithDpr(int)(device pixel ratio, default 1). All text is drawn throughTexHelper:drawString(x, y, text)callsgetOrCreateIcon, sets foreground to the current colour, and paints directly viaicon.paintIcon(null, g, ...)at the given coordinates;measureText(text)returns the icon dimensions for layout. No AWTFontorFontMetricsexposure.Application— Application shell (plain class, not a ScreenArea): owns aScreenand aLwjglDriver; extend and overridecreateMenuChoices()+handleCommand()
LwjglDriver— GLFW window + OpenGL 3.3 compositor. EachWindowrenders into its ownBufferedImage(viaWindow.renderToBuffer()/ Java2D);LwjglDriveruploads these as OpenGL textures and composites them in z-order each frame using a textured-quad shader. ProvidesforceRepaint()(no-op; continuous loop),quit(), and aframeStepRunnableregistered withScreenfor modal dialog loops. Requires-XstartOnFirstThreadand-Djava.awt.headless=trueon macOS.EventLwjglAdapter— Converts GLFW raw input (cursor pos, mouse button, key, char callbacks) → S.W.O.R.DEventMouse/EventKeyboard. GLFW key codes 65–90 and 48–57 match JavaVK_values directly.
Label— Non-interactive text label. Text is rendered viaPaintContext.drawString(→TexHelper) so plain text and\math{...}inline math are both supported.setFontSize(float)/getFontSize()control the JLaTeXMath point size (default 12 pt); centering usesctx.measureText().AbstractButton— Base for clickable buttons: 3D raised/pressed frame, scan-code support, command routingButton— Standard push button with centred textItemBox— Base for selection controls (no button frame); click togglesSF_DOWNCheckBox— Checkbox; bitmask integration withGroupBoxforgetData()RadioBox— Radio button; mutually exclusive withinGroupBoxGroupBox— Container forCheckBox/RadioBox; manages groupvalueand titled frameEditLine— Single-line text input: cursor, click-to-position, keyboard navigation, max length. Cursor x-position computed viaTexHelper.measure(prefix, fontSize).width.Menu— Menu bar (mainMenu=true) or dropdown; horizontal/vertical layouts, hotkey support. Choice widths computed viaTexHelper.measure().MenuChoice— Menu item: text, hotkey, command;separator=truefor dividersDialog— Window subclass with result codes (CM_OK,CM_CANCEL,CM_YES,CM_NO);execDialog()runs a GLFW-based modal loop viaScreen.getFrameStep(). CM_OK/CM_CANCEL are dispatched directly toDialog.command()within GLFW callbacks (not queued), sodialogResultis set immediately and the modal loop exits on the next iteration.StandardButtons— Factory for standard OK / Cancel / Yes / No button instancesScrollbar— Port ofTLift: H/V scrollbar with arrow buttons, thumb drag, page click;setRange(contentSize, viewSize),getPosition(),setOnChange(Runnable). Drag capture:mouseLUp/mouseMovereturn true while dragging even outside bounds.Scroller— Port ofTScroller: scrollable viewport backed by a viewport-sizedBufferedImage. Virtual content size (governs scrollbar range) is independent of the buffer. Mouse events are forwarded as viewport-local coordinates. Public API:setContentSize,setScrollPosition,getScrollX/Y,setOnScroll,resize(newViewW, newViewH)(live viewport resize).
Hello— Multiple overlapping draggable windows; each window contains aLabel(font size 22 pt) rendering "Hello World !" on the first line and the Gaussian integral formula via\math{...}on the second lineDialog— DemonstratesDialog,Button,CheckBox,RadioBox,GroupBox,EditLine,LabelMandel— Mandelbrot fractal viewer with zoom + pan.MandelWidgetrenders only the current viewport into aBufferedImage, trackingzoomandoffsetX/Y. Virtual world size is fixed atbaseW × baseH(set at construction) and scales with zoom (virtualW = baseW * zoom), so resizing the window reveals more of the complex plane rather than stretching the view. Left-click zooms in 2× (virtual world doubles, thumb halves); right-click undoes zoom. Wired toScrollerviaonZoomChange/onScrollcallbacks so scrollbars always reflect zoom level and enable full panning.
| Aspect | C++ Original | Java Port |
|---|---|---|
| Naming | All classes T-prefixed | Plain names used everywhere: ScreenArea, Application, WindowPalette, … No T-prefixed classes remain |
| Tree structure | TAtom: _Next/_Previous/_Son/_Father sibling chain |
Only father parent ref in ScreenArea; children in LinkedList |
| Child storage | TAtom linked tree | LinkedList<Widget> in Canvas, LinkedList<Window> in Screen |
| Event tables | C++ macros DEFINE_EVENTS_TABLE |
Virtual method overrides in ScreenArea subclasses |
| Graphics backend | libgrx20 calls | Java2D Graphics2D off-screen + LWJGL/OpenGL compositor |
| Driver coupling | N/A | Isolated in ui.driver (LwjglDriver + EventLwjglAdapter) |
| Data exchange | SetData()/GetData()/DataSize() |
Removed |
TShell |
Trivial TObject subclass | Removed; Application is a plain class |
TObject + TZone |
Separate mechanism/graphics layers | Merged into ScreenArea |
TDesktop |
Background application desktop | Screen (plain class, not a ScreenArea subclass) |
sfDisabled flag |
Status bitmask | Widget.enabled boolean |
opMainMenu / opSeparator |
Option bitmasks | Menu.mainMenu / MenuChoice.separator booleans |
opWinSizeable / opWinCloseBox |
Option bitmasks | Window.resizable / Window.closable booleans |
Button BO_* options |
Constructor parameter | Removed; use setEnabled(false) after construction |
| Packages | Flat subsystem names | ui.base, ui.widgets, ui.events, ui.driver |
- No TAtom: The linked sibling tree is removed. Children live in explicit
LinkedListcontainers in Canvas and Screen. - TObject merged into ScreenArea: The former mechanism/graphics split is collapsed.
ScreenAreais the single root for all visual objects; it holdsfather,status, event dispatch, bounds, and drawing. - Application is a plain class: Not a ScreenArea subclass. Owns a
Screenand aLwjglDriver; registers command/hotkey handlers via lambdas. - Driver isolated in
ui.driver:LwjglDriverholds the GLFW window and OpenGL compositor.EventLwjglAdaptertranslates GLFW callbacks. No LWJGL/AWT imports outside this package. - Screen is not a ScreenArea: Screen sits above the ScreenArea hierarchy.
ScreenArea.fatherterminates at the top-level Window (father = null). Windows hold a directScreenreference (Window.getScreen()) used for window management and command routing. - Parent reference only:
ScreenArea.fatherenables coordinate translation and event routing within the window hierarchy, but no sibling navigation. - Method-override event dispatch:
ScreenArea.handleEventdispatches via aswitchto overridable methods; no macro tables. - PaintContext: Local-coordinate translation is managed in
PaintContext; callers always draw in their own (0,0)-based coordinate space. - Window palette propagation:
Window.draw()callsctx.withPalette(palette)before passing tosuper.draw(),canvas.draw(), anddrawOverlay().PaintContext.withOrigin()copies the palette, so everypaint()method in the hierarchy receivesctx.palette()with the correct colour scheme — no extra wiring required. All widget paint methods readctx.palette().black/dark/medium/face/whiteinstead of staticTColorsconstants. - TexHelper / PaintContext text pipeline: All text drawing goes through
TexHelper. The expensive JLaTeXMath parse+layout step is cached in aCache<Duple<String,Float>, TeXIcon>(color-independent key).PaintContext.drawString(x, y, text)callsgetOrCreateIcon, setsTeXIcon.setForegroundto the current colour, and paints directly viaicon.paintIcon.PaintContext.measureText(text)reads icon dimensions directly. ThefontSizeis carried as a field onPaintContext;withFontSize(float)returns a derived context (just likewithPalette).LabelexposessetFontSize(float)so individual labels can override the default 12 pt. - Scrollbar drag capture: Like Window title-bar drag, Scrollbar returns
truefrommouseMove/mouseLUpwhiledragging==trueregardless of contains, so the thumb follows the mouse even outside the bar. - Scroller viewport buffer: Content renders at viewport size (not virtual size), so only the visible slice is computed. The scrollbar range tracks the virtual size independently. Scroll offset is forwarded to the content widget via callback.
- ✅ Object hierarchy (parent reference chain, command routing up)
- ✅ Event dispatching (mouse, keyboard, commands)
- ✅ Window creation, management, z-ordering, drag
- ✅ Overlapping window rendering
- ✅ Custom zone/widget painting
- ✅ GLFW input event conversion (EventLwjglAdapter)
- ✅ OpenGL compositing (LwjglDriver — per-window BufferedImage textures)
- ✅ Modal dialog event loop (execDialog — GLFW-based mini-loop)
- ✅ Button (standard push button, 3D pressed effect)
- ✅ CheckBox / RadioBox / GroupBox
- ✅ EditLine (text input, cursor, keyboard navigation)
- ✅ Menu / MenuChoice (hotkeys, separators, H+V layouts)
- ✅ Dialog (result codes OK/Cancel/Yes/No)
- ✅ Label (text +
\math{...}inline formulas via TexHelper; variable font size) - ✅ Scrollbar (arrow, thumb drag, page click, H/V)
- ✅ Scroller (viewport buffer, zoom-aware content/scrollbar sync)
- ✅ Mandel sample (fractal, zoom history, pan with scrollbars)
- ✅ Window palette system (
WindowPalette: STANDARD / GREEN / BLUE; propagated via PaintContext) - ✅ TexHelper (JLaTeXMath rendering, lazy FIFO cache, all text rendered via PaintContext)
- No window focus styling: Active window not visually distinct
- No COMMON subsystem: No path utilities, error handling, or debug facilities
- No DRIVERS subsystem: No file system or time/date access
- No TGauge: Progress bar not ported
- No IMAGE/MATH toolboxes: Deferred
- Mandel render blocks frame: Fractal re-render on zoom/scroll blocks the GLFW frame; async rendering is out of scope
[JRSAppKitAWT markAppIsDaemon]warning on macOS: Harmless. GLFW initializesNSApplicationbefore Java's headless setup completes natively; partial headless mode is sufficient for off-screen Java2D rendering alongside GLFW.
19 test classes, 217 tests (JUnit 5):
| Test Class | What It Tests |
|---|---|
PointTest |
Constructor, copy, arithmetic |
RectTest |
Constructors, geometry ops, intersect/union |
DupleTest |
Getters, equals/hashCode, null components, use as map key |
TripleTest |
Getters, equals/hashCode, null components, use as map key |
CacheTest |
put/get, FIFO eviction, size limit, contains, clear |
ScreenAreaTest |
Bounds, absolute position with parent chain, contains(Point), visibility, status flags, father reference |
CanvasTest |
Child widget management, parent wiring, unmodifiable list, widget order |
WindowPaletteTest |
Colour values for STANDARD/GREEN/BLUE, custom constructor, tint direction |
WindowTest |
Title, palette, resizable/closable flags, content dimensions, canvas sync on bounds change |
ScreenTest |
Desktop colour, add/remove/bringToFront, screen reference wiring, quitting flag, pending command queue |
CheckBoxTest |
Checked state, bitmask groups, disabled state |
TRadioBoxTest |
Mutual exclusion, getValue, disabled state |
EditLineTest |
setText, max length, null handling, enabled/disabled |
DialogTest |
Result codes (OK/Cancel/Yes/No), title, BLUE palette, non-resizable |
ButtonTest |
Text, null default, enabled/disabled, bounds |
MenuTest |
GREEN palette, not closable/resizable, choices list |
GroupBoxTest |
Title text, value field, null title, all constructors |
ScrollbarTest |
Initial state, H/V dimensions, setRange clamping, setPosition clamping |
LabelTest |
getText/setText, \math{} notation, getFontSize/setFontSize, bounds, visibility |
- Java source files: 39 (src/main)
- Test files: 19 (src/test)
- Total tests: 217
- Packages: 6 (ui, ui.events, ui.base, ui.widgets, ui.driver, samples)
- Classes: 39