FreeCAD

Форк
0
/
QGVNavStyle.cpp 
463 строки · 13.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2022 Wanderer Fan <wandererfan@gmail.com>               *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
#include <QContextMenuEvent>
26
#include <QKeyEvent>
27
#include <QScrollBar>
28
#endif
29

30
#include <App/Application.h>
31
#include <Base/Parameter.h>
32
#include <Mod/TechDraw/App/DrawPage.h>
33
#include <Mod/TechDraw/App/Preferences.h>
34

35
#include "QGSPage.h"
36
#include "QGVNavStyle.h"
37
#include "QGVPage.h"
38

39

40
using namespace TechDraw;
41
using namespace TechDrawGui;
42

43
namespace TechDrawGui
44
{
45

46
QGVNavStyle::QGVNavStyle(QGVPage* qgvp) : m_viewer(qgvp) { initialize(); }
47

48
QGVNavStyle::~QGVNavStyle() {}
49

50
void QGVNavStyle::initialize()
51
{
52
    this->button1down = false;
53
    this->button2down = false;
54
    this->button3down = false;
55
    this->ctrldown = false;
56
    this->shiftdown = false;
57
    this->altdown = false;
58
    this->invertZoom = App::GetApplication()
59
                           .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View")
60
                           ->GetBool("InvertZoom", true);
61
    this->zoomAtCursor = App::GetApplication()
62
                             .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View")
63
                             ->GetBool("ZoomAtCursor", true);
64
    this->zoomStep = App::GetApplication()
65
                         .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View")
66
                         ->GetFloat("ZoomStep", 0.2f);
67

68
    m_reversePan = Preferences::getPreferenceGroup("General")->GetInt("KbPan", 1);
69
    m_reverseScroll = Preferences::getPreferenceGroup("General")->GetInt("KbScroll", 1);
70

71
    panningActive = false;
72
    zoomingActive = false;
73
    m_clickPending = false;
74
    m_panPending = false;
75
    m_zoomPending = false;
76
    m_clickButton = Qt::NoButton;
77
    m_saveCursor = getViewer()->cursor();
78
    m_wheelDeltaCounter = 0;
79
    m_mouseDeltaCounter = 0;
80
}
81

82
void QGVNavStyle::setAnchor()
83
{
84
    if (m_viewer) {
85
        if (zoomAtCursor) {
86
            m_viewer->setResizeAnchor(QGraphicsView::AnchorUnderMouse);
87
            m_viewer->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
88
        }
89
        else {
90
            m_viewer->setResizeAnchor(QGraphicsView::AnchorViewCenter);
91
            m_viewer->setTransformationAnchor(QGraphicsView::AnchorViewCenter);
92
        }
93
    }
94
}
95

96
void QGVNavStyle::handleEnterEvent(QEvent* event)
97
{
98
    Q_UNUSED(event);
99
    if (getViewer()->isBalloonPlacing()) {
100
        getViewer()->getBalloonCursor()->hide();
101
    }
102
}
103

104
void QGVNavStyle::handleFocusOutEvent(QFocusEvent* event)
105
{
106
    Q_UNUSED(event);
107
    getViewer()->cancelBalloonPlacing();
108
}
109

110
void QGVNavStyle::handleKeyPressEvent(QKeyEvent* event)
111
{
112
    // Base::Console().Message("QGNS::handleKeyPressEvent(%d)\n", event->key());
113
    if (event->modifiers().testFlag(Qt::ControlModifier)) {
114
        switch (event->key()) {
115
            case Qt::Key_Plus: {
116
                zoomIn();
117
                event->accept();
118
                return;
119
            }
120
            case Qt::Key_Minus: {
121
                zoomOut();
122
                event->accept();
123
                return;
124
            }
125
            default: {
126
                return;
127
            }
128
        }
129
    }
130

131
    if (event->modifiers().testFlag(Qt::NoModifier)) {
132
        switch (event->key()) {
133
            case Qt::Key_Left: {
134
                getViewer()->kbPanScroll(1, 0);
135
                event->accept();
136
                return;
137
            }
138
            case Qt::Key_Up: {
139
                getViewer()->kbPanScroll(0, 1);
140
                event->accept();
141
                return;
142
            }
143
            case Qt::Key_Right: {
144
                getViewer()->kbPanScroll(-1, 0);
145
                event->accept();
146
                return;
147
            }
148
            case Qt::Key_Down: {
149
                getViewer()->kbPanScroll(0, -1);
150
                event->accept();
151
                return;
152
            }
153
            case Qt::Key_Escape: {
154
                getViewer()->cancelBalloonPlacing();
155
                event->accept();
156
                return;
157
            }
158
            case Qt::Key_Shift: {
159
                this->shiftdown = true;
160
                event->accept();
161
                return;
162
            }
163
            default: {
164
                return;
165
            }
166
        }
167
    }
168
    event->ignore();
169
}
170

171
void QGVNavStyle::handleKeyReleaseEvent(QKeyEvent* event)
172
{
173
    if (event->modifiers().testFlag(Qt::NoModifier)) {
174
        switch (event->key()) {
175
            case Qt::Key_Shift: {
176
                this->shiftdown = false;
177
                event->accept();
178
                break;
179
            }
180
            default: {
181
                break;
182
            }
183
        }
184
    }
185
}
186

187
void QGVNavStyle::handleLeaveEvent(QEvent* event)
188
{
189
    Q_UNUSED(event);
190
    if (getViewer()->isBalloonPlacing()) {
191
        int left_x;
192
        if (getViewer()->getBalloonCursorPos().x() < 32)
193
            left_x = 0;
194
        else if (getViewer()->getBalloonCursorPos().x()
195
                 > (getViewer()->contentsRect().right() - 32))
196
            left_x = getViewer()->contentsRect().right() - 32;
197
        else
198
            left_x = getViewer()->getBalloonCursorPos().x();
199

200
        int left_y;
201
        if (getViewer()->getBalloonCursorPos().y() < 32)
202
            left_y = 0;
203
        else if (getViewer()->getBalloonCursorPos().y()
204
                 > (getViewer()->contentsRect().bottom() - 32))
205
            left_y = getViewer()->contentsRect().bottom() - 32;
206
        else
207
            left_y = getViewer()->getBalloonCursorPos().y();
208

209
        /* When cursor leave the page, display getViewer()->balloonCursor where it left */
210
        getViewer()->getBalloonCursor()->setGeometry(left_x, left_y, 32, 32);
211
        getViewer()->getBalloonCursor()->show();
212
    }
213
}
214

215
void QGVNavStyle::handleMousePressEvent(QMouseEvent* event)
216
{
217
    // Base::Console().Message("QGVNS::handleMousePressEvent()\n");
218
    if (!panningActive && (event->button() == Qt::MiddleButton)) {
219
        startPan(event->pos());
220
        event->accept();
221
    }
222
}
223

224
void QGVNavStyle::handleMouseMoveEvent(QMouseEvent* event)
225
{
226
    //    Base::Console().Message("QGVNS::handleMouseMoveEvent()\n");
227
    if (getViewer()->isBalloonPlacing()) {
228
        balloonCursorMovement(event);
229
        return;
230
    }
231

232
    if (panningActive) {
233
        pan(event->pos());
234
        event->accept();
235
    }
236
}
237

238
//NOTE: QGraphicsView::contextMenuEvent consumes the mouse release event for the
239
//button that caused the event (typically RMB)
240
void QGVNavStyle::handleMouseReleaseEvent(QMouseEvent* event)
241
{
242
    //    Base::Console().Message("QGVNS::handleMouseReleaseEvent()\n");
243
    if (getViewer()->isBalloonPlacing()) {
244
        placeBalloon(event->pos());
245
    }
246

247
    if (panningActive && (event->button() == Qt::MiddleButton)) {
248
        stopPan();
249
        event->accept();
250
    }
251
}
252

253
bool QGVNavStyle::allowContextMenu(QContextMenuEvent* event)
254
{
255
    Q_UNUSED(event)
256
    //    Base::Console().Message("QGVNS::allowContextMenu()\n");
257
    //    if (event->reason() == QContextMenuEvent::Mouse) {
258
    //        //must check for a button combination involving context menu button
259
    //    }
260
    return true;
261
}
262

263
void QGVNavStyle::pseudoContextEvent() { getViewer()->pseudoContextEvent(); }
264

265
void QGVNavStyle::handleWheelEvent(QWheelEvent* event)
266
{
267
    //gets called once for every click of the wheel. the sign of event->angleDelta().y()
268
    //gives the direction of wheel rotation. positive indicates rotation forwards away
269
    //from the user; negative backwards toward the user. the magnitude of
270
    //event->angleDelta().y() is 120 for most mice which represents 120/8 = 15 degrees of
271
    //rotation. Some high resolution mice/trackpads report smaller values - ie a click is less than
272
    //15 degrees of wheel rotation.
273
    //https://doc.qt.io/qt-5/qwheelevent.html#angleDelta
274
    //to avoid overly sensitive behaviour in high resolution mice/touchpads,
275
    //save up wheel clicks until the wheel has rotated at least 15 degrees.
276
    constexpr int wheelDeltaThreshold = 120;
277
    m_wheelDeltaCounter += std::abs(event->angleDelta().y());
278
    if (m_wheelDeltaCounter < wheelDeltaThreshold) {
279
        return;
280
    }
281
    m_wheelDeltaCounter = 0;
282
    //starting with -ve direction keeps us in sync with the behaviour of the 3d window
283
    int rotationDirection = -event->angleDelta().y() / std::abs(event->angleDelta().y());
284
    if (invertZoom) {
285
        rotationDirection = -rotationDirection;
286
    }
287
    double zoomFactor = 1 + rotationDirection * zoomStep;
288
    zoom(zoomFactor);
289
}
290

291
void QGVNavStyle::zoom(double factor)
292
{
293
    constexpr double minimumScale(0.01);
294
    QTransform transform = getViewer()->transform();
295
    double xScale = transform.m11();
296
    if (xScale <= minimumScale && factor < 1.0) {
297
        //don't scale any smaller than this
298
        return;
299
    }
300

301
    setAnchor();
302
    getViewer()->scale(factor, factor);
303
    m_zoomPending = false;
304
}
305

306
void QGVNavStyle::startZoom(QPoint p)
307
{
308
    //    Base::Console().Message("QGVNS::startZoom(%s)\n", TechDraw::DrawUtil::formatVector(p).c_str());
309
    zoomOrigin = p;
310
    zoomingActive = true;
311
    m_zoomPending = false;
312
    getViewer()->setZoomCursor();
313
}
314

315
void QGVNavStyle::stopZoom()
316
{
317
    //    Base::Console().Message("QGVNS::stopZoom()\n");
318
    zoomingActive = false;
319
    m_zoomPending = false;
320
    getViewer()->resetCursor();
321
}
322

323
double QGVNavStyle::mouseZoomFactor(QPoint p)
324
{
325
    constexpr int threshold(20);
326
    int verticalTravel = (p - zoomOrigin).y();
327
    m_mouseDeltaCounter += std::abs(verticalTravel);
328
    if (m_mouseDeltaCounter < threshold) {
329
        //do not zoom yet
330
        return 1.0;
331
    }
332
    m_mouseDeltaCounter = 0;
333
    double direction = verticalTravel / std::abs(verticalTravel);
334
    if (invertZoom) {
335
        direction = -direction;
336
    }
337
    double factor = 1.0 + (direction * zoomStep);
338
    zoomOrigin = p;
339
    return factor;
340
}
341

342
void QGVNavStyle::zoomIn()
343
{
344
    zoom(1.0 + zoomStep);
345
}
346

347
void QGVNavStyle::zoomOut()
348
{
349
    zoom(1.0 - zoomStep);
350
}
351

352
void QGVNavStyle::startPan(QPoint p)
353
{
354
    panOrigin = p;
355
    panningActive = true;
356
    m_panPending = false;
357
    getViewer()->setPanCursor();
358
}
359

360
void QGVNavStyle::pan(QPoint p)
361
{
362
    QScrollBar* horizontalScrollbar = getViewer()->horizontalScrollBar();
363
    QScrollBar* verticalScrollbar = getViewer()->verticalScrollBar();
364
    QPoint direction = p - panOrigin;
365

366
    horizontalScrollbar->setValue(horizontalScrollbar->value() - m_reversePan * direction.x());
367
    verticalScrollbar->setValue(verticalScrollbar->value() - m_reverseScroll * direction.y());
368

369
    panOrigin = p;
370
}
371

372
void QGVNavStyle::stopPan()
373
{
374
    //    Base::Console().Message("QGVNS::stopPan()\n");
375
    panningActive = false;
376
    m_panPending = false;
377
    getViewer()->resetCursor();
378
}
379

380
void QGVNavStyle::startClick(Qt::MouseButton b)
381
{
382
    m_clickPending = true;
383
    m_clickButton = b;
384
}
385

386
void QGVNavStyle::stopClick()
387
{
388
    m_clickPending = false;
389
    m_clickButton = Qt::MouseButton::NoButton;
390
}
391

392
void QGVNavStyle::placeBalloon(QPoint p)
393
{
394
    //    Base::Console().Message("QGVNS::placeBalloon()\n");
395
    getViewer()->getBalloonCursor()->hide();
396
    //balloon was created in Command.cpp.  Why are we doing it again?
397
    getViewer()->getScene()->createBalloon(getViewer()->mapToScene(p),
398
                                           getViewer()->getBalloonParent());
399
    getViewer()->setBalloonPlacing(false);
400
}
401

402
void QGVNavStyle::balloonCursorMovement(QMouseEvent *event)
403
{
404
    getViewer()->setBalloonCursorPos(event->pos());
405
    event->accept();
406
    return;
407
}
408

409
//****************************************
410
KeyCombination::KeyCombination() {}
411

412
KeyCombination::~KeyCombination() {}
413

414
void KeyCombination::addKey(int inKey)
415
{
416
    bool found = false;
417
    //check for inKey already in keys
418
    if (!keys.empty()) {
419
        for (auto& k : keys) {
420
            if (k == inKey) {
421
                found = true;
422
            }
423
        }
424
    }
425
    if (!found) {
426
        keys.push_back(inKey);
427
    }
428
}
429

430
void KeyCombination::removeKey(int inKey)
431
{
432
    std::vector<int> newKeys;
433
    for (auto& k : keys) {
434
        if (k != inKey) {
435
            newKeys.push_back(k);
436
        }
437
    }
438
    keys = newKeys;
439
}
440

441
void KeyCombination::clear() { keys.clear(); }
442

443
bool KeyCombination::empty() { return keys.empty(); }
444

445
//does inCombo match the keys we have in current combination
446
bool KeyCombination::haveCombination(int inCombo)
447
{
448
    bool matched = false;
449
    int combo = 0;//no key
450
    if (keys.size() < 2) {
451
        //not enough keys for a combination
452
        return false;
453
    }
454
    for (auto& k : keys) {
455
        combo = combo | k;
456
    }
457
    if (combo == inCombo) {
458
        matched = true;
459
    }
460
    return matched;
461
}
462

463
}//namespace TechDrawGui
464

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.