Skip to content

User Interface Components

Samera2022 edited this page Jan 30, 2026 · 1 revision

User Interface Components

Relevant source files

Purpose and Scope

This document provides an overview of the MouseMacros user interface component architecture, including the main window, dialog system, component hierarchy, and user interaction patterns. It covers the structural organization of UI elements and how they interact with the core macro system.

For detailed documentation on specific dialogs, see:

For information about the main application window's integration with macro recording and playback, see Main Window (MainFrame)).


UI Component Architecture

The MouseMacros UI is built using Java Swing and follows a dialog-based architecture where the MainFrame serves as the primary application window, and multiple specialized JDialog subclasses provide configuration and information interfaces.

Component Hierarchy

flowchart TD

JFrame["JFrame"]
JDialog["JDialog"]
MainFrame["MainFrame<br>(Primary Application Window)"]
SettingsDialog["SettingsDialog<br>(Application Settings)"]
MacroSettingsDialog["MacroSettingsDialog<br>(Macro Configuration)"]
HotkeyDialog["HotkeyDialog<br>(Hotkey Capture)"]
AboutDialog["AboutDialog<br>(Author Information)"]
UpdateInfoDialog["UpdateInfoDialog<br>(Version History)"]

JFrame --> MainFrame
JDialog --> SettingsDialog
JDialog --> MacroSettingsDialog
JDialog --> HotkeyDialog
JDialog --> AboutDialog
JDialog --> UpdateInfoDialog
MainFrame --> SettingsDialog
MainFrame --> MacroSettingsDialog
SettingsDialog --> HotkeyDialog
SettingsDialog --> AboutDialog
SettingsDialog --> UpdateInfoDialog
Loading

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L1-L180, src/io/github/samera2022/mouse_macros/ui/frame/SettingsDialog.java L1-L220


MainFrame Components

The MainFrame class is the primary application window and contains the main UI elements for macro operations.

Main Window Structure

Component Type Field Name Purpose Location
JButton startBtn Initiates macro recording Row 1
JButton stopBtn Stops macro recording Row 1
JButton playBtn Plays recorded macro Row 1
JButton abortBtn Emergency abort for running macros Row 2
JButton saveBtn Saves macro to .mmc file Row 2
JButton loadBtn Loads macro from .mmc file Row 2
JButton settingsBtn Opens SettingsDialog Row 2
JButton macroSettingsBtn Opens MacroSettingsDialog Row 2
JTextArea logArea Displays status messages Center
flowchart TD

Row1["row1: FlowLayout<br>startBtn | stopBtn | playBtn"]
Row2["row2: FlowLayout<br>abortBtn | saveBtn | loadBtn | settingsBtn | macroSettingsBtn"]
Separator["JSeparator (Horizontal)"]
Center["Center: BorderLayout.CENTER<br>JScrollPane containing logArea"]
South["South: BorderLayout.SOUTH<br>southContainer"]

subgraph subGraph2 ["MainFrame Layout"]
    Center
    South

subgraph southContainer ["southContainer"]
    Separator

subgraph ButtonPanel ["ButtonPanel"]
    Row1
    Row2
end
end
end
Loading

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L26-L112

Button Action Listeners

flowchart TD

startBtn["startBtn"]
StartRecording["MacroManager.startRecording()"]
stopBtn["stopBtn"]
StopRecording["MacroManager.stopRecording()"]
playBtn["playBtn"]
Play["MacroManager.play()"]
abortBtn["abortBtn"]
Abort["MacroManager.stopRecording()"]
saveBtn["saveBtn"]
Save["MacroManager.saveToFile(this)"]
loadBtn["loadBtn"]
Load["MacroManager.loadFromFile(this)"]
settingsBtn["settingsBtn"]
OpenSettings["new SettingsDialog().setVisible(true)"]
macroSettingsBtn["macroSettingsBtn"]
OpenMacro["new MacroSettingsDialog().setVisible(true)"]

startBtn --> StartRecording
stopBtn --> StopRecording
playBtn --> Play
abortBtn --> Abort
saveBtn --> Save
loadBtn --> Load
settingsBtn --> OpenSettings
macroSettingsBtn --> OpenMacro
Loading

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L118-L125


Dialog System Overview

The application uses modal dialogs for all configuration interfaces. Each dialog is a separate JDialog subclass that handles its own layout, event handling, and configuration persistence.

Dialog Invocation Pattern

All dialogs follow a consistent pattern:

  1. Dialog is instantiated when user clicks a button
  2. Dialog constructor initializes UI components and applies current configuration
  3. Dialog is displayed modally (setModal(true))
  4. User interactions update local state
  5. "Save" button persists changes via ConfigManager.saveConfig()
  6. Dialog closes and main window refreshes if needed
sequenceDiagram
  participant User
  participant MainFrame
  participant settingsBtn
  participant SettingsDialog
  participant ConfigManager
  participant Localizer

  User->>settingsBtn: Click
  settingsBtn->>MainFrame: ActionListener triggered
  MainFrame->>SettingsDialog: new SettingsDialog()
  SettingsDialog->>ConfigManager: Load current config
  SettingsDialog->>SettingsDialog: Initialize UI with config values
  SettingsDialog->>SettingsDialog: Apply theme via ComponentUtil
  MainFrame->>SettingsDialog: setVisible(true)
  note over SettingsDialog: User modifies settings
  User->>SettingsDialog: Click "Save Settings"
  SettingsDialog->>ConfigManager: saveConfig(config)
  SettingsDialog->>ConfigManager: reloadConfig()
  SettingsDialog->>Localizer: load(config.lang)
  SettingsDialog->>MainFrame: refreshMainFrameTexts()
  SettingsDialog->>SettingsDialog: dispose()
Loading

Sources: src/io/github/samera2022/mouse_macros/ui/frame/SettingsDialog.java L172-L189, src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L124-L125


Configuration Dialogs

SettingsDialog Structure

The SettingsDialog provides a hierarchical configuration interface with conditional visibility for dependent settings.

Key UI Elements:

Component Field/Variable Configuration Key Description
JCheckBox followSysBox config.followSystemSettings Master toggle for system integration
JComboBox<String> langCombo config.lang Language selection (disabled when following system)
JCheckBox darkModeBox config.enableDarkMode Dark mode toggle (disabled when following system)
JCheckBox enableDefaultStorageBox config.enableDefaultStorage Enable default macro storage path
JTextField pathField config.defaultMmcStoragePath Default storage path (disabled unless enabled)
JButton browseBtn N/A Opens directory chooser
JButton hotkeyBtn N/A Opens HotkeyDialog
JButton aboutBtn N/A Opens AboutDialog
JButton updateInfoBtn N/A Opens UpdateInfoDialog
flowchart TD

EnableStorage["enableDefaultStorageBox: JCheckBox"]
PathField["pathField: JTextField"]
Browse["browseBtn: JButton"]
FollowSys["followSysBox: JCheckBox"]
Lang["langCombo: JComboBox"]
DarkMode["darkModeBox: JCheckBox"]
SettingsDialog["SettingsDialog"]
Hotkey["hotkeyBtn: JButton"]
About["aboutBtn: JButton"]
Update["updateInfoBtn: JButton"]
Save["saveSettingsBtn: JButton"]
HotkeyDialog["new HotkeyDialog()"]
AboutDialog["new AboutDialog()"]
UpdateInfoDialog["new UpdateInfoDialog()"]

Hotkey --> HotkeyDialog
About --> AboutDialog
Update --> UpdateInfoDialog

subgraph subGraph2 ["Action Buttons"]
    Hotkey
    About
    Update
end

subgraph subGraph1 ["Storage Settings"]
    EnableStorage
    PathField
    Browse
    EnableStorage --> PathField
    EnableStorage --> Browse
end

subgraph subGraph0 ["Main Settings"]
    FollowSys
    Lang
    DarkMode
    FollowSys --> Lang
    FollowSys --> DarkMode
end
Loading

Sources: src/io/github/samera2022/mouse_macros/ui/frame/SettingsDialog.java L43-L168

MacroSettingsDialog Structure

The MacroSettingsDialog provides macro-specific configuration options that override default behavior when enabled.

Key UI Elements:

Component Purpose Configuration Key
JCheckBox (custom settings) Enable custom macro settings config.enableCustomMacroSettings
JSpinner (repeat count) Number of times to repeat macro config.repeatTime

Sources: Referenced in src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L98


Event Flow and State Management

MainFrame Initialization Sequence

sequenceDiagram
  participant MainFrame()
  participant ConfigManager
  participant SystemUtil
  participant Localizer
  participant JNativeHook GlobalScreen
  participant ComponentUtil
  participant CacheManager

  MainFrame()->>ConfigManager: Check config.followSystemSettings
  loop [followSystemSettings == true]
    MainFrame()->>ConfigManager: getAvailableLangs()
    MainFrame()->>SystemUtil: getSystemLang(availableLangs)
    MainFrame()->>SystemUtil: isSystemDarkMode()
    MainFrame()->>ConfigManager: Update config.lang and config.enableDarkMode
  end
  MainFrame()->>Localizer: load(config.lang)
  MainFrame()->>Localizer: setRuntimeSwitch(true)
  MainFrame()->>ConfigManager: Load keyMap (hotkeys)
  note over MainFrame(): Initialize keyRecord, keyStop, keyPlay, keyAbort
  MainFrame()->>MainFrame(): Create logArea (JTextArea)
  MainFrame()->>MainFrame(): Create buttons (JButton)
  MainFrame()->>MainFrame(): Attach action listeners
  MainFrame()->>MainFrame(): Set up layout (BorderLayout)
  MainFrame()->>JNativeHook GlobalScreen: registerNativeHook()
  MainFrame()->>JNativeHook GlobalScreen: addNativeKeyListener(GML)
  MainFrame()->>JNativeHook GlobalScreen: addNativeMouseListener(GML)
  MainFrame()->>JNativeHook GlobalScreen: addNativeMouseWheelListener(GML)
  MainFrame()->>JNativeHook GlobalScreen: addNativeMouseMotionListener(GML)
  MainFrame()->>ComponentUtil: setMode(getContentPane(), theme)
  MainFrame()->>ComponentUtil: applyWindowSizeCache(this, "title", 430, 330)
Loading

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L39-L148

Button State Management

The MainFrame implements guard conditions to prevent invalid state transitions:

Recording Guards:

Button Condition Action Guard Logic
startBtn !MacroManager.isRecording() && !HotkeyDialog.inHotKeyDialog Start recording MainFrame.java L118
stopBtn MacroManager.isRecording() && !HotkeyDialog.inHotKeyDialog Stop recording MainFrame.java L119
playBtn !MacroManager.isRecording() && !HotkeyDialog.inHotKeyDialog Play macro MainFrame.java L120
abortBtn MacroManager.isPlaying() && !HotkeyDialog.inHotKeyDialog Abort playback MainFrame.java L121
saveBtn !MacroManager.isRecording() Save to file MainFrame.java L122
loadBtn !MacroManager.isRecording() Load from file MainFrame.java L123

The HotkeyDialog.inHotKeyDialog flag prevents hotkey conflicts when the user is configuring hotkeys.

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L118-L123


Cross-Cutting UI Concerns

Localization Integration

All UI components support runtime language switching through the Localizer class.

MainFrame Localization:

flowchart TD

Localizer["Localizer.get(key)"]
Title["setTitle(Localizer.get('title'))"]
StartBtn["startBtn text with hotkey"]
StopBtn["stopBtn text with hotkey"]
PlayBtn["playBtn text with hotkey"]
AbortBtn["abortBtn text with hotkey"]
SaveBtn["saveBtn text"]
LoadBtn["loadBtn text"]
SettingsBtn["settingsBtn text"]
MacroBtn["macroSettingsBtn text"]

Localizer --> Title
Localizer --> StartBtn
Localizer --> StopBtn
Localizer --> PlayBtn
Localizer --> AbortBtn
Localizer --> SaveBtn
Localizer --> LoadBtn
Localizer --> SettingsBtn
Localizer --> MacroBtn
Loading

The refreshMainFrameTexts() method reapplies all localized strings after a language change:

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L152-L162

Theming Integration

All UI components apply theming through ComponentUtil.setMode() which accepts a theme constant (OtherConsts.DARK_MODE or OtherConsts.LIGHT_MODE).

Theming Application Points:

Component Theme Application Line Reference
MainFrame On construction MainFrame.java L142
MainFrame logArea scrollbar On construction MainFrame.java L72-L73
SettingsDialog On construction SettingsDialog.java L215
SettingsDialog On save SettingsDialog.java L186-L187

Custom Components:

  • CustomScrollBarUI: Custom scrollbar rendering for themed appearance MainFrame.java L72-L73
  • Color scheme provided by ColorConsts class

For detailed theme implementation, see Theming System.

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L142, src/io/github/samera2022/mouse_macros/ui/frame/SettingsDialog.java L186-L187

Window Size Persistence

All dialogs and the main frame use ComponentUtil.applyWindowSizeCache() to remember and restore window dimensions across sessions.

Cached Windows:

Window Cache Key Default Size (W×H) Code Reference
MainFrame "title" 430×330 MainFrame.java L144
SettingsDialog "settings" 521×359 SettingsDialog.java L216

Cache data is persisted via CacheManager to cache.json. For details, see CacheManager.

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L144, src/io/github/samera2022/mouse_macros/ui/frame/SettingsDialog.java L216


Window Lifecycle Management

WindowClosingAdapter

The WindowClosingAdapter is attached to all top-level windows to ensure proper cleanup and state persistence on close.

flowchart TD

Window["Window (JFrame/JDialog)"]
Adapter["WindowClosingAdapter"]
WindowEvent["windowClosing(WindowEvent)"]
CacheManager["CacheManager"]
SizeCache["SizeCache.add(name, width, height)"]
SaveCache["CacheManager.saveCache()"]

Window --> Adapter
Adapter --> WindowEvent
WindowEvent --> SizeCache
SizeCache --> SaveCache
Loading

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L147, src/io/github/samera2022/mouse_macros/ui/frame/SettingsDialog.java L218

Dynamic Width Adjustment

MainFrame dynamically adjusts its width to accommodate button labels, which vary based on:

  1. Selected language (text length varies)
  2. Hotkey assignments (displayed in parentheses)

Adjustment Logic:

flowchart TD

RefreshTexts["refreshMainFrameTexts()"]
UpdateLabels["Update button texts with hotkeys"]
AdjustWidth["ComponentUtil.adjustFrameWidth(...)"]
Pack["MAIN_FRAME.pack()"]
Resize["setSize(width, scaled_height)"]

RefreshTexts --> UpdateLabels
UpdateLabels --> AdjustWidth
AdjustWidth --> Pack
Pack --> Resize
Loading

The adjustFrameWidth() method measures button preferred sizes and ensures all buttons fit horizontally.

Sources: src/io/github/samera2022/mouse_macros/ui/frame/MainFrame.java L161-L179


Summary

The MouseMacros UI architecture follows these key patterns:

  1. Single Main Window: MainFrame is the persistent primary window
  2. Modal Dialogs: Configuration via modal JDialog subclasses
  3. Centralized Theming: All components styled via ComponentUtil.setMode()
  4. Runtime Localization: Language switching without restart via Localizer
  5. State Persistence: Window sizes and directory paths cached via CacheManager
  6. Guard Conditions: Button handlers check state before executing actions
  7. Event-Driven Updates: Configuration changes propagate via explicit refresh methods

For implementation details of specific dialogs, see the sub-pages listed at the beginning of this document.

Clone this wiki locally