- Fixed Music app layout using incremental edit approach - Documented RmlUi file encoding issue in DESKTOP-DESIGNER.md - Added workaround: copy from working file and edit incrementally
8.8 KiB
Desktop Designer
The desktop designer (designer/) provides rapid UI development with:
- Hot-reload: Automatically reloads when RML/RCSS/Lua files change
- Shell Mode: Persistent system UI (status bar, nav bar) with apps loading into container
- UI Hierarchy Dumping: Exports element tree to JSON for inspection
- Screenshot Capture: PNG export via F12 key
- Logging: Detailed output for debugging navigation and events
- Action Recording: Record mouse/keyboard interactions to JSON
- Action Playback: Replay recorded interactions with timing
Key Files
| File | Purpose |
|---|---|
designer/main.cpp |
Main entry point, GLFW window, event loop |
designer/src/desktop_sandbox.cpp |
Per-app sandbox isolation |
designer/src/app_discovery.cpp |
Scans directories for app manifests |
designer/src/testing/ui_inspector.cpp |
UI hierarchy JSON export |
designer/src/testing/visual_capture.cpp |
PNG screenshot capture |
designer/src/testing/action_recorder.cpp |
Record user interactions |
designer/src/testing/action_player.cpp |
Playback recorded actions |
Command Line Options
General:
--resolution WxH Set window resolution (default: 540x960)
--assets PATH Set assets directory (default: derived from document)
--log FILE Write all log messages to file
--hierarchy FILE Continuously dump UI hierarchy to JSON
Simulator mode:
--simulator Run in simulator mode (uses shell by default)
--no-shell Disable shell (use direct document loading)
--test-apps PATH Path to test-apps directory (default: ./base-apps)
Test modes:
--record FILE Record user actions to JSON file
--playback FILE Playback actions from JSON file
--screenshot FILE Take screenshot and exit
--dump-hierarchy FILE Dump UI hierarchy to JSON and exit
Running the Designer
Simulator Mode with Shell (Recommended)
cd MosisService
./designer/build/Release/mosis-designer.exe --simulator --test-apps base-apps
This will:
- Load the system shell with persistent status bar and navigation bar
- Load home screen content into the shell's app container
- Scan
base-apps/for apps with validmanifest.json - Enable app navigation with proper back button support
Simulator Mode without Shell
To test the old direct-document approach:
./designer/build/Release/mosis-designer.exe --simulator --test-apps base-apps --no-shell
Direct Document Mode
To load a specific RML document directly:
./designer/build/Release/mosis-designer.exe path/to/document.rml
Keyboard Controls
| Key | Function |
|---|---|
| F5 | Reload document / Start-stop recording |
| F12 | Toggle RmlUi debugger |
| ESC | Back navigation |
| R | Start/Stop recording (in interactive mode) |
Shell Architecture
The shell (apps/shell/) provides a persistent system UI layer that prevents apps from taking over the full screen.
Shell Components
┌──────────────────────────────┐
│ Status Bar (36px) │ ← Time, WiFi, Signal, Battery
├──────────────────────────────┤
│ │
│ App Container │ ← App content loads here
│ (flex: 1) │
│ │
├──────────────────────────────┤
│ Navigation Bar (56px) │ ← Back, Home, Recents
└──────────────────────────────┘
Overlay Layers (z-index order):
- Dialog overlay (z: 600) ← Modal dialogs
- Toast container (z: 500) ← Toast notifications
- Notification panel (z: 400) ← Pull-down notifications
- Loading overlay (z: 300) ← App loading spinner
Shell Files
| File | Purpose |
|---|---|
apps/shell/shell.rml |
Shell document with status bar, nav bar, overlays |
apps/shell/shell.lua |
Navigation, toasts, dialogs, notifications |
App Content Fragments
Apps in shell mode use content fragments (*_content.rml) instead of full documents:
<!-- camera_content.rml - No <rml>, <head>, or document structure -->
<style>
.camera-content { ... }
</style>
<div class="camera-content">
<!-- App UI here -->
</div>
Shell Lua API
Functions available to apps via shell:
-- Navigation
shellNavigateTo("settings") -- Navigate to system app
shellLaunchApp(id, path, entry) -- Launch external app
shellGoBack() -- Go to previous app
shellGoHome() -- Go to home (clear history)
-- UI Feedback
showToast("Message") -- Show toast notification
showToast("Error!", "error") -- Toast types: default, success, error, warning
showDialog("Title", "Message", onConfirm, onCancel)
-- Notifications
addNotification("Title", "Text", icon, app_id)
toggleNotifications() -- Show/hide notification panel
clearNotifications()
Creating Content Fragments
- Create
appname_content.rml(not a full document) - Include styles via
<style>tag - Use shell functions for navigation (
shellNavigateTo,showToast, etc.) - Don't include status bar or nav bar (shell provides these)
Example:
<!-- settings_content.rml -->
<style>
.settings-list { padding: 16px; }
.settings-item { padding: 16px; cursor: pointer; }
</style>
<div class="settings-list">
<div class="settings-item" onclick="showToast('WiFi settings')">
WiFi
</div>
<div class="settings-item" onclick="showToast('Bluetooth settings')">
Bluetooth
</div>
</div>
Content Fragment Locations
| App | Content Fragment Path |
|---|---|
| Home | apps/home/home_content.rml |
| Camera | apps/camera/camera_content.rml |
| Dialer | apps/dialer/dialer_content.rml |
| Messages | apps/messages/messages_content.rml |
| Browser | apps/browser/browser_content.rml |
| Settings | apps/settings/settings_content.rml |
| Music | apps/music/music_content.rml |
| Store | apps/store/store_content.rml |
| Contacts | apps/contacts/contacts_content.rml |
Hot Reload
The designer watches for file changes in the assets directory:
- RML files: Reloads document
- RCSS files: Reloads stylesheets
- Lua files: Reloads scripts
- TGA/PNG files: Reloads textures
Press F5 to force reload.
UI Hierarchy Dump
Use --hierarchy to continuously dump the UI element tree:
./designer/build/Release/mosis-designer.exe --simulator --hierarchy ui_tree.json
The JSON contains element bounds, classes, IDs, and visibility - useful for automated testing.
Action Recording and Playback
See TESTING-FRAMEWORK.md for details on recording and playing back UI interactions.
Known Issues and Workarounds
RmlUi Layout Breaking Due to File Encoding
Problem: Content fragments created with certain file-writing methods may render with broken layouts - elements appear with 0 width, text wraps excessively, and flex layouts collapse.
Symptoms:
- List items don't expand to full width
- Text wraps to very narrow columns
- Avatars/icons overlap with text
- UI hierarchy shows
"width": 0.0for elements that should have proper width
Root Cause: RmlUi's parser is sensitive to certain invisible file formatting. While files may appear identical in text editors and have the same line endings (CRLF), subtle encoding differences can break layout parsing.
Diagnosis: Use --hierarchy FILE flag to dump UI element dimensions:
./designer/build/Release/mosis-designer.exe --simulator --playback tests/test_app.json --hierarchy hierarchy.json
Check the JSON for elements with "width": 0.0 that should have proper dimensions.
Workaround: Instead of creating content fragments from scratch, copy an existing working file and modify it:
# 1. Copy a known working file (e.g., messages_content.rml)
cp src/main/assets/apps/messages/messages_content.rml src/main/assets/apps/myapp/myapp_content.rml
# 2. Edit the file incrementally (use sed, text editor, or Edit tool)
# DO NOT rewrite the entire file - preserve the original byte structure
# 3. Test the layout
./designer/build/Release/mosis-designer.exe --simulator --playback tests/test_myapp.json --screenshot-after test.png
Working Reference Files:
apps/messages/messages_content.rml- Known good file formatapps/store/store_content.rml- Created by copying from messagesapps/settings/settings_content.rml- Created by copying from messages
Prevention: When creating new content fragments:
- Always start by copying an existing working content fragment
- Make incremental edits rather than full file rewrites
- Test layout after changes using
--hierarchyflag