Skip to content

Conversation

@mkh-user
Copy link
Member

@mkh-user mkh-user commented Dec 4, 2025

Summary of Changes

  • Shift hue, saturation, and brightness of editor without themes
  • Real "Dynamic Reload" for settings just when settings change
  • Add support for float values in preferences

Related Items

Technical Details & Testing

  • Unnecessary Signals.settings_changed emissions removed, currently Settings API emits this signal in set_setting().
  • Support for float setting values added as SpinBox.
  • A new force_silent property added to Settings.set_setting() to avoid Signals.settings_changed emissions when needed.
  • New overlay_filter added to main window of editor to apply UI Filter.
  • A shader for UI Filter with hue_shift, saturation, and brightness added:
    • Gets three hsb values from settings.
    • Converts screen texture to HSV.
    • Applies filter.
    • Converts filtered texture to RGB.
    • Sets screen texture to new colors (keeps alpha channel`).

Checklist

  • Linked all relevant issues/PRs/discussions
  • Code follows project style and guidelines
  • Self-reviewed and tested thoroughly
  • Documentation updated (if applicable)
  • No new warnings or errors introduced
  • Relevant changes added to CHANGELOG

Summary by CodeRabbit

  • New Features

    • Visual UI filter overlay (hue, saturation, brightness) and finer float-step control.
  • Improvements

    • Option to save settings silently (no notification).
    • Preferences window close behavior streamlined to avoid unintended callbacks.
    • Theme changes no longer broadcast a global settings-changed notification by default.
  • Documentation

    • Added "Customize Editor Appearance" / UI Filter guidance.
  • Tests

    • Substantial new and expanded tests covering settings, preferences, theme, UI filter, and shader.

✏️ Tip: You can customize this high-level summary in your review settings.

- Shift hue, saturation, and brightness of editor without themes
- Real "Dynamic Reload" for settings just when settings change
- Add support for float values in preferences
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 2025

📝 Walkthrough

Walkthrough

Preferences window no longer emits SettingsChanged on close; SettingOption guards empty keys and refactors float handling; Settings.set_setting gains a force_silent option to suppress signals; a new HSV UI filter shader and overlay ColorRect were added and Core updates its shader uniforms on settings reload.

Changes

Cohort / File(s) Summary
Preferences close behavior
action_scripts/scenes/preferences.gd, action_scripts/scenes/preferences.tscn
Removed _on_close_requested() handler that emitted Signals.settings_changed; close_requested now calls queue_free() directly.
SettingOption UI
action_scripts/scenes/setting_option.gd, action_scripts/scenes/setting_option.tscn
Added early-return when section/key empty, removed public default var, switched Settings.get_setting(section,key,default) to Settings.get_setting(section,key), and set SpinBox step = 0.01.
Settings API
core/autoload/settings.gd
Added force_silent parameter to set_setting(section,key,value,force_silent := false); early-return if value unchanged or save fails; emit Signals.settings_changed only when force_silent is false.
UI filter shader & overlay
core/main.gd, core/main.gdshader, core/main.gdshader.uid, core/main.tscn
Added canvas_item shader (hue_shift, saturation, brightness uniforms), new UIFilter CanvasLayer and OverlayShader ColorRect with ShaderMaterial, and exported overlay_shader on Core; Core updates shader uniforms on reload.
Marketplace theme handling
action_scripts/scenes/marketplace.gd
Removed emission of Signals.settings_changed from _change_theme, so theme updates no longer broadcast that signal.
Docs & changelog
CHANGELOG.md, docs/setup.md
Added "UI Filter" and "Enhanced dynamic reload" entries and a "Customize Editor Appearance / UI Filter" docs section.
Tests (new/updated)
tests/...
tests/core/main_test.gd, tests/core/shader_validation_test.gd, tests/core/ui_filter_integration_test.gd, tests/action_scripts/scenes/preferences_test.gd, tests/action_scripts/scenes/marketplace_test.gd, tests/action_scripts/scenes/setting_option_test.gd, tests/core/autoload/settings_test.gd
Added/expanded test suites covering Settings.set_setting behavior (force_silent, early-return), Preferences window close behavior, SettingOption UI types, Marketplace theme changes, shader validation, and UI filter integration; test counts and indexes updated.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as User (UI)
    participant Pref as Preferences Window
    participant Settings as Settings (autoload)
    participant Core as Core/Main
    participant Overlay as OverlayShader (ColorRect)

    User->>Pref: change setting or close window
    Pref->>Settings: set_setting(section,key,value,force_silent?)
    alt value unchanged
        Settings-->>Pref: return (no write, no emit)
    else save failed
        Settings-->>Pref: return (save failed)
    else save succeeded
        alt force_silent == false
            Settings->>Settings: emit Signals.settings_changed
            Settings->>Core: settings_changed triggers reload handler
            Core->>Core: reload mode, read UI presets
            Core->>Overlay: update shader uniforms (hue_shift,saturation,brightness)
        else force_silent == true
            Settings-->>Core: no settings_changed emitted (silent)
        end
    end

    Note right of Pref: Closing preferences now calls queue_free() directly (no manual settings_changed emit)
Loading

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature addition: a UI Filter for the main window that adjusts hue, saturation, and brightness, matching the primary objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mkh-user/ui-filter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai bot added the action scripts Official action scripts or action scripts features label Dec 4, 2025
coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@mkh-user mkh-user self-assigned this Dec 4, 2025
@mkh-user mkh-user removed the action scripts Official action scripts or action scripts features label Dec 4, 2025
@mkh-user mkh-user moved this from Needs Review to In Progress in Release: Text Forge 1.0 Dec 4, 2025
@mkh-user mkh-user added this to the Text Forge 0.2 milestone Dec 4, 2025
mkh-user and others added 2 commits December 4, 2025 10:07
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@mkh-user

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@coderabbitai coderabbitai bot added the action scripts Official action scripts or action scripts features label Dec 4, 2025
coderabbitai[bot]

This comment was marked as resolved.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@coderabbitai

This comment was marked as resolved.

1 similar comment
@coderabbitai

This comment was marked as duplicate.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
tests/README.md (1)

28-57: Fix markdown formatting issues in the code example.

The test generation guidance code block has two formatting issues:

  1. Line 29: Missing language identifier for the fenced code block
  2. Lines 43-53: Hard tabs should be replaced with spaces for consistency

Apply this diff to fix the formatting:

-- Don't use local variables in lambda functions, use like this (`test_neme__var_name`):
-```
+- Don't use local variables in lambda functions, use like this (`test_name__var_name`):
+```gdscript
 # GdUnit generated TestSuite
 class_name UIFilterIntegrationTestSuite
 extends GdUnitTestSuite
@@ -41,13 +41,13 @@
 ...
 
 func test_complete_ui_filter_workflow() -> void:
-	# Test complete workflow: setting -> signal -> reload
-	var connection := func(): test_complete_ui_filter_workflow__signal_emitted = true
-	Signals.settings_changed.connect(connection)
-
-	# Change hue shift
-	Settings.set_setting(test_section, "filter_hue_shift", 0.5)
-	await get_tree().process_frame
-	assert_bool(test_complete_ui_filter_workflow__signal_emitted).is_true()
-	assert_float(Settings.get_setting(test_section, "filter_hue_shift")).is_equal(0.5)
-
-	Signals.settings_changed.disconnect(connection)
+  # Test complete workflow: setting -> signal -> reload
+  var connection := func(): test_complete_ui_filter_workflow__signal_emitted = true
+  Signals.settings_changed.connect(connection)
+
+  # Change hue shift
+  Settings.set_setting(test_section, "filter_hue_shift", 0.5)
+  await get_tree().process_frame
+  assert_bool(test_complete_ui_filter_workflow__signal_emitted).is_true()
+  assert_float(Settings.get_setting(test_section, "filter_hue_shift")).is_equal(0.5)
+
+  Signals.settings_changed.disconnect(connection)
 
 ...

Note: Also fixed typo "test_neme__var_name" → "test_name__var_name" on line 28.

tests/action_scripts/scenes/marketplace_test.gd (2)

17-25: Marketplace tests currently exercise only Settings, not marketplace.gd behavior

All tests here operate directly on Settings.set_setting / Signals.settings_changed and never instantiate res://action_scripts/scenes/marketplace.gd or call its _change_theme() helper. That means these tests won’t catch regressions where _change_theme() starts emitting the signal manually again or stops delegating to Settings.set_setting.

If you want this suite to guard marketplace-specific behavior, consider:

  • Instantiating the marketplace scene/script, and
  • Calling _change_theme() (or the public equivalent) in these tests, asserting:
    • The theme setting is updated via Settings, and
    • Only one settings_changed emission occurs per theme change.

Otherwise, you may want to rename or relocate these tests to make it clear they’re exercising the Settings API contract rather than the marketplace scene itself.

Also applies to: 26-99


17-25: Clarify or implement theme restoration in hooks

before_test() is currently a stub with a comment about storing the original theme, while after_test() always calls Settings.restore_default("editor_ui", "theme_name") when a preset exists. That can permanently reset the editor’s theme to its preset default when tests run against a real user profile.

Two options:

  • Implement actual save/restore in the hooks (capture the original theme and set it back), or
  • If the test environment always uses an isolated config, simplify by removing the “Store original theme” comment to avoid implying behavior that doesn’t exist.
tests/core/autoload/settings_test.gd (1)

13-22: Settings signal/early‑return behavior is well covered; consider improving the save‑error test

The added fields and tests accurately exercise the updated Settings.set_setting contract:

  • Early return when setting the same value (string, numeric, boolean, float).
  • Signal emission on actual value changes.
  • force_silent suppressing Signals.settings_changed, including the explicit false case.
  • restore_default emitting when it changes a value and remaining silent when already at default.

This suite should catch most regressions around the new force_silent parameter and early‑return logic.

One gap is test_set_setting_does_not_emit_on_save_error(), which currently just passes with a comment. As written, it can’t fail and gives the impression that the save‑error path is tested when it isn’t. Consider either:

  • Implementing a small seam (e.g., injectable file API or temporary invalid path) to force a save failure and assert that no signal is emitted, or
  • Removing the test (or marking it explicitly as a documentation‑only placeholder) to avoid a false sense of coverage.

Also applies to: 139-269

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67e4367 and bd3d288.

📒 Files selected for processing (20)
  • action_scripts/scenes/setting_option.gd (1 hunks)
  • action_scripts/scenes/setting_option.tscn (1 hunks)
  • core/autoload/settings.gd (2 hunks)
  • tests/INDEX.md (1 hunks)
  • tests/README.md (2 hunks)
  • tests/TEST_SUMMARY.md (1 hunks)
  • tests/action_scripts/scenes/marketplace_test.gd (1 hunks)
  • tests/action_scripts/scenes/marketplace_test.gd.uid (1 hunks)
  • tests/action_scripts/scenes/preferences_test.gd (1 hunks)
  • tests/action_scripts/scenes/preferences_test.gd.uid (1 hunks)
  • tests/action_scripts/scenes/setting_option_test.gd (1 hunks)
  • tests/action_scripts/scenes/setting_option_test.gd.uid (1 hunks)
  • tests/core/autoload/backup_core_test.gd (1 hunks)
  • tests/core/autoload/settings_test.gd (2 hunks)
  • tests/core/main_test.gd (1 hunks)
  • tests/core/main_test.gd.uid (1 hunks)
  • tests/core/shader_validation_test.gd (1 hunks)
  • tests/core/shader_validation_test.gd.uid (1 hunks)
  • tests/core/ui_filter_integration_test.gd (1 hunks)
  • tests/core/ui_filter_integration_test.gd.uid (1 hunks)
✅ Files skipped from review due to trivial changes (6)
  • tests/action_scripts/scenes/setting_option_test.gd.uid
  • tests/core/main_test.gd.uid
  • tests/core/ui_filter_integration_test.gd.uid
  • tests/action_scripts/scenes/marketplace_test.gd.uid
  • tests/action_scripts/scenes/preferences_test.gd.uid
  • tests/core/shader_validation_test.gd.uid
🚧 Files skipped from review as they are similar to previous changes (1)
  • action_scripts/scenes/setting_option.gd
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-04T06:30:54.607Z
Learnt from: mkh-user
Repo: text-forge/text-forge PR: 145
File: core/main.gd:149-152
Timestamp: 2025-12-04T06:30:54.607Z
Learning: In the text-forge codebase (core/main.gd), the project prefers to use unit test assertions to verify that required scene nodes like overlay_shader are properly configured, rather than adding runtime null checks in the code.

Applied to files:

  • tests/core/main_test.gd
  • tests/core/shader_validation_test.gd
🪛 markdownlint-cli2 (0.18.1)
tests/README.md

29-29: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


43-43: Hard tabs
Column: 1

(MD010, no-hard-tabs)


44-44: Hard tabs
Column: 1

(MD010, no-hard-tabs)


45-45: Hard tabs
Column: 1

(MD010, no-hard-tabs)


47-47: Hard tabs
Column: 1

(MD010, no-hard-tabs)


48-48: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)


50-50: Hard tabs
Column: 1

(MD010, no-hard-tabs)


51-51: Hard tabs
Column: 1

(MD010, no-hard-tabs)


53-53: Hard tabs
Column: 1

(MD010, no-hard-tabs)

🔇 Additional comments (15)
tests/INDEX.md (1)

18-37: LGTM! Documentation accurately reflects test expansion.

The updated test counts align with the expanded test coverage across Action Scripts, Autoloads, and Core test suites introduced in this PR.

tests/TEST_SUMMARY.md (1)

9-43: LGTM! Test summary accurately documents expanded coverage.

The updated metrics and new test file entries properly reflect the comprehensive test expansion introduced in this PR, including the new UI Filter and Settings API test coverage.

tests/action_scripts/scenes/preferences_test.gd (3)

14-16: LGTM! Clean test setup.

The before_test hook properly instantiates the Preferences window from the scene file and adds it to the test tree.


30-38: LGTM! Validates the new close behavior.

This test correctly verifies that the close_requested signal is now connected to queue_free, aligning with the PR change to remove the manual signal emission handler.


40-52: Excellent test for the key behavioral change.

This test validates that closing the Preferences window no longer manually emits settings_changed, which is the core change in this PR. The signal should now only be emitted by Settings.set_setting().

action_scripts/scenes/setting_option.tscn (1)

67-67: LGTM! Enables float precision in preferences.

The step value of 0.01 provides appropriate granularity for float settings, aligning with the PR's goal to add float value support in preferences.

tests/core/autoload/backup_core_test.gd (1)

81-81: LGTM! Improves type safety.

The explicit type annotation enhances code clarity and leverages GDScript's static typing.

core/autoload/settings.gd (1)

98-112: LGTM! Well-designed Settings API improvements.

The changes introduce three valuable enhancements:

  1. force_silent parameter: Enables suppression of settings_changed signal for batch operations or internal updates
  2. Early return on unchanged value (lines 99-101): Prevents unnecessary file I/O and signal emission when the value hasn't changed
  3. Early return on save error (line 110): Correctly prevents signal emission when persistence fails

The logic correctly handles both existing keys (with change detection) and new keys (which always proceed to save).

tests/action_scripts/scenes/setting_option_test.gd (4)

14-30: LGTM! Proper test isolation with setup/teardown.

The before_test and after_test hooks correctly clean up test settings and presets, ensuring test independence.


44-110: Excellent coverage of numeric type handling.

The test suite comprehensively validates both integer and float settings, including important edge cases:

  • Boolean toggle (true/false with UI label changes)
  • Standard integer values
  • Float values with various edge cases (zero, negative, large values)

This ensures robust float support introduced in this PR.


139-197: LGTM! Thorough UI interaction validation.

The tests correctly verify that UI interactions (checkbox presses, spinbox changes, text submissions) properly update the underlying Settings backend, including array parsing with whitespace trimming.


199-207: Good defensive test for unsupported types.

This test verifies graceful degradation when an unsupported type (dictionary) is used, confirming the component properly queues itself for deletion rather than failing silently or crashing.

tests/core/ui_filter_integration_test.gd (1)

18-27: UI filter integration tests look consistent with Settings + signal semantics

The suite does a good job exercising:

  • Signal emission vs. force_silent behavior,
  • Multiple sequential updates,
  • Default restoration and edge ranges for the filter settings, and
  • Independence of UI filter values from theme changes.

The only minor thing to watch is that after_test() calls Settings.restore_default for the UI filter keys without checking whether presets exist; if restore_default ever starts asserting on missing presets, these tests will need corresponding guards (as you already do in MainTestSuite.after_test). Otherwise, the structure and coverage here look solid.

Also applies to: 28-183

tests/core/main_test.gd (1)

16-24: Main UI filter tests match the intended behavior and project testing style

This suite nicely documents:

  • Preset presence and default values for filter_hue_shift, filter_saturation, filter_brightness, and theme_name,
  • Accepted value ranges (including extremes), and
  • That UI filter settings are independent and resettable via restore_default.

The guarded restore_default calls in after_test() also avoid issues when presets are absent. Based on learnings, these tests align well with the project’s preference to validate configuration and nodes (e.g., overlay/filter) via tests rather than runtime null checks in core/main.gd.

One thing to keep in mind: tests like test_theme_default_value() hard‑code "dark" as the expected default. If you ever introduce “system” or OS‑driven defaults, you’ll need to update these assertions accordingly.

Also applies to: 25-170

tests/core/shader_validation_test.gd (1)

10-138: Shader validation tests are thorough; string checks may need maintenance over time

These tests give strong structural guarantees around res://core/main.gdshader and its UID: existence, load success, uniforms, helper functions, fragment entry point, shader type, and parameter wiring through ShaderMaterial and ColorRect. This fits well with the repo’s pattern of asserting required rendering pieces via tests instead of adding runtime null/defensive checks in core/main.gd. Based on learnings, this is the right place to encode those assumptions.

Be aware that tests using code.contains("...") on the shader source are somewhat brittle with respect to formatting or refactors to function signatures/uniform declarations. If you later reformat or restructure the shader, remember to adjust these substrings accordingly to keep the suite green.

@mkh-user mkh-user merged commit 64bef85 into Main Dec 4, 2025
2 checks passed
@mkh-user mkh-user deleted the mkh-user/ui-filter branch December 4, 2025 09:52
@github-project-automation github-project-automation bot moved this from In Progress to Completed in Release: Text Forge 1.0 Dec 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action scripts Official action scripts or action scripts features

Projects

Status: Completed

Development

Successfully merging this pull request may close these issues.

2 participants