# Macro Settings Dialog
> **Relevant source files**
> * [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java)
## Purpose and Scope
The Macro Settings Dialog provides a user interface for configuring custom macro playback behavior, specifically the ability to enable custom settings and define how many times a recorded macro should repeat during playback. This dialog is accessed from the main application window and persists its configuration to `config.cfg`.
For general application settings (language, dark mode, default storage paths), see [Settings Dialog](Settings-Dialog). For hotkey configuration, see [Hotkey Dialog](Exit-Dialog). For the underlying configuration persistence mechanism, see [ConfigManager](ConfigManager).
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L1-L138](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L1-L138)
---
## Class Overview
The `MacroSettingsDialog` class extends `JDialog` and is implemented in [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L16](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L16-L16)
### Key Characteristics
| Property | Value | Purpose |
| --- | --- | --- |
| Modal | `true` | Blocks interaction with parent window until closed |
| Window Name | `"macro_settings"` | Used for window size caching |
| Layout | `BorderLayout` | Main layout with 10px gaps |
| Icon | `IconConsts.CHECK_BOX` | Custom checkbox icons for consistent theming |
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L18-L26](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L18-L26)
---
## UI Component Hierarchy
The dialog follows a hierarchical structure with a title section, main content panel with indented sub-settings, and bottom action panel.
```mermaid
flowchart TD
Dialog["MacroSettingsDialog
(JDialog)"]
ContentPanel["content
(JPanel with BoxLayout.Y_AXIS)"]
Title["macroSettingsTitle
(JLabel - 18pt Bold)"]
Separator1["JSeparator"]
EnablePanel["enableCustomSettingsPanel
(FlowLayout.LEFT)"]
EnableLabel["enableCustomSettingsLabel
(JLabel)"]
EnableCheckbox["enableCustomSettingsBox
(JCheckBox)"]
SubPanel["subSettingsPanel
(BoxLayout.Y_AXIS, 32px left indent)"]
RepeatTimesPanel["repeatTimesPanel
(FlowLayout.LEFT)"]
RepeatTimesLabel["repeatTimesLabel
(JLabel)"]
RepeatTimesField["repeatTimesField
(JTextField, 7 columns)"]
RepeatDelayPanel["repeatDelayPanel
(FlowLayout.LEFT)"]
RepeatDelayLabel["repeatDelayLabel
(JLabel)"]
RepeatDelayField["repeatDelayField
(JTextField, 7 columns)"]
SavePanelContainer["savePanel
(FlowLayout.CENTER)"]
SaveButton["saveSettingsBtn
(JButton)"]
Dialog --> ContentPanel
Dialog --> SavePanelContainer
subgraph BorderLayout.SOUTH ["BorderLayout.SOUTH"]
SavePanelContainer
SaveButton
SavePanelContainer --> SaveButton
end
subgraph BorderLayout.CENTER ["BorderLayout.CENTER"]
ContentPanel
Title
Separator1
EnablePanel
EnableLabel
EnableCheckbox
SubPanel
RepeatTimesPanel
RepeatTimesLabel
RepeatTimesField
RepeatDelayPanel
RepeatDelayLabel
RepeatDelayField
ContentPanel --> Title
ContentPanel --> Separator1
ContentPanel --> EnablePanel
ContentPanel --> SubPanel
EnablePanel --> EnableLabel
EnablePanel --> EnableCheckbox
SubPanel --> RepeatTimesPanel
SubPanel --> RepeatDelayPanel
RepeatTimesPanel --> RepeatTimesLabel
RepeatTimesPanel --> RepeatTimesField
RepeatDelayPanel --> RepeatDelayLabel
RepeatDelayPanel --> RepeatDelayField
end
```
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L24-L98](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L24-L98)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L124-L126](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L124-L126)
---
## Configuration Options
The dialog exposes three interconnected configuration options from the `config` object:
### Enable Custom Macro Settings
| Field | Type | Config Path | Default State |
| --- | --- | --- | --- |
| Checkbox | `JCheckBox` | `config.enableCustomMacroSettings` | Read from config |
| Localization Key | String | `"macro_settings.enable_custom_macro_settings"` | - |
When this checkbox is **disabled**, both text fields become non-editable and default to `repeatTime = 1` and `repeatDelay = 0`.
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L37-L43](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L37-L43)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L106](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L106-L106)
### Repeat Count
| Field | Type | Config Path | Validation Rules |
| --- | --- | --- | --- |
| Text Field | `JTextField` | `config.repeatTime` | Positive integers, -1, or empty |
| Columns | 7 | - | Sufficient for 10-digit integers |
| Localization Key | String | `"macro_settings.repeat_times"` | - |
The repeat count determines how many times the `MacroManager` will execute the recorded action sequence during playback. A value of `-1` represents infinite repetition.
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L55-L68](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L55-L68)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L108](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L108-L108)
### Repeat Delay
| Field | Type | Config Path | Validation Rules |
| --- | --- | --- | --- |
| Text Field | `JTextField` | `config.repeatDelay` | Non-negative numbers with up to 3 decimal places |
| Columns | 7 | - | Sufficient for decimal values |
| Localization Key | String | `"macro_settings.repeat_delay"` | - |
The repeat delay specifies the time in seconds to wait between each repetition of the macro. This delay is applied after completing one full execution of the action sequence before starting the next repetition.
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L70-L80](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L70-L80)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L115](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L115-L115)
---
## Input Validation System
Both text fields implement strict input validation using `DocumentFilter` instances to prevent invalid data entry at the keystroke level.
### Repeat Times Field Validation
The `repeatTimesField` uses a custom `DocumentInputFilter` that validates integer input:
```mermaid
flowchart TD
Input["User Input"]
Filter["DocumentInputFilter
isValidContent()"]
Check1["Is '-1'?"]
Check2["Matches \d+
(positive int)?"]
Check3["Is empty string?"]
Check4["Is single '-'?"]
Accept["Input Accepted"]
Reject["Input Rejected"]
Input --> Filter
Filter --> Check1
Check1 --> Accept
Check1 --> Check2
Check2 --> Accept
Check2 --> Check3
Check3 --> Accept
Check3 --> Check4
Check4 --> Accept
Check4 --> Reject
```
**Validation Pattern**: `text.equals("-1") || text.matches("\\d+") || text.isEmpty() || text.equals("-")`
**Special Cases**:
* **`-1`**: Allowed as a special value for infinite repetition
* **Single `"-"`**: Allowed temporarily to facilitate typing `-1`
* **Empty string**: Allowed to clear the field
* **Positive integers**: Any sequence of digits
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L62-L68](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L62-L68)
### Repeat Delay Field Validation
The `repeatDelayField` uses a custom `DocumentInputFilter` that validates decimal number input:
```mermaid
flowchart TD
Input["User Input"]
Filter["DocumentInputFilter
isValidContent()"]
Check1["Matches \d*\.\d{0,3}
(decimal with up to 3 places)?"]
Check2["Is empty string?"]
Accept["Input Accepted"]
Reject["Input Rejected"]
Input --> Filter
Filter --> Check1
Check1 --> Accept
Check1 --> Check2
Check2 --> Accept
Check2 --> Reject
```
**Validation Pattern**: `text.matches("\\d*(\\.\\d{0,3})?") || text.isEmpty()`
**Allowed Values**:
* **Integers**: `0`, `1`, `123`
* **Decimals**: `0.5`, `1.234`, `10.1`
* **Partial input**: `.`, `1.`, `1.2` (facilitates typing)
* **Empty string**: Allowed to clear the field
* **Maximum precision**: 3 decimal places
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L74-L80](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L74-L80)
### DocumentInputFilter Implementation
Both fields use the `DocumentInputFilter` class from [io.github.samera2022.mouse_macros.filter.DocumentInputFilter
1](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/io.github.samera2022.mouse_macros.filter.DocumentInputFilter#L1-LNaN)
which extends `AbstractDocument.DocumentFilter`. The filter intercepts all text modification operations and validates the resulting string before allowing the change.
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L62-L80](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L62-L80)
---
## State Linkage and Event Handling
The dialog implements reactive state management where both text fields' enabled states follow the checkbox state.
```mermaid
sequenceDiagram
participant User
participant enableCustomSettingsBox
participant followSysListener
participant repeatTimesField
participant repeatDelayField
note over enableCustomSettingsBox,repeatDelayField: Initial State Setup
enableCustomSettingsBox->>followSysListener: addItemListener(followSysListener)
followSysListener->>followSysListener: itemStateChanged(null)
followSysListener->>enableCustomSettingsBox: isSelected()?
loop [Enabled]
followSysListener->>repeatTimesField: setEnabled(true)
followSysListener->>repeatDelayField: setEnabled(true)
followSysListener->>repeatTimesField: setEnabled(false)
followSysListener->>repeatTimesField: setText("1")
followSysListener->>repeatDelayField: setEnabled(false)
followSysListener->>repeatDelayField: setText("0")
note over User,repeatDelayField: User Interaction
User->>enableCustomSettingsBox: Toggle checkbox
enableCustomSettingsBox->>followSysListener: itemStateChanged(event)
followSysListener->>enableCustomSettingsBox: isSelected()?
followSysListener->>repeatTimesField: setEnabled(true)
followSysListener->>repeatDelayField: setEnabled(true)
followSysListener->>repeatTimesField: setEnabled(false)
followSysListener->>repeatTimesField: setText("1")
followSysListener->>repeatDelayField: setEnabled(false)
followSysListener->>repeatDelayField: setText("0")
end
```
### Implementation
The linkage is implemented via an `ItemListener` attached to the checkbox that controls both text fields:
| Action | Checkbox State | repeatTimesField | repeatDelayField |
| --- | --- | --- | --- |
| Enable | Selected | `setEnabled(true)` | `setEnabled(true)` |
| Disable | Not Selected | `setEnabled(false)`, `setText("1")` | `setEnabled(false)`, `setText("0")` |
The listener is invoked immediately after registration with `itemStateChanged(null)` to establish the initial state based on the loaded configuration.
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L128-L138](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L128-L138)
---
## Save Operation and Data Flow
When the user clicks the save button, the dialog validates input from both fields, updates the configuration object, persists to disk, and closes.
```mermaid
sequenceDiagram
participant User
participant saveSettingsBtn
participant MacroSettingsDialog
participant config object
participant ConfigManager
participant config.cfg
User->>saveSettingsBtn: Click "Save Settings"
saveSettingsBtn->>MacroSettingsDialog: ActionListener triggered
MacroSettingsDialog->>MacroSettingsDialog: text = repeatTimesField.getText()
MacroSettingsDialog->>MacroSettingsDialog: delayText = repeatDelayField.getText()
loop [Parse successful]
MacroSettingsDialog->>config object: config.enableCustomMacroSettings = checkbox.isSelected()
MacroSettingsDialog->>config object: config.repeatTime = Integer.parseInt(text)
MacroSettingsDialog->>MacroSettingsDialog: printStackTrace()
MacroSettingsDialog->>config object: (value unchanged)
MacroSettingsDialog->>MacroSettingsDialog: config.repeatDelay = Double.parseDouble(delayText)
end
MacroSettingsDialog->>ConfigManager: printStackTrace()
ConfigManager->>config.cfg: (value unchanged)
MacroSettingsDialog->>ConfigManager: saveConfig(config)
ConfigManager->>config.cfg: Write JSON to config.cfg
ConfigManager->>config object: reloadConfig()
MacroSettingsDialog->>MacroSettingsDialog: Read config.cfg
note over MacroSettingsDialog: Window closes
```
### Error Handling
| Scenario | Behavior | Code Reference |
| --- | --- | --- |
| Empty repeatTimes field | repeatTime not updated, no error | [MacroSettingsDialog.java L105](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/MacroSettingsDialog.java#L105-L105) |
| Empty repeatDelay field | repeatDelay not updated, no error | [MacroSettingsDialog.java L113](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/MacroSettingsDialog.java#L113-L113) |
| Invalid integer format (repeatTime) | Exception printed, value unchanged | [MacroSettingsDialog.java L109-L111](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/MacroSettingsDialog.java#L109-L111) |
| Invalid decimal format (repeatDelay) | Exception printed, value unchanged | [MacroSettingsDialog.java L116-L118](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/MacroSettingsDialog.java#L116-L118) |
| Valid input | Save and reload config | [MacroSettingsDialog.java L120-L122](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/MacroSettingsDialog.java#L120-L122) |
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L102-L123](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L102-L123)
---
## Integration Points
### Configuration Manager
The dialog reads and writes to the global `config` object via `ConfigManager`:
| Operation | Method | Purpose |
| --- | --- | --- |
| Read | `config.enableCustomMacroSettings` | Initialize checkbox state |
| Read | `config.repeatTime` | Initialize repeatTimes text field |
| Read | `config.repeatDelay` | Initialize repeatDelay text field |
| Write | `ConfigManager.saveConfig(config)` | Persist changes to disk |
| Reload | `ConfigManager.reloadConfig()` | Refresh in-memory config |
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L15](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L15-L15)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L40](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L40-L40)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L56](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L56-L56)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L71](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L71-L71)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L120-L121](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L120-L121)
### Localization
All user-facing strings are externalized using the `Localizer` service:
| UI Element | Translation Key |
| --- | --- |
| Dialog title | `"macro_settings"` |
| Main title label | `"macro_settings"` |
| Enable checkbox label | `"macro_settings.enable_custom_macro_settings"` |
| Repeat times label | `"macro_settings.repeat_times"` |
| Repeat delay label | `"macro_settings.repeat_delay"` |
| Save button | `"macro_settings.save_settings"` |
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L20](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L20-L20)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L30](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L30-L30)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L38](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L38-L38)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L55](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L55-L55)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L70](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L70-L70)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L101](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L101-L101)
### Theming System
The dialog applies the current theme (dark/light mode) via `ComponentUtil.setMode()`:
```
ComponentUtil.setMode(getContentPane(),
config.enableDarkMode ? OtherConsts.DARK_MODE : OtherConsts.LIGHT_MODE);
```
The `IconConsts.CHECK_BOX` provides themed checkbox icons that adapt to the current color scheme.
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L142](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L142-L142)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L39](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L39-L39)
### Window Size Caching
The dialog's dimensions are persisted and restored via `ComponentUtil.adjustFrameWithCache()`, which calculates optimal window dimensions based on component content and applies cached sizes when available:
| Parameter | Value | Purpose |
| --- | --- | --- |
| Window Name | `"macro_settings"` | Set via `setName()`, used for cache lookup |
| Default Height | 170 px | Base height for calculation |
| Component Arrays | 4 arrays | Title, main panel, sub-panel, save button |
The method analyzes the localized text width of each component array to determine the optimal window width, then applies or caches the result.
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L21](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L21-L21)
[src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L143-L148](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L143-L148)
### Window Lifecycle
The dialog uses `WindowClosingAdapter` to handle window close events, which saves the window size to cache before disposal.
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L150](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L150-L150)
---
## Usage Context
The Macro Settings Dialog is opened from the `MainFrame` via a dedicated button. The settings configured here affect how the `MacroManager` executes playback:
* When `enableCustomMacroSettings` is `true` and `repeatTime > 1`, the macro will execute the recorded actions multiple times in sequence
* When `enableCustomMacroSettings` is `false`, the macro executes once (equivalent to `repeatTime = 1`)
For details on how these settings are consumed during macro playback, see [MacroManager](MacroManager).
**Sources**: [src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java L1-L138](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/ui/frame/MacroSettingsDialog.java#L1-L138)