Skip to content

Add contextual tool rail actions#437

Merged
fernandotonon merged 2 commits into
masterfrom
codex/contextual-tool-rail
May 8, 2026
Merged

Add contextual tool rail actions#437
fernandotonon merged 2 commits into
masterfrom
codex/contextual-tool-rail

Conversation

@fernandotonon
Copy link
Copy Markdown
Owner

@fernandotonon fernandotonon commented May 8, 2026

Summary

  • Add mode-scoped left rail actions for animation, material, and validation workflows.
  • Reuse existing actions/controllers for Dope Sheet, Curve Editor, Merge Animations, Material Editor, and MeshValidator.
  • Keep shared menu actions reachable while hiding their top-toolbar widgets by mode.
  • Add coverage for rail mode switching, shared action reachability, and bottom-tool button behavior.

Validation

  • cmake --build build_local --target UnitTests -j"$(nproc)"
  • env QT_QPA_PLATFORM=offscreen build_local/bin/UnitTests --gtest_filter=MainWindowTest.ContextualToolRail*:MainWindowTest.ModeBarLoadsAndModeChangeUpdatesStatusIndicator
  • cmake --build build_local --target QtMeshEditor -j"$(nproc)"

Summary by CodeRabbit

Release Notes

  • New Features

    • Added quick-access toolbar buttons for Dope Sheet, Curve Editor, Merge Animations, Material Editor, and Mesh Validation tools.
  • Improvements

    • Toolbar now intelligently displays and hides relevant editing tools based on your current mode.
    • Toolbar state automatically updates when your selections change.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack

Warning

Rate limit exceeded

@fernandotonon has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 28 minutes and 2 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e635d6e-a7a3-4d9f-926c-c65041c13884

📥 Commits

Reviewing files that changed from the base of the PR and between 5f295d5 and 119d199.

📒 Files selected for processing (2)
  • src/mainwindow.cpp
  • src/mainwindow_test.cpp
📝 Walkthrough

Walkthrough

This PR introduces context-sensitive toolbar rail buttons and centralizes mode-driven action visibility in MainWindow. It adds a helper to create reusable rail buttons for Dope Sheet, Curve Editor, Merge Animations, Material Editor, and Mesh Validation. The core updateToolRailForMode() logic is expanded to show/hide actions by editor mode and selection state, with signals from SelectionSet and MeshValidator triggering visibility refreshes. Three new tests validate mode transitions, shared action visibility, and rail button behavior.

Changes

Toolbar Rail Buttons and Mode-Driven Visibility

Layer / File(s) Summary
Include and Helper Setup
src/mainwindow.cpp
Adds <functional> include to support a reusable addRailButton lambda helper for creating toolbar rail actions.
Rail Button Creation
src/mainwindow.cpp
Creates new toolbar rail buttons for Dope Sheet, Curve Editor, Merge Animations, Material Editor, and Mesh Validation using the helper. Each button wires to existing dock-show actions or toolbar commands.
Mode-Driven Visibility Logic
src/mainwindow.cpp
Enhances updateToolRailForMode() to support Validation mode, add per-action visibility control by objectName() prefix (modeObject, modeEdit, modeAnimation, modeMaterial, modeValidation, modeAny), and enable actions based on mode and selection state.
Signal Routing and Connections
src/mainwindow.cpp
Wires SelectionSet::selectionChanged and MeshValidator::selectionChanged signals to trigger updateToolRailForMode() for consistent rail visibility refresh.
Merge Animation State Synchronization
src/mainwindow.cpp
Updates updateMergeAnimationsButton() to call updateToolRailForMode() whenever the Merge Animations action enablement changes, keeping rail UI synchronized with merge button state.
Test Coverage
src/mainwindow_test.cpp
Three new tests validate mode-specific action visibility transitions, shared menu action visibility in Validation mode, and DopeSheet rail button activation of the bottom dock.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Rail buttons hop in line,
Mode-aware and fine,
Selection signals dance and glow,
Each action knows when to show! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% 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
Title check ✅ Passed The title 'Add contextual tool rail actions' directly describes the main change: introducing mode-scoped left rail actions with context-sensitive behavior.
Description check ✅ Passed The description follows the template structure with a comprehensive Summary section covering the key changes and objectives, plus a Validation section with build/test commands. However, it lacks the Technical Details subsection with ✨ Features and 🐛 Bugfixes breakdown as specified in the template.
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.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/contextual-tool-rail

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.

@fernandotonon fernandotonon force-pushed the codex/contextual-tool-rail branch from 5f295d5 to 7c9b4ea Compare May 8, 2026 14:26
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (2)
src/mainwindow.cpp (2)

2596-2618: ⚡ Quick win

updateToolRailForMode() is called redundantly inside updateMergeAnimationsButton.

SelectionSet::selectionChanged is connected to updateMergeAnimationsButton first (line ~1401) and then directly to updateToolRailForMode (line ~1403). Qt fires connections in registration order, so updateToolRailForMode already executes after updateMergeAnimationsButton has updated actionMerge_Animations->isEnabled() on every selection change. The three explicit updateToolRailForMode() calls at lines 2600, 2612, and 2618 are therefore redundant and cause updateToolRailForMode to iterate all toolbar actions twice per selection event.

♻️ Proposed fix — remove the three redundant calls
     if (skelEntities.size() < 2)
     {
         ui->actionMerge_Animations->setEnabled(false);
-        updateToolRailForMode();
         return;
     }
 
     // Check all pairs are compatible
     Ogre::SkeletonPtr baseSkel = skelEntities.first()->getMesh()->getSkeleton();
     for (int i = 1; i < skelEntities.size(); ++i)
     {
         Ogre::SkeletonPtr otherSkel = skelEntities[i]->getMesh()->getSkeleton();
         if (!AnimationMerger::areSkeletonsCompatible(baseSkel, otherSkel))
         {
             ui->actionMerge_Animations->setEnabled(false);
-            updateToolRailForMode();
             return;
         }
     }
 
     ui->actionMerge_Animations->setEnabled(true);
-    updateToolRailForMode();
🤖 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 `@src/mainwindow.cpp` around lines 2596 - 2618, The three explicit calls to
updateToolRailForMode() inside updateMergeAnimationsButton are redundant because
SelectionSet::selectionChanged is already connected to updateToolRailForMode and
Qt will call it after updateMergeAnimationsButton; remove the
updateToolRailForMode() calls that follow setting
ui->actionMerge_Animations->setEnabled(...) (the ones after the early return
when skelEntities.size() < 2, after detecting incompatible skeletons, and after
enabling the action) so updateMergeAnimationsButton only sets
ui->actionMerge_Animations and returns, leaving updateToolRailForMode() to be
invoked by the existing signal connection.

1811-1815: 💤 Low value

setSharedToolbarActionVisible: visible parameter does not control action visibility — name is misleading.

action->setVisible(true) is unconditionally called regardless of visible; the parameter only governs the toolbar-widget button. A caller passing false would reasonably expect the action to be hidden, but it won't be. Consider renaming to setSharedToolbarButtonVisible or adding an inline comment clarifying the intent.

♻️ Proposed clarification
-    auto setSharedToolbarActionVisible = [this](QAction* action, bool visible) {
-        action->setVisible(true);
+    // Keeps the QAction reachable in menus (action always visible) while
+    // showing/hiding only its toolbar-button representation.
+    auto setSharedToolbarButtonVisible = [this](QAction* action, bool showButton) {
+        action->setVisible(true); // keep reachable in menus
         if (QWidget* toolbarButton = ui->toolToolbar->widgetForAction(action))
-            toolbarButton->setVisible(visible);
+            toolbarButton->setVisible(showButton);
     };
-    setSharedToolbarActionVisible(ui->actionMaterial_Editor, objectMode || materialMode);
-    setSharedToolbarActionVisible(ui->actionMerge_Animations, objectMode || animationMode);
+    setSharedToolbarButtonVisible(ui->actionMaterial_Editor, objectMode || materialMode);
+    setSharedToolbarButtonVisible(ui->actionMerge_Animations, objectMode || animationMode);
🤖 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 `@src/mainwindow.cpp` around lines 1811 - 1815, The lambda
setSharedToolbarActionVisible currently forces the QAction visible regardless of
the visible parameter, so change action->setVisible(true) to
action->setVisible(visible) so the QAction visibility follows the boolean;
ensure the ui->toolToolbar->widgetForAction(action) branch continues to set the
toolbar widget visibility as before (toolbarButton->setVisible(visible)), and
update any callers or rename the lambda if you prefer the original behavior to
only affect the toolbar button.
🤖 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.

Nitpick comments:
In `@src/mainwindow.cpp`:
- Around line 2596-2618: The three explicit calls to updateToolRailForMode()
inside updateMergeAnimationsButton are redundant because
SelectionSet::selectionChanged is already connected to updateToolRailForMode and
Qt will call it after updateMergeAnimationsButton; remove the
updateToolRailForMode() calls that follow setting
ui->actionMerge_Animations->setEnabled(...) (the ones after the early return
when skelEntities.size() < 2, after detecting incompatible skeletons, and after
enabling the action) so updateMergeAnimationsButton only sets
ui->actionMerge_Animations and returns, leaving updateToolRailForMode() to be
invoked by the existing signal connection.
- Around line 1811-1815: The lambda setSharedToolbarActionVisible currently
forces the QAction visible regardless of the visible parameter, so change
action->setVisible(true) to action->setVisible(visible) so the QAction
visibility follows the boolean; ensure the
ui->toolToolbar->widgetForAction(action) branch continues to set the toolbar
widget visibility as before (toolbarButton->setVisible(visible)), and update any
callers or rename the lambda if you prefer the original behavior to only affect
the toolbar button.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8282ad56-84af-48a0-9397-d32f7f848c45

📥 Commits

Reviewing files that changed from the base of the PR and between 751583a and 5f295d5.

📒 Files selected for processing (2)
  • src/mainwindow.cpp
  • src/mainwindow_test.cpp

… rail refreshes

- Rename `setSharedToolbarActionVisible` -> `setSharedToolbarButtonVisible`
  and add a comment explaining the contract: the QAction stays visible in
  menus (so users always find Material Editor / Merge Animations there),
  while only the toolbar-button widget is gated by mode. The previous
  parameter name suggested it controlled QAction visibility, but the body
  unconditionally set the action visible regardless of the flag.
- Remove three redundant `updateToolRailForMode()` calls inside
  `updateMergeAnimationsButton()`. `SelectionSet::selectionChanged` is
  wired to `updateMergeAnimationsButton` first and `updateToolRailForMode`
  right after, so the rail is already refreshed for free after this slot
  completes — calling it here just iterated every toolbar action twice
  per selection event. Added a comment so the next reader sees why.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fernandotonon
Copy link
Copy Markdown
Owner Author

Addressed both CodeRabbit findings in 119d199:

  • Misleading setSharedToolbarActionVisible (src/mainwindow.cpp ~L1811) — renamed to setSharedToolbarButtonVisible with a comment documenting the contract. The QAction stays visible in menus on purpose so users can always reach Material Editor / Merge Animations from the menu bar, while only the toolbar-button widget is gated by the active mode. The parameter name (showButton) now reflects that.
  • Redundant updateToolRailForMode() in updateMergeAnimationsButton (src/mainwindow.cpp ~L2596-2618) — removed all three calls. SelectionSet::selectionChanged is wired to updateMergeAnimationsButton first and updateToolRailForMode immediately after (see the connect() pair around L1402-1404), and Qt fires connections in registration order — so the rail is already refreshed for free after this slot completes. Added a comment in updateMergeAnimationsButton so the next reader sees why we don't call it here. Existing UpdateMergeAnimationsButton* and ContextualToolRail* tests still cover the behaviour through the signal path.

Validation:

  • cmake --build build_local --target QtMeshEditor UnitTests -j"$(nproc)" (clean)
  • Local GUI smoke test (app starts, no console errors)

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 8, 2026

@fernandotonon fernandotonon merged commit fb87f5e into master May 8, 2026
19 checks passed
@fernandotonon fernandotonon deleted the codex/contextual-tool-rail branch May 8, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant