Skip to content

Conversation

@nschimme
Copy link
Contributor

@nschimme nschimme commented Dec 19, 2025

Summary by Sourcery

Add Alt+Left-click drag interaction to adjust the 3D viewport orientation and extend horizontal camera rotation range.

New Features:

  • Allow Alt+Left-click dragging on the map canvas to rotate the camera by adjusting yaw and pitch based on mouse movement.

Enhancements:

  • Persist and restore the original cursor while Alt-dragging to give visual feedback of camera-rotation mode.
  • Increase the configurable horizontal camera angle range from ±45° to ±180° for wider viewport rotation.

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 19, 2025

Reviewer's Guide

Implements an Alt+Left-click drag interaction on the map canvas to rotate the 3D viewport camera (yaw and optionally pitch) with visual cursor feedback, and extends the horizontal camera angle configuration to support full 360° rotation.

Sequence diagram for Alt+Left-drag camera rotation interaction

sequenceDiagram
    actor User
    participant MapCanvas
    participant CanvasAdvancedConfig as CanvasAdvancedConfig

    User->>MapCanvas: mousePressEvent(Alt + Left, pos0)
    MapCanvas->>MapCanvas: create m_altDragState(lastPos = pos0, originalCursor)
    MapCanvas->>MapCanvas: setCursor(ClosedHandCursor)
    MapCanvas-->>User: event.accept()

    loop While Alt held and mouse moves
        User->>MapCanvas: mouseMoveEvent(Alt + Left, posN)
        MapCanvas->>MapCanvas: delta = posN - lastPos
        MapCanvas->>CanvasAdvancedConfig: read horizontalAngle, verticalAngle, autoTilt
        alt dx != 0
            MapCanvas->>CanvasAdvancedConfig: horizontalAngle.set(horizontalAngle + dx * SENSITIVITY)
        end
        alt !autoTilt and dy != 0
            MapCanvas->>CanvasAdvancedConfig: verticalAngle.set(verticalAngle - dy * SENSITIVITY)
        end
        alt angleChanged
            MapCanvas->>MapCanvas: graphicsSettingsChanged()
        end
        MapCanvas->>MapCanvas: update lastPos
        MapCanvas-->>User: event.accept()
    end

    User->>MapCanvas: mouseReleaseEvent(event)
    MapCanvas->>MapCanvas: restore cursor from m_altDragState.originalCursor
    MapCanvas->>MapCanvas: m_altDragState.reset()
    MapCanvas-->>User: event.accept()
Loading

Updated class diagram for MapCanvas Alt-drag state and configuration

classDiagram
    class MapCanvas {
        +MapCanvas(MapData &mapData, PrespammedPath &prespammedPath)
        +void mousePressEvent(QMouseEvent *event)
        +void mouseMoveEvent(QMouseEvent *event)
        +void mouseReleaseEvent(QMouseEvent *event)
        -std::optional~AltDragState~ m_altDragState
    }

    class AltDragState {
        +QPoint lastPos
        +QCursor originalCursor
    }

    class Configuration {
    }

    class CanvasAdvancedConfig {
        +FixedPoint_1_ verticalAngle
        +FixedPoint_1_ horizontalAngle  "-180.0 .. 180.0 degrees"
        +FixedPoint_1_ fov
        +FixedPoint_1_ layerHeight
        +BoolSetting autoTilt
    }

    MapCanvas *-- AltDragState : uses
    Configuration o-- CanvasAdvancedConfig : has
    MapCanvas ..> CanvasAdvancedConfig : setConfig().canvas.advanced
Loading

File-Level Changes

Change Details Files
Add Alt+Left-click drag interaction on the map canvas to adjust camera orientation with cursor feedback.
  • Detect Alt+Left-button combination in mousePressEvent to initiate a special drag state, capturing initial position and original cursor, switching to a closed-hand cursor, and short-circuiting normal handling.
  • Track mouse movement during an active Alt-drag in mouseMoveEvent, computing pixel deltas from the last position and converting them into incremental yaw and optional pitch changes using a fixed sensitivity factor, then triggering graphicsSettingsChanged when angles are updated.
  • Terminate Alt-drag cleanly in mouseMoveEvent when Alt is released mid-drag or in mouseReleaseEvent, restoring the original cursor, clearing drag state, and preventing further event propagation where appropriate.
  • Introduce AltDragState struct and optional member on MapCanvas to store drag bookkeeping (last mouse position and original cursor).
src/display/mapcanvas.cpp
src/display/mapcanvas.h
Extend horizontal camera angle configuration range to allow full 360°-equivalent yaw.
  • Increase horizontalAngle FixedPoint range from -45..45 degrees to -180..180 degrees by adjusting underlying bounds from -450..450 to -1800..180.
  • Keep existing default value while expanding allowed configuration range, enabling wider yaw rotation in the viewport.
src/configuration/configuration.h

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

Copy link

@sourcery-ai sourcery-ai bot left a comment

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:

  • The Alt-drag state is only cleared on mouseRelease, so if the user releases the Alt key while still holding the mouse button the canvas will stay in drag mode with the closed-hand cursor; consider listening for modifier changes or checking event->modifiers() during mouseMoveEvent to cancel the drag when Alt is no longer pressed.
  • The SENSITIVITY constant in mouseMoveEvent is hardcoded and its comment (1.0 degree per pixel) no longer matches the value (0.3f); consider either aligning the value with the comment or moving this into configuration so the mapping between pixels and degrees is explicit and easier to tune.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The Alt-drag state is only cleared on mouseRelease, so if the user releases the Alt key while still holding the mouse button the canvas will stay in drag mode with the closed-hand cursor; consider listening for modifier changes or checking `event->modifiers()` during `mouseMoveEvent` to cancel the drag when Alt is no longer pressed.
- The `SENSITIVITY` constant in `mouseMoveEvent` is hardcoded and its comment (`1.0 degree per pixel`) no longer matches the value (`0.3f`); consider either aligning the value with the comment or moving this into configuration so the mapping between pixels and degrees is explicit and easier to tune.

## Individual Comments

### Comment 1
<location> `src/display/mapcanvas.cpp:603-604` </location>
<code_context>
+        const auto delta = pos - dragState.lastPos;
+        dragState.lastPos = pos;
+
+        // Camera rotation sensitivity: 1.0 degree per pixel
+        constexpr float SENSITIVITY = 0.3f;
+
+        // Horizontal movement adjusts yaw (horizontalAngle)
</code_context>

<issue_to_address>
**issue:** Sensitivity comment and constant value are inconsistent.

The code comment says `1.0 degree per pixel`, but `SENSITIVITY` is `0.3f`. Please update either the comment or the constant so they match the actual behavior.
</issue_to_address>

### Comment 2
<location> `src/display/mapcanvas.cpp:623` </location>
<code_context>
+            }
+        }
+
+        graphicsSettingsChanged();
+        event->accept();
+        return;
</code_context>

<issue_to_address>
**suggestion (performance):** graphicsSettingsChanged() is called even when no angle change occurs.

When dx == 0 and (auto-tilt is enabled or dy == 0), neither horizontalAngle nor verticalAngle changes, yet graphicsSettingsChanged() is still emitted. If this signal can trigger expensive work, add a guard so it’s only emitted when one of these angles actually changes.

Suggested implementation:

```cpp
void MapCanvas::mouseMoveEvent(QMouseEvent *const event)
{
    if (m_altDragState.has_value()) {
        auto &conf = setConfig().canvas.advanced;
        bool angleChanged = false;

```

```cpp
        // Vertical movement adjusts pitch (verticalAngle), if auto-tilt is off
        if (!conf.autoTilt.get()) {
            const int dy = delta.y();
            if (dy != 0) {
                // Negated to match intuitive up/down dragging
                conf.verticalAngle.set(conf.verticalAngle.get()
                                       + static_cast<int>(static_cast<float>(-dy) * SENSITIVITY));
                angleChanged = true;
            }
        }

```

```cpp
        if (angleChanged) {
            graphicsSettingsChanged();
        }
        event->accept();
        return;

```

You should also set `angleChanged = true;` anywhere in this `mouseMoveEvent` branch where `conf.horizontalAngle` is modified (likely in the `dx != 0` handling). That ensures `graphicsSettingsChanged()` is emitted whenever either `horizontalAngle` or `verticalAngle` changes, and skipped when neither changes, matching the intent of the review comment.
</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.

@nschimme
Copy link
Contributor Author

@Halvance How does this look compared to #426 ?

The main change is switching to Alt+LeftClick as Macs don't have a MiddleClick.

@codecov
Copy link

codecov bot commented Dec 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.53%. Comparing base (26d1a9d) to head (7957436).
⚠️ Report is 163 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #433      +/-   ##
==========================================
- Coverage   66.48%   65.53%   -0.96%     
==========================================
  Files          85       86       +1     
  Lines        4186     3963     -223     
  Branches      255      264       +9     
==========================================
- Hits         2783     2597     -186     
+ Misses       1403     1366      -37     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nschimme
Copy link
Contributor Author

@sourcery-ai review

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • Consider handling m_altDragState cleanup in additional paths like leaveEvent/focusOutEvent (or widget destruction) so the cursor and drag state are always restored even if the mouse leaves the canvas or the widget loses focus mid-drag.
  • The SENSITIVITY constant and the comment // Camera rotation sensitivity: 3 degree per pixel appear inconsistent with the FixedPoint<1> angle units and integer cast; it would help to clarify the intended units and ensure the numeric value matches the comment (or vice versa).
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider handling `m_altDragState` cleanup in additional paths like `leaveEvent`/`focusOutEvent` (or widget destruction) so the cursor and drag state are always restored even if the mouse leaves the canvas or the widget loses focus mid-drag.
- The `SENSITIVITY` constant and the comment `// Camera rotation sensitivity: 3 degree per pixel` appear inconsistent with the `FixedPoint<1>` angle units and integer cast; it would help to clarify the intended units and ensure the numeric value matches the comment (or vice versa).

## Individual Comments

### Comment 1
<location> `src/display/mapcanvas.cpp:613-614` </location>
<code_context>
+        const auto delta = pos - dragState.lastPos;
+        dragState.lastPos = pos;
+
+        // Camera rotation sensitivity: 3 degree per pixel
+        constexpr float SENSITIVITY = 0.3f;
+
+        // Horizontal movement adjusts yaw (horizontalAngle)
</code_context>

<issue_to_address>
**issue:** The sensitivity comment appears inconsistent with the numeric value and the FixedPoint<1> units.

The code comment (`3 degree per pixel`) doesn’t match the effective rotation: with `SENSITIVITY = 0.3f` and `FixedPoint<1>` angles (tenths of a degree), a `dx` of 10 yields a change of 3 units = 0.3°. Please either change the constant to achieve the intended degrees-per-pixel, or update the comment to reflect the actual rotation per pixel.
</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.

@nschimme nschimme merged commit cce30bc into MUME:master Dec 28, 2025
20 of 21 checks passed
@nschimme nschimme deleted the alt-click-viewport branch December 28, 2025 16:36
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