# Component Utilities > **Relevant source files** > * [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java) ## Purpose and Scope The `ComponentUtil` class provides cross-cutting functionality for UI component manipulation, theme application, and window sizing management. This utility serves as the central mechanism for applying dark/light mode themes recursively across Swing component hierarchies and managing window dimensions with configurable sizing strategies. For information about the color schemes and constants used by this utility, see [Constants and Resources](Custom-UI-Components). For details on the dark/light mode system architecture, see [Theming and UI Styling](Custom-UI-Components). For window state persistence, see [CacheManager](CacheManager). **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L1-L196](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L1-L196) --- ## Class Structure and Dependencies The `ComponentUtil` class is a utility class containing only static methods. It has no instance state and serves as a functional module for component manipulation operations. ### Core Dependencies | Dependency | Purpose | Usage | | --- | --- | --- | | `ColorConsts` | Color scheme definitions | Provides 9-color palettes for dark/light modes | | `ConfigManager` | Configuration access | Reads `readjustFrameMode` setting for window sizing | | `CacheManager` | Runtime state access | Reads/writes window size cache via `windowSizeMap` | | `CustomScrollBarUI` | Custom UI component | Applied to `JScrollBar` components during theme application | | `OtherConsts` | Mode constants | Provides `DARK_MODE` and `LIGHT_MODE` constants | ``` ``` **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L1-L12](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L1-L12) [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L46-L151](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L46-L151) --- ## Theme Application System ### Theme Application Entry Point The public `setMode()` method serves as the entry point for applying themes to component hierarchies. It accepts a root `Component` and a mode integer constant (`OtherConsts.DARK_MODE` or `OtherConsts.LIGHT_MODE`). ``` ``` **Method Signature**: `public static void setMode(Component root, int mode)` **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L46-L66](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L46-L66) ### Color Scheme Structure Both dark and light mode color schemes contain exactly 9 colors, each serving a specific purpose in the component styling system: | Index | Variable Name (in recursive method) | Purpose | | --- | --- | --- | | 0 | `bg` | General background color | | 1 | `fg` | General foreground (text) color | | 2 | `pbg` | Panel background color | | 3 | `pfg` | Panel foreground color | | 4 | `bbg` | Button background color | | 5 | `bfg` | Button foreground color | | 6 | `lbg` | Label background color (unused in current implementation) | | 7 | `lfg` | Label foreground color (unused in current implementation) | | 8 | `caret` | Caret color for text input components | If a color scheme does not contain exactly 9 colors, the system prints an error message and falls back to dark mode. **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L50-L66](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L50-L66) [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L69](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L69-L69) ### Recursive Component Styling The private `setComponent()` method recursively traverses the component hierarchy, applying appropriate colors based on component type. The method handles the following Swing component types: ``` ``` **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L69-L151](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L69-L151) ### UIManager Integration For certain complex components (`JTextField` and `JComboBox`), the method directly manipulates the Swing `UIManager` to set Look and Feel properties, followed by calling `SwingUtilities.updateComponentTreeUI()` to refresh the component's appearance. #### JTextField Properties Set | Mode | Properties Updated | | --- | --- | | Dark Mode | `TextField.background`, `TextField.foreground`, `TextField.inactiveForeground`, `TextField.inactiveBackground` | | Light Mode | Same properties with light mode colors | #### JComboBox Properties Set | Mode | Properties Updated | | --- | --- | | Dark Mode | `ComboBox.disabledBackground`, `ComboBox.disabledForeground`, `ComboBox.background`, `ComboBox.foreground`, `ComboBox.selectionBackground`, `ComboBox.selectionForeground`, `ComboBox.buttonBackground`, `ComboBox.buttonShadow` | | Light Mode | Same properties with light mode colors | **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L90-L139](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L90-L139) ### Custom Scrollbar Styling When a `JScrollBar` is encountered, the method applies a `CustomScrollBarUI` instance constructed with the current mode. This provides custom-styled scrollbars that match the application theme. The UI is updated asynchronously using `SwingUtilities.invokeLater()` to ensure proper rendering. **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L142-L144](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L142-L144) --- ## Window Sizing and Layout Management ### Window Sizing Strategy The `ComponentUtil` class provides sophisticated window sizing logic that balances three competing concerns: 1. **Proper Size**: Calculated dimensions based on component preferred sizes 2. **Cached Size**: Previously stored window dimensions from user resizing 3. **Aspect Ratio**: A 3:2 aspect ratio constraint for aesthetic consistency ``` ``` **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L173-L195](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L173-L195) [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L16-L44](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L16-L44) ### Proper Size Calculation The `getProperSize()` method calculates the minimum required window dimensions by: 1. **Measuring Components**: Iterating through variable-length arrays of `JComponent` arrays, summing preferred widths and heights within each array 2. **Finding Maxima**: Taking the maximum width and height across all component arrays 3. **Adding Padding**: Adding fixed padding (80+20 pixels horizontal, hAdjust+20 pixels vertical) 4. **Fitting to Aspect Ratio**: Calling `fitSize()` to enforce the 3:2 aspect ratio The `hAdjust` parameter compensates for extra spacing elements like `Box` glue components that affect vertical spacing but don't report accurate preferred sizes. **Method Signature**: `private static int[] getProperSize(int hAdjust, JComponent[]... comps2)` **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L14-L33](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L14-L33) ### Aspect Ratio Enforcement The `fitSize()` method enforces a 3:2 (width:height) aspect ratio by: 1. Starting with the provided height and calculating `targetW = height * 3/2` 2. If calculated width is too small, using the provided width and calculating `targetH = width * 2/3` 3. Returning the adjusted dimensions as an `int[]` array This ensures all windows maintain consistent proportions regardless of content. **Method Signature**: `private static int[] fitSize(int width, int height)` **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L36-L44](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L36-L44) ### Cache Size Parsing The `parseWindowSize()` method parses cached size strings that can be in two formats: * **Comma-separated**: `"width,height"` (e.g., `"600,400"`) * **Asterisk-separated**: `"width*height"` (e.g., `"600*400"`) The method returns `null` if the string is malformed or cannot be parsed. **Method Signature**: `private static int[] parseWindowSize(String sizeStr)` **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L153-L171](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L153-L171) ### Readjust Frame Modes The `adjustFrameWithCache()` method supports three window sizing strategies controlled by `ConfigManager.config.readjustFrameMode`: | Mode | Constant | Behavior | | --- | --- | --- | | Mixed | `RFM_MIXED` | Takes maximum of proper size and cached size for both dimensions, then fits to aspect ratio | | Standardized | `RFM_STANDARDIZED` | Always uses calculated proper size, ignoring cache | | Memorized | `RFM_MEMORIZED` | Always uses cached size if available, ignoring calculations | The **Mixed** mode is particularly useful after language changes, as it allows windows to grow to accommodate longer translated strings while preserving user preferences when the new proper size is smaller than the cached size. **Method Signature**: `public static void adjustFrameWithCache(Window window, int hAdjust, JComponent[]... comps)` **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L173-L195](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L173-L195) --- ## Integration with Application Systems ### Integration with Configuration System `ComponentUtil` reads from `ConfigManager.config.readjustFrameMode` to determine window sizing behavior. This setting is user-configurable through the Settings dialog and persists across application sessions. **Configuration Path**: `ConfigManager.config.readjustFrameMode` → one of `RFM_MIXED`, `RFM_STANDARDIZED`, or `RFM_MEMORIZED` ### Integration with Cache System `ComponentUtil` reads from `CacheManager.cache.windowSizeMap`, which is a `Map` storing window dimensions keyed by window name. Window names are set via `Window.setName()` in dialog constructors. The cache is automatically updated by window listeners when users manually resize windows. `ComponentUtil` only reads from the cache; it does not write to it. **Cache Path**: `CacheManager.cache.windowSizeMap.get(window.getName())` → `"width,height"` or `"width*height"` ### Integration with Localization System When the application language changes, all windows need to be resized to accommodate the new text dimensions. The sequence is: 1. User changes language in Settings dialog 2. All text components update their content via `Localizer` 3. Components report new preferred sizes 4. Windows call `adjustFrameWithCache()` to recalculate and apply new dimensions 5. The `readjustFrameMode` setting determines how cached sizes and new proper sizes are reconciled This integration enables smooth language transitions without windows becoming too small for their content or discarding user size preferences unnecessarily. **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L173-L195](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L173-L195) --- ## Usage Patterns ### Typical Theme Application Pattern ``` // In dialog constructor or when theme changes ComponentUtil.setMode(this, currentMode); ``` Where `currentMode` is obtained from: * `ConfigManager.config.enableDarkMode` (if not following system settings) * `SystemUtil` detection (if following system settings) ### Typical Window Sizing Pattern ``` // In dialog constructor, after all components are added ComponentUtil.adjustFrameWithCache( this, // the Window 50, // hAdjust value for extra spacing new JComponent[]{comp1, comp2}, // first row components new JComponent[]{comp3, comp4} // second row components ); ``` The variable-length `JComponent[]...` parameter allows grouping components by logical rows or sections to calculate maximum dimensions accurately. **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L173-L195](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L173-L195) --- ## Technical Notes ### Component Type Detection The recursive styling method uses `instanceof` checks to determine component types. Components are styled in this order of precedence: 1. Container components (`JScrollPane`, `JPanel`) - recursively processed 2. Leaf components - directly styled based on type This ensures parent containers are styled before their children, and the recursion naturally handles arbitrarily nested component hierarchies. ### Focus Painting Disabled For `JButton` and `JRadioButton` components, focus painting is explicitly disabled via `setFocusPainted(false)`. This removes the dotted focus rectangle that appears around focused buttons, providing a cleaner visual appearance consistent with modern UI design. **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L87](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L87-L87) ### Asynchronous Scrollbar Updates Scrollbar UI updates are scheduled asynchronously using `SwingUtilities.invokeLater(comp::repaint)` to ensure proper rendering after the custom UI is applied. This avoids potential threading issues and ensures the scrollbar appears correctly. **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L144](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L144-L144) ### Comment Documentation The source file contains Chinese comments explaining implementation details: * Line 14: Explains the `hAdjust` parameter's purpose - compensating for `Box` spacers that aren't included in height calculations * Line 68: Notes that the method recursively sets styles **Sources**: [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L14](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L14-L14) [src/io/github/samera2022/mouse_macros/util/ComponentUtil.java L68](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/util/ComponentUtil.java#L68-L68)