Skip to content

refactor(ui): introduce semantic color system#26

Merged
karolak6612 merged 6 commits into
mainfrom
Themes-fix
May 31, 2026
Merged

refactor(ui): introduce semantic color system#26
karolak6612 merged 6 commits into
mainfrom
Themes-fix

Conversation

@karolak6612

@karolak6612 karolak6612 commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Implemented a unified SemanticColors namespace to standardize UI state indicators (modified, saved, danger, etc.) across the application. Replaced hardcoded ImVec4 color values throughout dialogs and panels with these semantic constants to ensure theme consistency.

  • ImguiMapEditor/Application.cpp — injected theme pointer into preferences
  • ImguiMapEditor/Presentation/MainWindow.cpp — updated tab coloring using semantic constants
  • ImguiMapEditor/UI/Core/Theme.h — defined SemanticColors namespace with standard state/text roles
  • ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientConfigurationDialog.cpp — replaced hardcoded colors with SemanticColors constants
  • ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientPropertyEditor.cpp — updated color constants to semantic mapping
  • ImguiMapEditor/UI/Dialogs/ConfirmationDialog.cpp — included theme header [minor]
  • ImguiMapEditor/UI/Dialogs/EditTownsDialog.cpp — replaced local color definitions with SemanticColors
  • ImguiMapEditor/UI/Dialogs/MapCompatibilityPopup.cpp — used semantic constants for warnings
  • ImguiMapEditor/UI/Dialogs/NewMapDialog.cpp — updated label/text coloring and button styles
  • ImguiMapEditor/UI/Dialogs/Properties/ItemPropertiesDialog.cpp — included theme header [minor]
  • ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp — applied semantic colors to panel headers and status
  • ImguiMapEditor/UI/Dialogs/Startup/ClientInfoPanel.cpp — updated client info status and label styling
  • ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp — applied semantic colors to list items and labels
  • ImguiMapEditor/UI/Dialogs/Startup/SelectedMapPanel.cpp — updated status and label styling
  • ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp — refactored startup dialog styling to be theme-aware
  • ImguiMapEditor/UI/Dialogs/UnsavedChangesModal.cpp — included theme header [minor]
  • ImguiMapEditor/UI/Panels/BrushSizePanel.cpp — used SemanticColors::SAVED for active toggle
  • ImguiMapEditor/UI/Panels/NewMapPanel.cpp — updated frame/border styling with semantic colors
  • ImguiMapEditor/UI/PreferencesDialog.cpp — added theme selection UI and semantic color usage
  • ImguiMapEditor/UI/PreferencesDialog.h — added theme pointer tracking
  • ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h — updated separator color to SemanticColors::MUTED
  • ImguiMapEditor/UI/Widgets/TilesetGridWidget.cpp — included theme header [minor]
  • ImguiMapEditor/UI/Windows/BrowseTile/BrowseTileWindow.cpp — used semantic constants for property colors
  • ImguiMapEditor/UI/Windows/BrowseTile/SpawnCreatureRenderer.cpp — included theme header [minor]
  • ImguiMapEditor/UI/Windows/IngameBoxWindow.cpp — replaced hardcoded colors with semantic indicators

Summary by CodeRabbit

  • New Features

    • Theme selection with live preview in Preferences; chosen theme is applied and persisted.
  • Style

    • Added a centralized semantic color system and helpers for consistent theming.
    • Replaced many hard-coded colors across dialogs, panels, widgets and windows with theme tokens, improving hover/active/disabled states, warnings/errors, and pulsing/modified visuals.

Implemented a unified `SemanticColors` namespace to standardize UI state indicators (modified, saved, danger, etc.) across the application. Replaced hardcoded `ImVec4` color values throughout dialogs and panels with these semantic constants to ensure theme consistency.
- `ImguiMapEditor/Application.cpp` — injected theme pointer into preferences
- `ImguiMapEditor/Presentation/MainWindow.cpp` — updated tab coloring using semantic constants
- `ImguiMapEditor/UI/Core/Theme.h` — defined `SemanticColors` namespace with standard state/text roles
- `ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientConfigurationDialog.cpp` — replaced hardcoded colors with `SemanticColors` constants
- `ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientPropertyEditor.cpp` — updated color constants to semantic mapping
- `ImguiMapEditor/UI/Dialogs/ConfirmationDialog.cpp` — included theme header [minor]
- `ImguiMapEditor/UI/Dialogs/EditTownsDialog.cpp` — replaced local color definitions with `SemanticColors`
- `ImguiMapEditor/UI/Dialogs/MapCompatibilityPopup.cpp` — used semantic constants for warnings
- `ImguiMapEditor/UI/Dialogs/NewMapDialog.cpp` — updated label/text coloring and button styles
- `ImguiMapEditor/UI/Dialogs/Properties/ItemPropertiesDialog.cpp` — included theme header [minor]
- `ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp` — applied semantic colors to panel headers and status
- `ImguiMapEditor/UI/Dialogs/Startup/ClientInfoPanel.cpp` — updated client info status and label styling
- `ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp` — applied semantic colors to list items and labels
- `ImguiMapEditor/UI/Dialogs/Startup/SelectedMapPanel.cpp` — updated status and label styling
- `ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp` — refactored startup dialog styling to be theme-aware
- `ImguiMapEditor/UI/Dialogs/UnsavedChangesModal.cpp` — included theme header [minor]
- `ImguiMapEditor/UI/Panels/BrushSizePanel.cpp` — used `SemanticColors::SAVED` for active toggle
- `ImguiMapEditor/UI/Panels/NewMapPanel.cpp` — updated frame/border styling with semantic colors
- `ImguiMapEditor/UI/PreferencesDialog.cpp` — added theme selection UI and semantic color usage
- `ImguiMapEditor/UI/PreferencesDialog.h` — added theme pointer tracking
- `ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h` — updated separator color to `SemanticColors::MUTED`
- `ImguiMapEditor/UI/Widgets/TilesetGridWidget.cpp` — included theme header [minor]
- `ImguiMapEditor/UI/Windows/BrowseTile/BrowseTileWindow.cpp` — used semantic constants for property colors
- `ImguiMapEditor/UI/Windows/BrowseTile/SpawnCreatureRenderer.cpp` — included theme header [minor]
- `ImguiMapEditor/UI/Windows/IngameBoxWindow.cpp` — replaced hardcoded colors with semantic indicators
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 535a1390-3b80-43f2-bea3-0cc1dba5f4b7

📥 Commits

Reviewing files that changed from the base of the PR and between 4accc1f and f82a139.

📒 Files selected for processing (8)
  • ImguiMapEditor/UI/Core/Theme.h
  • ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/ClientInfoPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/SelectedMapPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp
  • ImguiMapEditor/UI/PreferencesDialog.cpp
  • ImguiMapEditor/UI/Ribbon/Panels/ThemePanel.cpp

<review_stack_artifact>

</review_stack_artifact>

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.32% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(ui): introduce semantic color system' directly and accurately describes the main change: introducing a centralized semantic color system to replace hardcoded UI colors throughout the codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a unified semantic color system to the UI layer, replacing hardcoded color definitions with a centralized namespace. This change significantly improves maintainability and ensures visual consistency across the application's various dialogs, panels, and windows, while also laying the groundwork for more robust theme support.

Highlights

  • Introduction of Semantic Color System: Defined a centralized SemanticColors namespace in UI/Core/Theme.h to standardize UI state indicators such as MODIFIED, SAVED, DANGER, and WARNING.
  • Refactoring UI Components: Replaced hardcoded ImVec4 color values with semantic constants across multiple dialogs, panels, and windows to ensure visual consistency and maintainability.
  • Theme Integration: Updated Application.cpp and PreferencesDialog to support theme-aware UI, enabling dynamic color management across the application.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@sourcery-ai

sourcery-ai Bot commented May 27, 2026

Copy link
Copy Markdown

Reviewer's Guide

Introduces a centralized SemanticColors namespace and integrates it across dialogs, panels, and windows to replace hardcoded ImGui colors, while wiring theme selection through Preferences and removing dialog-specific dark styling in favor of the active theme.

File-Level Changes

Change Details Files
Introduce SemanticColors namespace to define semantic UI state and text role colors used across all themes.
  • Added SemanticColors namespace in Theme.h with state colors (MODIFIED, SAVED, DANGER, WARNING, INFO, GOLD) and text roles (LABEL, VALUE, EMPTY, HEADER_TEXT, MUTED), plus PULSE_BASE and DISABLED_ALPHA.
  • Documented SemanticColors intent as theme-independent semantic meanings.
  • Updated other headers to include Theme.h where semantic colors are referenced.
ImguiMapEditor/UI/Core/Theme.h
ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h
ImguiMapEditor/UI/Dialogs/ConfirmationDialog.cpp
ImguiMapEditor/UI/Dialogs/Properties/ItemPropertiesDialog.cpp
ImguiMapEditor/UI/Dialogs/UnsavedChangesModal.cpp
ImguiMapEditor/UI/Windows/BrowseTile/SpawnCreatureRenderer.cpp
ImguiMapEditor/UI/Widgets/TilesetGridWidget.cpp
ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp
ImguiMapEditor/UI/Dialogs/NewMapDialog.cpp
ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientConfigurationDialog.cpp
ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientPropertyEditor.cpp
ImguiMapEditor/UI/Dialogs/EditTownsDialog.cpp
ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/ClientInfoPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/SelectedMapPanel.cpp
ImguiMapEditor/UI/Panels/BrushSizePanel.cpp
ImguiMapEditor/UI/Windows/IngameBoxWindow.cpp
ImguiMapEditor/UI/Panels/NewMapPanel.cpp
ImguiMapEditor/UI/Windows/BrowseTile/BrowseTileWindow.cpp
Refactor dialogs and panels to use semantic colors instead of hardcoded ImVec4 values for stateful and informational UI elements.
  • Replaced direct ImVec4 color literals for labels, values, headers, warnings, errors, and info text with SemanticColors constants (e.g., LABEL, VALUE, HEADER_TEXT, WARNING, DANGER, SAVED, INFO, GOLD, EMPTY, MUTED).
  • Updated button styles in various dialogs (NewMapDialog, EditTownsDialog, MapCompatibilityPopup, StartupDialog, ClientConfigurationDialog) to use semantic state colors (INFO for primary, DANGER for destructive, WARNING for risky actions, SAVED for success).
  • Adjusted disabled states to use SemanticColors::DISABLED_ALPHA or ImGui default disabled color instead of manual alpha values.
  • Centralized tab and toggle status coloring (e.g., map editor tabs, BrushSizePanel active toggles, IngameBoxWindow toggles, browse tile property flags) on SemanticColors meanings.
  • Introduced local aliases namespace SC = SemanticColors; for concise usage in multiple source files.
ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp
ImguiMapEditor/UI/Dialogs/NewMapDialog.cpp
ImguiMapEditor/Presentation/MainWindow.cpp
ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientConfigurationDialog.cpp
ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientPropertyEditor.cpp
ImguiMapEditor/UI/Dialogs/EditTownsDialog.cpp
ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/ClientInfoPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/SelectedMapPanel.cpp
ImguiMapEditor/UI/Panels/BrushSizePanel.cpp
ImguiMapEditor/UI/Windows/IngameBoxWindow.cpp
ImguiMapEditor/UI/Panels/NewMapPanel.cpp
ImguiMapEditor/UI/Windows/BrowseTile/BrowseTileWindow.cpp
ImguiMapEditor/UI/Dialogs/MapCompatibilityPopup.cpp
Make startup dialog and related panels theme-aware instead of enforcing a custom dark background overlay.
  • Removed custom window and child background color pushes in StartupDialog and rely on ImGui style/theme for window backgrounds.
  • Switched header child background to ImGuiCol_Header from the current theme instead of fixed dark gray.
  • Normalized sidebar and footer button colors to either semantic INFO for primary actions or theme defaults for secondary actions.
  • Used SemanticColors::MUTED for version text and other secondary labels, and SemanticColors::DISABLED_ALPHA for disabled Load Map button alpha.
  • Ensured status toggles such as "Ignore signatures" reuse INFO and default button colors for active/inactive states.
ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp
ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/ClientInfoPanel.cpp
ImguiMapEditor/UI/Dialogs/Startup/SelectedMapPanel.cpp
Expose theme selection in Preferences and wire the selected ThemeType into app settings.
  • Extended PreferencesDialog to hold a ThemeType* pointer and setter, plus use Theme.h in the header.
  • In Application::initialize, passed the app settings theme pointer into PreferencesDialog via setThemePtr and ensured settings are saved via the existing apply callback.
  • Implemented a new Theme section in PreferencesDialog::renderEditorTab with a collapsing header, combo box listing AVAILABLE_THEMES, icons per theme type, preview colors, tooltips, and description text for the selected theme.
  • Hooked theme selection to ApplyTheme(theme.type) and updated the stored ThemeType via the theme pointer, then invoked on_apply_settings_ callback to persist changes.
ImguiMapEditor/UI/PreferencesDialog.h
ImguiMapEditor/UI/PreferencesDialog.cpp
ImguiMapEditor/Application.cpp
Align ribbon and various utility UI elements with the semantic color system for consistent separators and previews.
  • Updated RibbonUtils::RenderSeparator to use SemanticColors::MUTED instead of a literal semi-transparent gray.
  • Ensured miscellaneous UI utilities and dialogs include Theme.h where semantic colors might be used, preparing them for further adoption.
  • Left behavior of non-color logic untouched, focusing changes solely on visual consistency.
ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h
ImguiMapEditor/UI/Widgets/TilesetGridWidget.cpp
ImguiMapEditor/UI/Dialogs/ConfirmationDialog.cpp
ImguiMapEditor/UI/Dialogs/Properties/ItemPropertiesDialog.cpp
ImguiMapEditor/UI/Dialogs/UnsavedChangesModal.cpp
ImguiMapEditor/UI/Windows/BrowseTile/SpawnCreatureRenderer.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions github-actions Bot added Type: Enhancement New feature or request. Area: UI Changes to the wxWidgets GUI (palettes, dialogs, menus, toolbar). labels May 27, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In PreferencesDialog::renderEditorTab, std::ranges::find_if is dereferenced unconditionally when theme_ptr_ is set; consider handling the case where the theme type is not found in AVAILABLE_THEMES to avoid undefined behavior if the list and saved value ever get out of sync.
  • In AvailableClientsPanel and RecentMapsPanel, the kSelectedHeader* and kUnselectedHeader* colors are still hardcoded dark-theme RGBA values; it would be more robust to derive these from the active theme (or add corresponding semantic roles) so they adapt correctly when new themes are added.
  • Several buttons (e.g., primary actions in StartupDialog, NewMapDialog, and the compatibility popup) use SC::INFO for all of normal/hover/active states, which removes visual hover/press feedback; consider deriving slightly varied hover/active colors from the semantic base color to preserve interaction affordance.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `PreferencesDialog::renderEditorTab`, `std::ranges::find_if` is dereferenced unconditionally when `theme_ptr_` is set; consider handling the case where the theme type is not found in `AVAILABLE_THEMES` to avoid undefined behavior if the list and saved value ever get out of sync.
- In `AvailableClientsPanel` and `RecentMapsPanel`, the `kSelectedHeader*` and `kUnselectedHeader*` colors are still hardcoded dark-theme RGBA values; it would be more robust to derive these from the active theme (or add corresponding semantic roles) so they adapt correctly when new themes are added.
- Several buttons (e.g., primary actions in `StartupDialog`, `NewMapDialog`, and the compatibility popup) use `SC::INFO` for all of normal/hover/active states, which removes visual hover/press feedback; consider deriving slightly varied hover/active colors from the semantic base color to preserve interaction affordance.

## Individual Comments

### Comment 1
<location path="ImguiMapEditor/UI/PreferencesDialog.cpp" line_range="180-181" />
<code_context>
+
+    if (theme_ptr_) {
+      ImGui::SameLine();
+      const auto& current_theme = *std::ranges::find_if(
+          AVAILABLE_THEMES, [this](const ThemeInfo& ti) { return ti.type == *theme_ptr_; });
+      ImGui::TextUnformatted(current_theme.description);
+    }
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against std::ranges::find_if returning end() before dereferencing current_theme.

If *theme_ptr_ holds a theme that isn’t in AVAILABLE_THEMES (e.g., after theme list changes or from older/corrupt config), std::ranges::find_if will return end(), and dereferencing it is UB. Please either handle the end() case (e.g., fallback/default description) or assert that a match must exist before dereferencing, so the code remains safe when AVAILABLE_THEMES or saved settings change.
</issue_to_address>

### Comment 2
<location path="ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp" line_range="248-251" />
<code_context>
-                        ImVec4(0.25f, 0.55f, 0.80f, 1.0f));
-  ImGui::PushStyleColor(ImGuiCol_ButtonActive,
-                        ImVec4(0.15f, 0.40f, 0.65f, 1.0f));
+  // New Map button (primary action)
+  ImGui::PushStyleColor(ImGuiCol_Button, SC::INFO);
+  ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::INFO);
+  ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::INFO);
   if (ImGui::Button(ICON_FA_FILE " New map", kUniformButtonSize)) {
     pending_result_.action = Action::NewMap;
</code_context>
<issue_to_address>
**suggestion:** Primary buttons use the same color for normal, hovered, and active states, reducing visual feedback.

For primary actions like New Map and Load Map, ImGuiCol_Button, ImGuiCol_ButtonHovered, and ImGuiCol_ButtonActive are all SC::INFO, which removes hover/pressed feedback and can hurt usability/accessibility. Please derive slightly lighter/darker variants from SC::INFO (or introduce INFO_HOVER/INFO_ACTIVE semantic colors) so button states remain visually distinct while staying on-theme.

Suggested implementation:

```cpp
  // New Map button (primary action)
  ImGui::PushStyleColor(ImGuiCol_Button, SC::INFO);
  ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::INFO_HOVER);
  ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::INFO_ACTIVE);

```

To fully implement this suggestion you should also:
1. Define `SC::INFO_HOVER` and `SC::INFO_ACTIVE` in your shared style/colors module (where `SC::INFO` is currently defined), making them slightly lighter/darker variants of `SC::INFO` for good hover/pressed contrast.
2. Ensure any other primary buttons (e.g. "Load Map") also use `SC::INFO`, `SC::INFO_HOVER`, and `SC::INFO_ACTIVE` consistently for normal/hover/active states.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread ImguiMapEditor/UI/PreferencesDialog.cpp Outdated
Comment thread ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary

The PR successfully introduces a semantic color system, which is a great step towards a more maintainable and themeable UI. It replaces many hardcoded colors with meaningful constants.

🔍 General Feedback

  • Correctness: Identified an unsafe dereference in PreferencesDialog.cpp when looking up theme descriptions.
  • Maintainability: The Theme.h header is becoming quite large due to inline implementations of theme functions. Consider splitting these into a .cpp file.
  • Portability: Added a note about missing <cmath> include for sinf in MainWindow.cpp.
  • Cleanliness: Noted an unnecessary inclusion of imgui_internal.h in Theme.h and some minor formatting/comment issues.

Overall, the architectural direction is excellent.

@@ -96,20 +99,20 @@ void MainWindow::renderEditor(Domain::ChunkedMap *current_map,
if (is_active) {
// Pulsate between Green and Yellow for Active + Modified
float t = (sinf((float)ImGui::GetTime() * 5.0f) * 0.5f) + 0.5f;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 This file uses sinf, but <cmath> is not explicitly included. While it might be included transitively, it's better to include it for portability and clarity.

Comment thread ImguiMapEditor/UI/PreferencesDialog.cpp Outdated

if (theme_ptr_) {
ImGui::SameLine();
const auto& current_theme = *std::ranges::find_if(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Unsafe dereference of std::ranges::find_if result. If *theme_ptr_ happens to be an invalid value (not in AVAILABLE_THEMES), this will result in undefined behavior.

Suggested change
const auto& current_theme = *std::ranges::find_if(
if (theme_ptr_) {
ImGui::SameLine();
auto it = std::ranges::find_if(
AVAILABLE_THEMES, [this](const ThemeInfo& ti) { return ti.type == *theme_ptr_; });
if (it != std::end(AVAILABLE_THEMES)) {
ImGui::TextUnformatted(it->description);
}
}

Comment thread ImguiMapEditor/UI/Core/Theme.h Outdated

// ============================================================================
// Semantic Colors — universal across all themes
// These represent UI state meaning, visible regardless of background.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Great job standardizing the UI colors with a semantic system! This will significantly improve maintainability and make theme switching much more reliable.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request centralizes UI styling by introducing a universal SemanticColors namespace in Theme.h and refactoring various dialogs, panels, and windows to use these semantic constants instead of hardcoded ImVec4 values. It also adds theme selection support to the preferences dialog. The review feedback highlights a critical safety issue in PreferencesDialog.cpp where a search iterator is dereferenced without checking for std::end. Additionally, the reviewer notes that using identical semantic colors for normal, hovered, and active button states eliminates interactive visual feedback, suggesting the addition of Lighten and Darken helper utilities to SemanticColors to dynamically adjust brightness. Other minor improvements include removing redundant style pushes in StartupDialog.cpp and preserving alpha transparency for the ribbon separator.

Comment on lines +178 to +183
if (theme_ptr_) {
ImGui::SameLine();
const auto& current_theme = *std::ranges::find_if(
AVAILABLE_THEMES, [this](const ThemeInfo& ti) { return ti.type == *theme_ptr_; });
ImGui::TextUnformatted(current_theme.description);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Dereferencing the iterator returned by std::ranges::find_if without checking if it equals std::end(AVAILABLE_THEMES) can lead to undefined behavior or a crash if the theme is not found. Safely check the iterator before dereferencing.

    if (theme_ptr_) {
      ImGui::SameLine();
      const auto it = std::ranges::find_if(
          AVAILABLE_THEMES, [this](const ThemeInfo& ti) { return ti.type == *theme_ptr_; });
      if (it != std::end(AVAILABLE_THEMES)) {
        ImGui::TextUnformatted(it->description);
      }
    }

Comment on lines +386 to +388
ImGui::PushStyleColor(ImGuiCol_Button, SC::SAVED);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::SAVED);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::SAVED);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the exact same color for Button, ButtonHovered, and ButtonActive removes all visual feedback when the user hovers over or clicks the button. Use the Lighten and Darken helper functions to restore interactive feedback.

            ImGui::PushStyleColor(ImGuiCol_Button, SC::SAVED);
            ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::Lighten(SC::SAVED));
            ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::Darken(SC::SAVED));

Comment on lines +40 to +46
constexpr ImVec4 kRed = SemanticColors::DANGER;
constexpr ImVec4 kYellow = SemanticColors::PULSE_BASE;
constexpr ImVec4 kGreen = SemanticColors::SAVED;
constexpr ImVec4 kTextMuted = SemanticColors::MUTED;
constexpr ImVec4 kGreenStatus = SemanticColors::SAVED;
constexpr ImVec4 kBlueAccent = SemanticColors::INFO;
constexpr ImVec4 kBlueHover = SemanticColors::INFO;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Defining the normal and hovered button colors as the exact same semantic color removes visual feedback when the user hovers over the buttons. Use the Lighten helper function to restore interactive feedback.

constexpr ImVec4 kRed       = SemanticColors::DANGER;
constexpr ImVec4 kYellow    = SemanticColors::PULSE_BASE;
constexpr ImVec4 kGreen     = SemanticColors::SAVED;
constexpr ImVec4 kTextMuted = SemanticColors::MUTED;
constexpr ImVec4 kGreenStatus = SemanticColors::SAVED;
constexpr ImVec4 kBlueAccent  = SemanticColors::INFO;
constexpr ImVec4 kBlueHover   = SemanticColors::Lighten(SemanticColors::INFO);

Comment on lines +160 to +162
ImGui::PushStyleColor(ImGuiCol_Button, SC::DANGER);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::DANGER);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::DANGER);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the exact same color for Button, ButtonHovered, and ButtonActive removes all visual feedback when the user hovers over or clicks the button. Use the Lighten and Darken helper functions to restore interactive feedback.

                ImGui::PushStyleColor(ImGuiCol_Button, SC::DANGER);
                ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::Lighten(SC::DANGER));
                ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::Darken(SC::DANGER));

Comment on lines +332 to +334
ImGui::PushStyleColor(ImGuiCol_Button, SC::DANGER);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::DANGER);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::DANGER);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the exact same color for Button, ButtonHovered, and ButtonActive removes all visual feedback when the user hovers over or clicks the button. Use the Lighten and Darken helper functions to restore interactive feedback.

        ImGui::PushStyleColor(ImGuiCol_Button, SC::DANGER);
        ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::Lighten(SC::DANGER));
        ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::Darken(SC::DANGER));

Comment on lines +249 to +251
ImGui::PushStyleColor(ImGuiCol_Button, SC::INFO);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::INFO);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::INFO);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the exact same color for Button, ButtonHovered, and ButtonActive removes all visual feedback when the user hovers over or clicks the button. Use the Lighten and Darken helper functions to restore interactive feedback.

  ImGui::PushStyleColor(ImGuiCol_Button, SC::INFO);
  ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::Lighten(SC::INFO));
  ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::Darken(SC::INFO));

Comment on lines +375 to +377
ImGui::PushStyleColor(ImGuiCol_Button, SC::INFO);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::INFO);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::INFO);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the exact same color for Button, ButtonHovered, and ButtonActive removes all visual feedback when the user hovers over or clicks the button. Use the Lighten and Darken helper functions to restore interactive feedback.

  ImGui::PushStyleColor(ImGuiCol_Button, SC::INFO);
  ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::Lighten(SC::INFO));
  ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::Darken(SC::INFO));

Comment on lines +30 to +37
constexpr ImVec4 kBlueAccent = SemanticColors::INFO;
constexpr ImVec4 kBlueHover = SemanticColors::INFO;
constexpr ImVec4 kBlueActive = SemanticColors::INFO;
constexpr ImVec4 kRedDelete = SemanticColors::DANGER;
constexpr ImVec4 kRedHover = SemanticColors::DANGER;
constexpr ImVec4 kGreenStatus = SemanticColors::SAVED;
constexpr ImVec4 kTextOffWhite = SemanticColors::HEADER_TEXT;
constexpr ImVec4 kTextMuted = SemanticColors::MUTED;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Defining the normal, hovered, and active button colors as the exact same semantic color removes all visual feedback when the user interacts with the buttons. Use the Lighten and Darken helper functions to restore interactive feedback.

constexpr ImVec4 kBlueAccent   = SemanticColors::INFO;
constexpr ImVec4 kBlueHover    = SemanticColors::Lighten(SemanticColors::INFO);
constexpr ImVec4 kBlueActive   = SemanticColors::Darken(SemanticColors::INFO);
constexpr ImVec4 kRedDelete    = SemanticColors::DANGER;
constexpr ImVec4 kRedHover     = SemanticColors::Lighten(SemanticColors::DANGER);
constexpr ImVec4 kGreenStatus  = SemanticColors::SAVED;
constexpr ImVec4 kTextOffWhite = SemanticColors::HEADER_TEXT;
constexpr ImVec4 kTextMuted    = SemanticColors::MUTED;

Comment on lines 333 to 338
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4(ImGuiCol_Button));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered));
if (ImGui::Button(ICON_FA_POWER_OFF " Exit", kUniformButtonSize)) {
pending_result_.action = Action::Exit;
}
ImGui::PopStyleColor(2);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

Pushing the default style colors (ImGui::GetStyleColorVec4) onto the ImGui stack is completely redundant because ImGui will naturally use these colors if no style colors are pushed. Removing these redundant pushes simplifies the code and avoids unnecessary style stack operations.

  if (ImGui::Button(ICON_FA_POWER_OFF " Exit", kUniformButtonSize)) {
    pending_result_.action = Action::Exit;
  }

*/
inline void RenderSeparator() {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5f, 0.5f, 0.5f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_Text, SemanticColors::MUTED);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low

The original separator had an alpha of 0.5f to keep it visually subtle. Changing it to SemanticColors::MUTED directly makes it fully opaque (1.0f alpha), which may look too prominent. Consider preserving the 0.5f alpha while using the semantic color components.

Suggested change
ImGui::PushStyleColor(ImGuiCol_Text, SemanticColors::MUTED);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(SemanticColors::MUTED.x, SemanticColors::MUTED.y, SemanticColors::MUTED.z, 0.5f));

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp`:
- Around line 12-16: The four hardcoded ImVec4 constants (kSelectedHeader,
kSelectedHeaderHover, kUnselectedHeader, kUnselectedHeaderHover) should be
replaced with theme-derived values so headers follow the active semantic/theme
colors (also apply the same change where these are repeated around the 46–50
region); locate the constant definitions and replace the literal initializers
with calls to your theme/color API (for example retrieve ImVec4 via
ImGui::GetStyleColorVec4 or your project's Theme::GetColor/semantic lookup using
the appropriate semantic keys like Header/HeaderHovered/HeaderActive) so the
panel adapts to light/dark themes rather than using fixed dark-biased RGBA
literals.

In `@ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp`:
- Around line 11-15: The constants kSelectedHeader, kSelectedHeaderHover,
kUnselectedHeader and kUnselectedHeaderHover hardcode dark-theme colors; replace
them with colors sampled from the current ImGui style (e.g., derive from
ImGuiCol_Header / ImGuiCol_HeaderHovered / ImGuiCol_HeaderActive via
ImGui::GetStyleColorVec4 or style.Colors[]) so the panel respects
light/dark/custom themes, and compute any selection/hover variants at runtime
(optionally using ImLerp to blend). Update both the declarations
(kSelectedHeader etc.) and the other set used around lines 38–43 to use the
runtime-derived colors instead of fixed constexpr values.

In `@ImguiMapEditor/UI/PreferencesDialog.cpp`:
- Around line 178-183: The code in PreferencesDialog.cpp dereferences the result
of std::ranges::find_if when resolving AVAILABLE_THEMES into current_theme,
which can be undefined if the theme value isn't found; change the logic in the
block that checks theme_ptr_ to first store the iterator/result (auto it =
std::ranges::find_if(AVAILABLE_THEMES, ...)), test it against
std::end(AVAILABLE_THEMES) (or use it != AVAILABLE_THEMES.end()), and only
access it->description when found—otherwise handle the missing-theme case (e.g.,
skip ImGui::TextUnformatted, show a fallback string, or log an error). Ensure
you still respect the existing theme_ptr_ null check and update references to
current_theme accordingly.

In `@ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h`:
- Around line 3-4: The header is missing the <format> include used by
std::format in this file; open ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h and
add `#include` <format> near the other standard includes so the uses of
std::format (the calls to std::format found in this header) compile regardless
of include order.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 148e5c8c-a2a1-438f-8d4b-506454e67aa6

📥 Commits

Reviewing files that changed from the base of the PR and between b0f0c2a and 7d94a34.

📒 Files selected for processing (25)
  • ImguiMapEditor/Application.cpp
  • ImguiMapEditor/Presentation/MainWindow.cpp
  • ImguiMapEditor/UI/Core/Theme.h
  • ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientConfigurationDialog.cpp
  • ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientPropertyEditor.cpp
  • ImguiMapEditor/UI/Dialogs/ConfirmationDialog.cpp
  • ImguiMapEditor/UI/Dialogs/EditTownsDialog.cpp
  • ImguiMapEditor/UI/Dialogs/MapCompatibilityPopup.cpp
  • ImguiMapEditor/UI/Dialogs/NewMapDialog.cpp
  • ImguiMapEditor/UI/Dialogs/Properties/ItemPropertiesDialog.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/ClientInfoPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/SelectedMapPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp
  • ImguiMapEditor/UI/Dialogs/UnsavedChangesModal.cpp
  • ImguiMapEditor/UI/Panels/BrushSizePanel.cpp
  • ImguiMapEditor/UI/Panels/NewMapPanel.cpp
  • ImguiMapEditor/UI/PreferencesDialog.cpp
  • ImguiMapEditor/UI/PreferencesDialog.h
  • ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h
  • ImguiMapEditor/UI/Widgets/TilesetGridWidget.cpp
  • ImguiMapEditor/UI/Windows/BrowseTile/BrowseTileWindow.cpp
  • ImguiMapEditor/UI/Windows/BrowseTile/SpawnCreatureRenderer.cpp
  • ImguiMapEditor/UI/Windows/IngameBoxWindow.cpp

Comment thread ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp Outdated
Comment thread ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp Outdated
Comment thread ImguiMapEditor/UI/PreferencesDialog.cpp
Comment thread ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h
…states

Added Lighten/Darken helper functions to SemanticColors for consistent hover/active button states and replaced manual color overrides with dynamic variants across UI dialogs. Removed redundant local color definitions in favor of system-wide constants and added safety checks for theme resolution.
- `ImguiMapEditor/Presentation/MainWindow.cpp` — added `<cmath>` include
- `ImguiMapEditor/UI/Core/Theme.h` — introduced `Lighten` and `Darken` `constexpr` helpers
- `ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientConfigurationDialog.cpp` — switched to dynamic `Lighten`/`Darken` variants for button accents
- `ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientPropertyEditor.cpp` — used `Lighten` helper for button hover state
- `ImguiMapEditor/UI/Dialogs/EditTownsDialog.cpp` — updated button hover/active states to use semantic variants
- `ImguiMapEditor/UI/Dialogs/MapCompatibilityPopup.cpp` — updated warning button states to use semantic variants
- `ImguiMapEditor/UI/Dialogs/NewMapDialog.cpp` — updated create map button hover state to use `Lighten` variant
- `ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp` — switched header colors to use system-defined active/hover styles, removed local constants
- `ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp` — switched header colors to use system-defined active/hover styles, removed local constants
- `ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp` — simplified button style management and updated sidebar/footer button states to use semantic variants
- `ImguiMapEditor/UI/PreferencesDialog.cpp` — added bounds check for theme search in `renderEditorTab`
- `ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h` — added `<format>` include, updated separator color to use explicit alpha transparency

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary

The PR successfully introduces a semantic color system and refactors several UI components to use it. This improves maintainability and theme consistency.

🔍 General Feedback

  • Standardizing UI states (MODIFIED, SAVED, DANGER, etc.) is a great architectural improvement.
  • Found a few duplicate namespace aliases and opportunities for better clamping in helper functions.
  • Ensure that removing fallback button styles doesn't lead to regressions in different themes.

Great work on this refactoring!

Comment on lines +335 to 344
// Ignore signatures toggle button
if (ignore_signatures_) {
// Active state - more prominent color
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.35f, 0.50f, 0.65f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
ImVec4(0.40f, 0.55f, 0.70f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(0.30f, 0.45f, 0.60f, 1.0f));
} else {
// Inactive state - standard gray
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.25f, 0.28f, 0.32f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
ImVec4(0.35f, 0.38f, 0.42f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(0.20f, 0.22f, 0.26f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_Button, SC::INFO);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::Lighten(SC::INFO));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::Darken(SC::INFO));
}

const char *sig_label = ignore_signatures_ ? ICON_FA_CHECK " Ignore Sigs"
: ICON_FA_XMARK " Ignore Sigs";
if (ImGui::Button(sig_label, kUniformButtonSize)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The "inactive" state button styling (previously standard gray) has been removed here. If this is intentional to rely on the theme's default button color, it's fine, but ensure it doesn't look out of place when the theme itself is dark.

Comment on lines +38 to +43
constexpr ImVec4 Lighten(const ImVec4& c, float amount = 0.12f) {
return ImVec4(c.x + amount, c.y + amount, c.z + amount, c.w);
}
constexpr ImVec4 Darken(const ImVec4& c, float amount = 0.12f) {
return ImVec4(c.x - amount, c.y - amount, c.z - amount, c.w);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 These helpers should ideally clamp the resulting color components to the [0.0, 1.0] range to avoid potential issues with ImGui color processing or extreme values if the amount is high.

Suggested change
constexpr ImVec4 Lighten(const ImVec4& c, float amount = 0.12f) {
return ImVec4(c.x + amount, c.y + amount, c.z + amount, c.w);
}
constexpr ImVec4 Darken(const ImVec4& c, float amount = 0.12f) {
return ImVec4(c.x - amount, c.y - amount, c.z - amount, c.w);
}
constexpr ImVec4 Lighten(const ImVec4& c, float amount = 0.12f) {
return ImVec4(std::clamp(c.x + amount, 0.0f, 1.0f),
std::clamp(c.y + amount, 0.0f, 1.0f),
std::clamp(c.z + amount, 0.0f, 1.0f), c.w);
}
constexpr ImVec4 Darken(const ImVec4& c, float amount = 0.12f) {
return ImVec4(std::clamp(c.x - amount, 0.0f, 1.0f),
std::clamp(c.y - amount, 0.0f, 1.0f),
std::clamp(c.z - amount, 0.0f, 1.0f), c.w);
}

namespace UI {

namespace SC = SemanticColors;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 This local color constant could be replaced with a derivative of SemanticColors::MODIFIED to maintain the unified semantic system introduced in this PR.

Comment on lines +9 to +11
namespace SC = SemanticColors;

namespace SC = SemanticColors;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Duplicate namespace alias.

Suggested change
namespace SC = SemanticColors;
namespace SC = SemanticColors;
namespace SC = SemanticColors;

Comment on lines 9 to +11

namespace SC = SemanticColors;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Duplicate namespace alias.

Suggested change
namespace SC = SemanticColors;
namespace SC = SemanticColors;

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp (1)

11-11: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Remove duplicate SC namespace alias declaration.

namespace SC = SemanticColors; is already declared at Line 9; redeclaring it at Line 11 causes a redefinition compile error.

Proposed fix
-namespace SC = SemanticColors;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp` at line 11, Remove the
duplicate namespace alias declaration for SC in RecentMapsPanel.cpp: locate the
second occurrence of "namespace SC = SemanticColors;" (duplicate of the earlier
declaration) and delete it so SC is only aliased once; ensure no other code
relies on multiple aliases and that the single alias remains at the original
declaration site.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ImguiMapEditor/UI/Core/Theme.h`:
- Around line 38-43: The Lighten and Darken functions can produce out-of-range
RGB values; update ImGuiMapEditor::Theme::Lighten and ::Darken to clamp each RGB
channel to the [0.0f, 1.0f] range (preserve c.w) before constructing the
returned ImVec4, e.g., use constexpr std::clamp for c.x/c.y/c.z with amount
added/subtracted; ensure the clamp header is available.

---

Duplicate comments:
In `@ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp`:
- Line 11: Remove the duplicate namespace alias declaration for SC in
RecentMapsPanel.cpp: locate the second occurrence of "namespace SC =
SemanticColors;" (duplicate of the earlier declaration) and delete it so SC is
only aliased once; ensure no other code relies on multiple aliases and that the
single alias remains at the original declaration site.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 27244df8-2930-4ad2-8452-ea6aa6aceccf

📥 Commits

Reviewing files that changed from the base of the PR and between 7d94a34 and 0e2a3ef.

📒 Files selected for processing (12)
  • ImguiMapEditor/Presentation/MainWindow.cpp
  • ImguiMapEditor/UI/Core/Theme.h
  • ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientConfigurationDialog.cpp
  • ImguiMapEditor/UI/Dialogs/ClientConfiguration/ClientPropertyEditor.cpp
  • ImguiMapEditor/UI/Dialogs/EditTownsDialog.cpp
  • ImguiMapEditor/UI/Dialogs/MapCompatibilityPopup.cpp
  • ImguiMapEditor/UI/Dialogs/NewMapDialog.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp
  • ImguiMapEditor/UI/PreferencesDialog.cpp
  • ImguiMapEditor/UI/Ribbon/Utils/RibbonUtils.h

Comment thread ImguiMapEditor/UI/Core/Theme.h
Added `std::clamp` to theme light/dark helpers to prevent color values from exceeding the valid [0.0, 1.0] range and removed duplicate namespace aliases.
- `ImguiMapEditor/UI/Core/Theme.h` — clamped RGB components in `Lighten` and `Darken` helpers to 0.0-1.0 range
- `ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp` — removed duplicate `namespace SC` alias
- `ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp` — [minor] added duplicate `namespace SC` alias

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary

The PR successfully introduces a centralized SemanticColors system and updates most UI components to use it, which significantly improves maintainability and theme consistency. However, a critical ImGui style stack imbalance was introduced in StartupDialog.cpp which could lead to crashes or rendering glitches. There are also some minor code duplications (namespace aliases).

🔍 General Feedback

Great work on standardizing the colors. Moving away from hardcoded ImVec4 values makes the application much easier to theme. Please address the ImGui stack imbalance in the startup dialog as it's a regression. Also, consider cleaning up the redundant namespace aliases in RecentMapsPanel.cpp.

namespace SC = SemanticColors;

namespace SC = SemanticColors;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Redundant Namespace Aliases: There are multiple redundant declarations of namespace SC = SemanticColors;. One is sufficient.

: ICON_FA_XMARK " Ignore Sigs";
if (ImGui::Button(sig_label, kUniformButtonSize)) {
ignore_signatures_ = !ignore_signatures_;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 ImGui Stack Imbalance: This logic will cause a style color stack underflow or overflow. If ignore_signatures_ changes state during the ImGui::Button call, the PopStyleColor will either be skipped (when it should have happened) or called (when it shouldn't have).

Suggested change
}
const bool pushed_color = ignore_signatures_;
if (pushed_color) {
ImGui::PushStyleColor(ImGuiCol_Button, SC::INFO);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, SC::Lighten(SC::INFO));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, SC::Darken(SC::INFO));
}
const char *sig_label = ignore_signatures_ ? ICON_FA_CHECK " Ignore Sigs"
: ICON_FA_XMARK " Ignore Sigs";
if (ImGui::Button(sig_label, kUniformButtonSize)) {
ignore_signatures_ = !ignore_signatures_;
}
if (pushed_color) {
ImGui::PopStyleColor(3);
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp (1)

9-13: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove duplicate namespace alias declarations.

The namespace alias namespace SC = SemanticColors; is declared three times. Keep only one declaration.

🔧 Proposed fix
 namespace SC = SemanticColors;
-
-namespace SC = SemanticColors;
-
-namespace SC = SemanticColors;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp` around lines 9 - 13,
Remove the duplicate namespace alias declarations: keep a single declaration of
"namespace SC = SemanticColors;" and delete the other repeated lines so only one
namespace alias remains in RecentMapsPanel.cpp (i.e., remove the extra
occurrences of the symbol "namespace SC = SemanticColors;").
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp`:
- Around line 9-13: Remove the duplicate namespace alias declarations: keep a
single declaration of "namespace SC = SemanticColors;" and delete the other
repeated lines so only one namespace alias remains in RecentMapsPanel.cpp (i.e.,
remove the extra occurrences of the symbol "namespace SC = SemanticColors;").

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f12445d8-33ba-4344-b5a0-40b71cae8f53

📥 Commits

Reviewing files that changed from the base of the PR and between 0e2a3ef and 955d42e.

📒 Files selected for processing (3)
  • ImguiMapEditor/UI/Core/Theme.h
  • ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp
  • ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp
💤 Files with no reviewable changes (1)
  • ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp

Removed redundant namespace aliases in the recent maps panel and refactored the ignore signatures toggle to use a stable boolean state for style application, ensuring consistent color popping.
- `ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp` — removed redundant `namespace SC` aliases [minor]
- `ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp` — cached `ignore_signatures_` state in `pushed_color` to guarantee matching push and pop calls for button styles

@codacy-production codacy-production Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

The refactor successfully introduces a centralized semantic color system and theme management. Static analysis indicates the implementation adheres to quality standards, with no new issues or complexity increases detected.

However, the scope of the changes—spanning more than 20 files—presents a high risk for visual regressions or inconsistent styling. The primary concern is the absence of automated test coverage for critical user-facing features: theme persistence across sessions and the real-time update of UI components during theme selection. Verification of the theme pointer injection into application preferences is recommended to ensure stability.

About this PR

  • Critical paths for theme selection persistence and live UI updates are currently missing automated verification. This logic should be covered by unit or integration tests to prevent future regressions in preference handling.
  • The refactor affects a significant number of files. Ensure that visual consistency has been manually verified across all updated dialogs and panels, as the current test suite does not appear to cover the new semantic mappings.

Test suggestions

  • Verify that selecting a new theme in the Preferences dialog updates the UI colors in real-time (live preview).
  • Verify that the selected theme is correctly saved and restored upon application restart.
  • Confirm that the SemanticColors namespace correctly maps semantic roles to the expected color values for each theme.
  • Verify that specific UI elements, such as the ribbon separator and MainWindow tabs, use the correct semantic constants (e.g., MUTED, SAVED).
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Verify that selecting a new theme in the Preferences dialog updates the UI colors in real-time (live preview).
2. Verify that the selected theme is correctly saved and restored upon application restart.
3. Confirm that the SemanticColors namespace correctly maps semantic roles to the expected color values for each theme.
4. Verify that specific UI elements, such as the ribbon separator and MainWindow tabs, use the correct semantic constants (e.g., MUTED, SAVED).

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

@codacy-production

codacy-production Bot commented May 30, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 4 medium

Alerts:
⚠ 4 issues (≤ 0 issues of at least minor severity)

Results:
4 new issues

Category Results
ErrorProne 3 medium
Complexity 1 medium

View in Codacy

🟢 Metrics 3 complexity · -9 duplication

Metric Results
Complexity 3
Duplication -9

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary

This PR successfully implements a semantic color system and a theme selection mechanism. It centralizes UI state colors (like modified, saved, and danger) into a unified namespace, which greatly improves consistency and maintainability across the codebase.

Key Improvements:

  • Introduced SemanticColors namespace to standardize state indicators.
  • Added 7 diverse themes (Tibia RPG, Modern Dark, etc.) with a live preview in Preferences.
  • Refactored multiple UI components to use theme-aware constants instead of hardcoded values.

🔍 General Feedback

The overall architecture is sound and leverages C++20 features (like std::ranges) effectively. The transition to a theme-driven UI is well-executed.

I have raised some minor points regarding:

  1. Header Hygiene: Removal of unnecessary imgui_internal.h.
  2. Modern C++: Using inline constexpr for global constants in headers to avoid multiple definitions.
  3. Consistency: Ensuring semantically correct constants are used even when values overlap.
  4. Code Quality: Fixing some minor indentation and switch-case issues.

Overall, great work on standardizing the UI visuals!

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary (Addendum)

I've added some further suggestions for Theme.h regarding code style, switch-case exhaustive matching, and header-only constant linkage.

Further Observations:

  • Theme.h Indentation: Fixed inconsistent indentation in ApplyOtclientTheme and ApplyTibiaRPGTheme.
  • Exhaustive Switches: Recommended explicit case for OtclientTheme to ensure all enum values are covered.
  • Header Linkage: Suggested inline constexpr for global arrays in Theme.h to avoid ODR issues and redundant copies in multiple translation units.
  • Consistency: Suggested using SC::MODIFIED instead of SC::GOLD in MainWindow.cpp for modified tab coloring (even though values are identical).

Overall, the semantic color system is a very solid addition to the project.

// Semantic Colors — universal across all themes
// These represent UI state meaning, visible regardless of background.
// ============================================================================
namespace SemanticColors {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Use inline constexpr for global constants in headers to avoid multiple definitions across translation units.

Suggested change
namespace SemanticColors {
namespace SemanticColors {

Simplified theme system by removing redundant themes and consolidated UI text color usage through semantic helpers to improve maintainability and consistency.
- `ImguiMapEditor/UI/Core/Theme.h` — removed unused theme functions, consolidated theme enum, and added `TextPrimary()`/`TextDim()` helpers
- `ImguiMapEditor/UI/Dialogs/Startup/AvailableClientsPanel.cpp` — migrated hardcoded colors to semantic text helpers
- `ImguiMapEditor/UI/Dialogs/Startup/ClientInfoPanel.cpp` — migrated hardcoded colors to semantic text helpers
- `ImguiMapEditor/UI/Dialogs/Startup/RecentMapsPanel.cpp` — added hover tooltip for map path, migrated colors to semantic helpers
- `ImguiMapEditor/UI/Dialogs/Startup/SelectedMapPanel.cpp` — migrated hardcoded colors to semantic text helpers
- `ImguiMapEditor/UI/Dialogs/Startup/StartupDialog.cpp` — migrated hardcoded colors to semantic text helpers
- `ImguiMapEditor/UI/PreferencesDialog.cpp` — updated theme selection icon logic for streamlined theme list
- `ImguiMapEditor/UI/Ribbon/Panels/ThemePanel.cpp` — updated theme icon mapping to reflect consolidated theme set

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Review Summary

This PR introduces a robust Semantic Color System that significantly improves the maintainability and consistency of the UI. By centralizing UI state indicators (modified, saved, danger, etc.) into the SemanticColors namespace, the application is now much better equipped for future theming work.

🔍 General Feedback

  • Semantic Colors: Great architectural improvement. Using descriptive names like SAVED and DANGER instead of raw RGB values makes the code much more readable.
  • Theme Awareness: The refactoring of StartupDialog and other components to use theme-driven tokens correctly removes hardcoded assumptions about the background colors.
  • Breaking Changes: The reordering and removal of themes in ThemeType will affect existing user configurations. This is the primary concern that should be addressed (either via migration or by preserving enum values).
  • Code Quality: The implementation is clean and follows the project's existing style.

🔴 Critical Issues

  • None (aside from the breaking change in configuration which is 🟠).

🟠 Major Issues

  • Backward Compatibility: ThemeType enum reordering will cause theme mismatches for existing users.

🟡 Minor Issues

  • Feature Removal: Several themes were removed without notice in the PR description.
  • Hardcoded Values: A few hardcoded alpha values remain in the pulse animations.

Overall, this is a very high-quality contribution that moves the project in the right direction.

// ============================================================================
namespace SemanticColors {
// State indicators
inline constexpr ImVec4 MODIFIED { 1.00f, 0.80f, 0.00f, 1.00f };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Excellent Refactor: Replacing hardcoded ImVec4 values with semantic constants is a great step towards a more maintainable and consistent UI. The SemanticColors namespace provides a clear vocabulary for UI states.

// ============================================================================
// Theme selection
// ============================================================================
enum class ThemeType {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Breaking Change: The ThemeType enum has been reordered and several values removed. Since these are likely persisted in user configuration files as integers, this will cause existing settings to load incorrect themes.

For example:

  • Old ModernDark (1) will now load DocumentLight (1).
  • Old TibiaRPG (0) will now load ModernDark (0).

Consider preserving the original integer values to maintain backward compatibility, or implement a migration path.

} // namespace SemanticColors

// Theme selection enum
// ============================================================================

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Feature Regression: Several themes (TibiaRPG, ForestGreen, SunsetOrange, etc.) have been removed. While the new semantic color system is a significant improvement, these removals should be explicitly mentioned in the PR description as they affect user-facing features.


tab_color.x = color_green.x + (color_yellow.x - color_green.x) * t;
tab_color.y = color_green.y + (color_yellow.y - color_green.y) * t;
tab_color.z = color_green.z + (color_yellow.z - color_green.z) * t;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Hardcoded Alpha: While the color components are now semantic, the alpha value 0.7f remains hardcoded. It might be worth adding a constant to SemanticColors for standard overlay alphas to ensure consistency across the application.

@karolak6612 karolak6612 merged commit 7bf322e into main May 31, 2026
7 of 8 checks passed
@karolak6612 karolak6612 deleted the Themes-fix branch June 6, 2026 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: UI Changes to the wxWidgets GUI (palettes, dialogs, menus, toolbar). Type: Enhancement New feature or request.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant