-
Notifications
You must be signed in to change notification settings - Fork 0
Improve camera zoom and pan for smoother navigation #198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -218,10 +218,27 @@ | |
|
|
||
| void SpaceCamera::wheelEvent(QWheelEvent *event) | ||
| { | ||
| int delta = event->angleDelta().y() * 10 / 60 * getCameraSpeed(); | ||
| zoom(delta); | ||
| Ogre::Real xDelta = event->angleDelta().x() / 120.0f; | ||
|
Check warning on line 221 in src/SpaceCamera.cpp
|
||
| Ogre::Real yDelta = event->angleDelta().y() / 120.0f; | ||
|
Check warning on line 222 in src/SpaceCamera.cpp
|
||
|
|
||
| pan(Ogre::Vector2 ( event->angleDelta().x() * 10 / 60 * getCameraSpeed() , 0.0 )); | ||
| if (event->modifiers().testFlag(Qt::ControlModifier)) | ||
| { | ||
| // Ctrl + scroll = zoom (for mouse wheel users) | ||
| zoom(yDelta); | ||
| } | ||
| else if (event->source() == Qt::MouseEventSynthesizedBySystem) | ||
| { | ||
| // Trackpad two-finger swipe = pan in both axes | ||
| Ogre::Real panScale = 3.0f; | ||
| pan(Ogre::Vector2(xDelta * panScale, yDelta * panScale)); | ||
| } | ||
| else | ||
| { | ||
| // Mouse scroll wheel = zoom | ||
| zoom(yDelta); | ||
| if (std::abs(xDelta) > 0.01f) | ||
| pan(Ogre::Vector2(xDelta * 3.0f, 0.0f)); | ||
| } | ||
|
|
||
| event->accept(); | ||
| } | ||
|
|
@@ -331,20 +348,37 @@ | |
| ////////////////////////////////////////////////////////////////////////////////// | ||
| //Private Methods | ||
|
|
||
| void SpaceCamera::zoomByDelta(int delta) | ||
| void SpaceCamera::zoomByDelta(Ogre::Real delta) | ||
| { | ||
| zoom(delta); | ||
| } | ||
|
|
||
| void SpaceCamera::zoom(const int delta) | ||
| void SpaceCamera::zoom(Ogre::Real delta) | ||
| { | ||
| Ogre::Vector3 zTranslation(0, 0, delta); | ||
| mCameraNode->translate(zTranslation,Ogre::Node::TS_PARENT); | ||
| // Proportional zoom: step size scales with distance to target, | ||
| // so zooming feels consistent regardless of model size. | ||
| Ogre::Real distance = std::abs(mCameraNode->getPosition().z); | ||
| Ogre::Real minDistance = 0.01f; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Using a hardcoded Useful? React with 👍 / 👎. |
||
| Ogre::Real zoomFactor = 0.15f; // 15% of distance per scroll tick | ||
|
|
||
| Ogre::Real step = delta * std::max(distance, minDistance) * zoomFactor; | ||
|
|
||
| Ogre::Vector3 newPos = mCameraNode->getPosition(); | ||
| newPos.z += step; | ||
|
|
||
| // Don't pass through the target | ||
| if (newPos.z > -minDistance) | ||
| newPos.z = -minDistance; | ||
|
|
||
| mCameraNode->setPosition(newPos); | ||
| } | ||
|
|
||
| void SpaceCamera::pan(const Ogre::Real& deltaX, const Ogre::Real& deltaY) | ||
| { | ||
| mTarget->translate(deltaX,deltaY,0,Ogre::Node::TS_LOCAL ); | ||
| // Proportional pan: step scales with distance to target | ||
| Ogre::Real distance = std::abs(mCameraNode->getPosition().z); | ||
| Ogre::Real scale = std::max(distance, 0.01f) * 0.01f; | ||
| mTarget->translate(deltaX * scale, deltaY * scale, 0, Ogre::Node::TS_LOCAL); | ||
| } | ||
|
|
||
| void SpaceCamera::pan(const Ogre::Vector2& translation) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
In Qt (5 and 6), is QWheelEvent::source() == Qt::MouseEventSynthesizedBySystem a reliable way to detect two-finger touchpad scroll across macOS, Windows, and Linux? What is the recommended cross-platform detection signal (e.g., pixelDelta, pointingDevice type, phase)?💡 Result:
No.
QWheelEvent::source() == Qt::MouseEventSynthesizedBySystemis not a reliable (or portable) “two‑finger touchpad scroll” detector across macOS/Windows/Linux (and not even reliably on macOS): Qt explicitly warns that it was “tempting and wrong” to equate “synthesized” mouse events with “from touch”, and in practice both mouse-wheel and touchpad wheel events can reportMouseEventSynthesizedBySystem. [1], [2]Recommended cross‑platform approach (Qt 5 & Qt 6): don’t detect “touchpad”, detect high‑resolution scrolling
Use the wheel event properties that describe how the scroll is delivered, and handle both smoothly:
pixelDelta()when non-null (high‑resolution / touch-like scrolling); otherwise fall back toangleDelta()(traditional wheel “steps”). [3]phase()(when provided) to know whether you’re starting/updating/ending a scroll sequence; for non‑phase‑aware mice it isNoScrollPhase. [4]inverted()to respect “natural scrolling” direction (trackpads, some mice). (Documented alongside wheel event construction in Qt docs.) [3]Qt 6: if you truly need device-based detection, use the pointing device (not
source())In Qt 6,
QWheelEventcarries aQPointingDevice* device, and Qt documents that for touchpad-originated wheel eventsdevice()->type()will beQInputDevice::DeviceType::Touchpad. [3]That’s the closest Qt provides to an explicit “this was a touchpad” classification; availability/accuracy still depends on platform backend/device discovery, but it’s the intended API in Qt 6—not
source(). [1], [3]Practical rule of thumb (best portability):
pixelDelta()!=QPoint(0,0)as “smooth/pixel scrolling” (often touchpad / precision scrolling), and otherwise treat it as a wheel. [3]device()->type()==Touchpadonly as an optional refinement in Qt 6. [3]Sources:
[1] Qt blog (“Input Events in Qt 6”) on why
QMouseEvent::source()was misleading for inferring touch origin (qt.io)[2] StackOverflow report that both real mouse wheel and touchpad can show
MouseEventSynthesizedBySystem(stackoverflow.com)[3]
QWheelEventdocs (Qt 6) includingpixelDelta/angleDelta/phase/source/device()and note aboutdevice()->type()==Touchpad(doc.qt.io)[4] Qt 5.7 changelog note:
QWheelEvent::phase()returnsNoScrollPhasefor non-phase-aware mice (sources.debian.org)Citations:
🏁 Script executed:
# Find and examine SpaceCamera.cpp around lines 229-234 fd SpaceCamera.cpp --type fRepository: fernandotonon/QtMeshEditor
Length of output: 89
🏁 Script executed:
# Get the size and examine the wheel event handling context wc -l src/SpaceCamera.cppRepository: fernandotonon/QtMeshEditor
Length of output: 93
🏁 Script executed:
Repository: fernandotonon/QtMeshEditor
Length of output: 1976
🏁 Script executed:
Repository: fernandotonon/QtMeshEditor
Length of output: 226
🏁 Script executed:
Repository: fernandotonon/QtMeshEditor
Length of output: 187
🏁 Script executed:
Repository: fernandotonon/QtMeshEditor
Length of output: 1502
Touchpad detection via
MouseEventSynthesizedBySystemis unreliable; use pixel-delta as fallback.Qt's
MouseEventSynthesizedBySystemflag is not reliable for distinguishing touchpad events across macOS, Windows, and Linux—both real mouse wheel and touchpad scroll can report it, and some platforms may not set it at all. This causes touchpad scrolling to incorrectly fall through to zoom (line 238) instead of panning.Harden detection by checking for high-resolution scrolling:
Fix: Add pixel-delta fallback
Qt 6 (which this project uses) documents that
pixelDelta()indicates high-resolution/touch-like scrolling (typically trackpad), whileangleDelta()is traditional wheel "steps." Falling back to pixel-delta detection ensures portable touchpad handling.🤖 Prompt for AI Agents