/* Copyright 2006-2026 The QElectroTech Team This file is part of QElectroTech. QElectroTech is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. QElectroTech is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with QElectroTech. If not, see . */ #include "spacemousemotion.h" #include #include namespace { //A device deflection is an integer on roughly the same order of //magnitude as a QWheelEvent::angleDelta() tick (about +-120 per //detent, more under a hard push/twist -- exact range depends on the //backend and the driver's own sensitivity). DiagramView::wheelEvent() //turns such a tick into a zoom step of about 1 + value/1000, reused //here as a starting point. // //Neither constant has been calibrated against real hardware; the //user-facing speed settings scale both. constexpr qreal ZOOM_DIVISOR = 1000.0; constexpr qreal PAN_SCALE = 1.0; const QString GROUP = QStringLiteral("spacemouse/motion/"); } /** @brief SpaceMouseSettings::load @return the settings saved by the configuration page, or the defaults */ SpaceMouseSettings SpaceMouseSettings::load() { QSettings settings; SpaceMouseSettings s; s.pan_speed = settings.value(GROUP + "pan_speed", s.pan_speed).toInt(); s.zoom_speed = settings.value(GROUP + "zoom_speed", s.zoom_speed).toInt(); s.dead_zone = settings.value(GROUP + "dead_zone", s.dead_zone).toInt(); s.invert_pan_x = settings.value(GROUP + "invert_pan_x", s.invert_pan_x).toBool(); s.invert_pan_y = settings.value(GROUP + "invert_pan_y", s.invert_pan_y).toBool(); s.invert_zoom = settings.value(GROUP + "invert_zoom", s.invert_zoom).toBool(); s.zoom_axis = settings.value(GROUP + "zoom_axis").toString() == QLatin1String("twist") ? ZoomAxis::Twist : ZoomAxis::PushPull; return s; } /** @brief SpaceMouseSettings::save */ void SpaceMouseSettings::save() const { QSettings settings; settings.setValue(GROUP + "pan_speed", pan_speed); settings.setValue(GROUP + "zoom_speed", zoom_speed); settings.setValue(GROUP + "dead_zone", dead_zone); settings.setValue(GROUP + "invert_pan_x", invert_pan_x); settings.setValue(GROUP + "invert_pan_y", invert_pan_y); settings.setValue(GROUP + "invert_zoom", invert_zoom); settings.setValue(GROUP + "zoom_axis", zoom_axis == ZoomAxis::Twist ? QStringLiteral("twist") : QStringLiteral("push_pull")); } bool SpaceMouseSettings::operator==(const SpaceMouseSettings &other) const { return pan_speed == other.pan_speed && zoom_speed == other.zoom_speed && dead_zone == other.dead_zone && invert_pan_x == other.invert_pan_x && invert_pan_y == other.invert_pan_y && invert_zoom == other.invert_zoom && zoom_axis == other.zoom_axis; } /** @brief SpaceMouseMotion::stepFor @param elapsed_ms @return see the declaration */ qreal SpaceMouseMotion::stepFor(qint64 elapsed_ms) { if (elapsed_ms < 0 || elapsed_ms > MAX_PERIOD_MS) { return 1.0; } return elapsed_ms / NOMINAL_PERIOD_MS; } /** @brief SpaceMouseMotion::applyDeadZone @param value @param dead_zone @return see the declaration */ int SpaceMouseMotion::applyDeadZone(int value, int dead_zone) { if (dead_zone <= 0) { return value; } if (qAbs(value) <= dead_zone) { return 0; } return value > 0 ? value - dead_zone : value + dead_zone; } /** @brief SpaceMouseMotion::map Pan is a scrollbar delta: pushing the cap right moves the drawing right, so the scrollbar goes the other way, as in DiagramView::wheelEvent(). Zoom is exponential in the deflection, so the factor is always positive and an equal push and pull cancel out exactly. @param sample @param elapsed_ms @param settings @return see the declaration */ SpaceMouseViewMotion SpaceMouseMotion::map(const SpaceMouseSample &sample, qint64 elapsed_ms, const SpaceMouseSettings &settings) { const qreal step = stepFor(elapsed_ms); const int x = applyDeadZone(sample.x, settings.dead_zone); const int y = applyDeadZone(sample.y, settings.dead_zone); const int zoom_value = applyDeadZone( settings.zoom_axis == SpaceMouseSettings::ZoomAxis::Twist ? sample.rz : sample.z, settings.dead_zone); const qreal pan = PAN_SCALE * settings.pan_speed / 100.0 * step; const qreal zoom = settings.zoom_speed / 100.0 / ZOOM_DIVISOR * step; SpaceMouseViewMotion motion; motion.scroll_x = -x * pan * (settings.invert_pan_x ? -1 : 1); motion.scroll_y = -y * pan * (settings.invert_pan_y ? -1 : 1); motion.zoom_factor = qExp(zoom_value * zoom * (settings.invert_zoom ? -1 : 1)); return motion; }