FreeCAD

Форк
0
/
MouseSelection.cpp 
677 строк · 19.2 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net>     *
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

25
#ifndef _PreComp_
26
#include <QPixmap>
27
#include <QMenu>
28
#include <Inventor/SbBox.h>
29
#include <Inventor/events/SoEvent.h>
30
#include <Inventor/events/SoKeyboardEvent.h>
31
#include <Inventor/events/SoLocation2Event.h>
32
#include <Inventor/events/SoMouseButtonEvent.h>
33
#endif
34

35
#include "MouseSelection.h"
36
#include "View3DInventorViewer.h"
37

38

39
using namespace Gui;
40

41
AbstractMouseSelection::AbstractMouseSelection()
42
{
43
    m_iXold = 0;
44
    m_iYold = 0;
45
    m_iXnew = 0;
46
    m_iYnew = 0;
47
    m_selectedRole = SelectionRole::None;
48
}
49

50
void AbstractMouseSelection::grabMouseModel(Gui::View3DInventorViewer* viewer)
51
{
52
    _pcView3D = viewer;
53
    m_cPrevCursor = _pcView3D->getWidget()->cursor();
54

55
    // do initialization of your mousemodel
56
    initialize();
57
}
58

59
void AbstractMouseSelection::releaseMouseModel(bool abort)
60
{
61
    if (_pcView3D) {
62
        // do termination of your mousemodel
63
        terminate(abort);
64

65
        _pcView3D->getWidget()->setCursor(m_cPrevCursor);
66
        _pcView3D = nullptr;
67
    }
68
}
69

70

71
int AbstractMouseSelection::handleEvent(const SoEvent* const ev, const SbViewportRegion& vp)
72
{
73
    int ret = Continue;
74

75
    const SbVec2s& sz = vp.getWindowSize();
76
    short w, h;
77
    sz.getValue(w, h);
78

79
    SbVec2s loc = ev->getPosition();
80
    short x, y;
81
    loc.getValue(x, y);
82
    y = h - y;  // the origin is at the left bottom corner (instead of left top corner)
83

84
    if (ev->getTypeId().isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
85
        const auto event = (const SoMouseButtonEvent*)ev;
86
        const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
87

88
        if (press) {
89
            _clPoly.push_back(ev->getPosition());
90
            ret = mouseButtonEvent(static_cast<const SoMouseButtonEvent*>(ev), QPoint(x, y));
91
        }
92
        else {
93
            ret = mouseButtonEvent(static_cast<const SoMouseButtonEvent*>(ev), QPoint(x, y));
94
        }
95
    }
96
    else if (ev->getTypeId().isDerivedFrom(SoLocation2Event::getClassTypeId())) {
97
        ret = locationEvent(static_cast<const SoLocation2Event*>(ev), QPoint(x, y));
98
    }
99
    else if (ev->getTypeId().isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
100
        ret = keyboardEvent(static_cast<const SoKeyboardEvent*>(ev));
101
    }
102

103
    if (ret == Restart) {
104
        _clPoly.clear();
105
    }
106

107
    return ret;
108
}
109

110
// -----------------------------------------------------------------------------------
111

112
BaseMouseSelection::BaseMouseSelection()
113
    : AbstractMouseSelection()
114
{}
115

116
// clang-format off
117
static const char* cursor_cut_scissors[]= {
118
    "32 32 6 1",
119
    "a c #800000",
120
    "c c #808080",
121
    "+ c #c0c0c0",
122
    "b c #ff0000",
123
    "# c #ffffff",
124
    ". c None",
125
    "....#...........................",
126
    "....#...........................",
127
    "....#...........................",
128
    "................................",
129
    "###.#.###.......................",
130
    "................................",
131
    "....#...........................",
132
    "....#...................aaaaa...",
133
    "....#.................aabbbbba..",
134
    ".....................abbbbbbba..",
135
    ".....ccc............abbaaaaabb..",
136
    "....cc++cc.........babaa...aba..",
137
    "...c+#++++cc.......abba...abba..",
138
    "...cc+#+++++c......abba.aabbaa..",
139
    ".....c+++++#+cc....abbaaabbaa...",
140
    "......cc+#+++#+cc.aabbbbbbaa....",
141
    "........cc+#+++#+cabbbaaaa......",
142
    "..........c+++++++abbaa.........",
143
    "...........cc+++#+aaaa..........",
144
    "...........cc+#+++caa...........",
145
    ".........cc+++++#+cbbaaaaa......",
146
    "........cc+#+++#+cabbabbbaaa....",
147
    "......cc+#+++#+cc.aaabbbbbbaa...",
148
    "....cc+#+++#+cc....abbaaaabba...",
149
    "...c++#++#+cc......abba..aabba..",
150
    "...c+###++c........aabaa..aaba..",
151
    "....cc++cc..........abbaa..aba..",
152
    "......c.............aabbaaaaba..",
153
    ".....................baabbbbba..",
154
    ".......................aaaaaa...",
155
    "................................",
156
    "................................"
157
};
158
// clang-format on
159

160
PolyPickerSelection::PolyPickerSelection()
161
{
162
    lastConfirmed = false;
163
}
164

165
void PolyPickerSelection::setColor(float r, float g, float b, float a)
166
{
167
    polyline.setColor(r, g, b, a);
168
}
169

170
void PolyPickerSelection::setLineWidth(float l)
171
{
172
    polyline.setLineWidth(l);
173
}
174

175
void PolyPickerSelection::initialize()
176
{
177
    QPixmap p(cursor_cut_scissors);
178
    QCursor cursor(p, 4, 4);
179
    _pcView3D->getWidget()->setCursor(cursor);
180

181
    polyline.setViewer(_pcView3D);
182

183
    _pcView3D->addGraphicsItem(&polyline);
184
    _pcView3D->redraw();  // needed to get an up-to-date image
185
    _pcView3D->setRenderType(View3DInventorViewer::Image);
186
    _pcView3D->redraw();
187

188
    lastConfirmed = false;
189
}
190

191
void PolyPickerSelection::terminate(bool abort)
192
{
193
    Q_UNUSED(abort)
194

195
    _pcView3D->removeGraphicsItem(&polyline);
196
    _pcView3D->setRenderType(View3DInventorViewer::Native);
197
    _pcView3D->redraw();
198
}
199

200
void PolyPickerSelection::draw()
201
{
202
    _pcView3D->redraw();
203
}
204

205
PolyPickerSelection::~PolyPickerSelection() = default;
206

207
int PolyPickerSelection::popupMenu()
208
{
209
    QMenu menu;
210
    QAction* fi = menu.addAction(QObject::tr("Finish"));
211
    menu.addAction(QObject::tr("Clear"));
212
    QAction* ca = menu.addAction(QObject::tr("Cancel"));
213

214
    if (getPositions().size() < 3) {
215
        fi->setEnabled(false);
216
    }
217

218
    QAction* id = menu.exec(QCursor::pos());
219

220
    if (id == fi) {
221
        return Finish;
222
    }
223
    else if (id == ca) {
224
        return Cancel;
225
    }
226
    else {
227
        return Restart;
228
    }
229
}
230

231
int PolyPickerSelection::mouseButtonEvent(const SoMouseButtonEvent* const e, const QPoint& pos)
232
{
233
    const int button = e->getButton();
234
    const SbBool press = e->getState() == SoButtonEvent::DOWN ? true : false;
235

236
    if (press) {
237
        switch (button) {
238
            case SoMouseButtonEvent::BUTTON1: {
239
                if (!polyline.isWorking()) {
240
                    polyline.setWorking(true);
241
                    polyline.clear();
242
                };
243
                polyline.addNode(pos);
244
                lastConfirmed = true;
245
                m_iXnew = pos.x();
246
                m_iYnew = pos.y();
247
                m_iXold = pos.x();
248
                m_iYold = pos.y();
249
            } break;
250

251
            case SoMouseButtonEvent::BUTTON2: {
252
                polyline.addNode(pos);
253
                m_iXnew = pos.x();
254
                m_iYnew = pos.y();
255
                m_iXold = pos.x();
256
                m_iYold = pos.y();
257
            } break;
258

259
            default: {
260
            } break;
261
        }
262
    }
263
    // release
264
    else {
265
        switch (button) {
266
            case SoMouseButtonEvent::BUTTON2: {
267
                QCursor cur = _pcView3D->getWidget()->cursor();
268
                _pcView3D->getWidget()->setCursor(m_cPrevCursor);
269

270
                // The pop-up menu should be shown when releasing mouse button because
271
                // otherwise the navigation style doesn't get the UP event and gets into
272
                // an inconsistent state.
273
                int id = popupMenu();
274

275
                if (id == Finish || id == Cancel) {
276
                    releaseMouseModel();
277
                }
278
                else if (id == Restart) {
279
                    _pcView3D->getWidget()->setCursor(cur);
280
                }
281

282
                polyline.setWorking(false);
283
                return id;
284
            } break;
285

286
            default: {
287
            } break;
288
        }
289
    }
290

291
    return Continue;
292
}
293

294
int PolyPickerSelection::locationEvent(const SoLocation2Event* const, const QPoint& pos)
295
{
296
    // do all the drawing stuff for us
297
    QPoint clPoint = pos;
298

299
    if (polyline.isWorking()) {
300
        // check the position
301
        qreal dpr = _pcView3D->getGLWidget()->devicePixelRatioF();
302
        QRect r = _pcView3D->getGLWidget()->rect();
303
        if (dpr != 1.0) {
304
            r.setHeight(r.height() * dpr);
305
            r.setWidth(r.width() * dpr);
306
        }
307

308
        if (!r.contains(clPoint)) {
309
            if (clPoint.x() < r.left()) {
310
                clPoint.setX(r.left());
311
            }
312

313
            if (clPoint.x() > r.right()) {
314
                clPoint.setX(r.right());
315
            }
316

317
            if (clPoint.y() < r.top()) {
318
                clPoint.setY(r.top());
319
            }
320

321
            if (clPoint.y() > r.bottom()) {
322
                clPoint.setY(r.bottom());
323
            }
324

325
#ifdef FC_OS_WINDOWS
326
            QPoint newPos = _pcView3D->getGLWidget()->mapToGlobal(clPoint);
327
            QCursor::setPos(newPos);
328
#endif
329
        }
330

331
        if (!lastConfirmed) {
332
            polyline.popNode();
333
        }
334
        polyline.addNode(clPoint);
335
        lastConfirmed = false;
336

337
        draw();
338
    }
339

340
    m_iXnew = clPoint.x();
341
    m_iYnew = clPoint.y();
342

343
    return Continue;
344
}
345

346
int PolyPickerSelection::keyboardEvent(const SoKeyboardEvent* const)
347
{
348
    return Continue;
349
}
350

351
// -----------------------------------------------------------------------------------
352

353
PolyClipSelection::PolyClipSelection()
354
{
355
    selectionBits.set(1);
356
    selectionBits.set(2);
357
}
358

359
PolyClipSelection::~PolyClipSelection() = default;
360

361
int PolyClipSelection::popupMenu()
362
{
363
    QMenu menu;
364
    QAction* ci = menu.addAction(QObject::tr("Inner"));
365
    QAction* co = menu.addAction(QObject::tr("Outer"));
366
    QAction* cs = menu.addAction(QObject::tr("Split"));
367
    QAction* ca = menu.addAction(QObject::tr("Cancel"));
368

369
    ci->setVisible(testRole(SelectionRole::Inner));
370
    co->setVisible(testRole(SelectionRole::Outer));
371
    cs->setVisible(testRole(SelectionRole::Split));
372

373
    if (getPositions().size() < 3) {
374
        ci->setEnabled(false);
375
        co->setEnabled(false);
376
    }
377

378
    QAction* id = menu.exec(QCursor::pos());
379

380
    if (id == ci) {
381
        m_selectedRole = SelectionRole::Inner;
382
        return Finish;
383
    }
384
    else if (id == co) {
385
        m_selectedRole = SelectionRole::Outer;
386
        return Finish;
387
    }
388
    else if (id == cs) {
389
        m_selectedRole = SelectionRole::Split;
390
        return Finish;
391
    }
392
    else if (id == ca) {
393
        m_selectedRole = SelectionRole::None;
394
        return Cancel;
395
    }
396
    else {
397
        m_selectedRole = SelectionRole::None;
398
        return Restart;
399
    }
400
}
401

402
// -----------------------------------------------------------------------------------
403

404
FreehandSelection::FreehandSelection() = default;
405

406
FreehandSelection::~FreehandSelection() = default;
407

408
void FreehandSelection::setClosed(bool on)
409
{
410
    polyline.setClosed(on);
411
    polyline.setCloseStippled(true);
412
}
413

414
int FreehandSelection::popupMenu()
415
{
416
    QMenu menu;
417
    QAction* fi = menu.addAction(QObject::tr("Finish"));
418
    menu.addAction(QObject::tr("Clear"));
419
    QAction* ca = menu.addAction(QObject::tr("Cancel"));
420

421
    if (getPositions().size() < 3) {
422
        fi->setEnabled(false);
423
    }
424

425
    QAction* id = menu.exec(QCursor::pos());
426
    if (id == fi) {
427
        return Finish;
428
    }
429
    else if (id == ca) {
430
        return Cancel;
431
    }
432
    else {
433
        return Restart;
434
    }
435
}
436

437
int FreehandSelection::mouseButtonEvent(const SoMouseButtonEvent* const e, const QPoint& pos)
438
{
439
    const int button = e->getButton();
440
    const SbBool press = e->getState() == SoButtonEvent::DOWN ? true : false;
441

442
    if (press) {
443
        switch (button) {
444
            case SoMouseButtonEvent::BUTTON1: {
445
                if (!polyline.isWorking()) {
446
                    polyline.setWorking(true);
447
                    polyline.clear();
448
                }
449

450
                polyline.addNode(pos);
451
                polyline.setCoords(pos.x(), pos.y());
452
                m_iXnew = pos.x();
453
                m_iYnew = pos.y();
454
                m_iXold = pos.x();
455
                m_iYold = pos.y();
456
            } break;
457

458
            case SoMouseButtonEvent::BUTTON2: {
459
                polyline.addNode(pos);
460
                m_iXnew = pos.x();
461
                m_iYnew = pos.y();
462
                m_iXold = pos.x();
463
                m_iYold = pos.y();
464
            } break;
465

466
            default:
467
                break;
468
        }
469
    }
470
    // release
471
    else {
472
        switch (button) {
473
            case SoMouseButtonEvent::BUTTON1:
474
                if (polyline.isWorking()) {
475
                    releaseMouseModel();
476
                    return Finish;
477
                }
478
                break;
479
            case SoMouseButtonEvent::BUTTON2: {
480
                QCursor cur = _pcView3D->getWidget()->cursor();
481
                _pcView3D->getWidget()->setCursor(m_cPrevCursor);
482

483
                // The pop-up menu should be shown when releasing mouse button because
484
                // otherwise the navigation style doesn't get the UP event and gets into
485
                // an inconsistent state.
486
                int id = popupMenu();
487

488
                if (id == Finish || id == Cancel) {
489
                    releaseMouseModel();
490
                }
491
                else if (id == Restart) {
492
                    _pcView3D->getWidget()->setCursor(cur);
493
                }
494

495
                polyline.setWorking(false);
496
                return id;
497
            } break;
498

499
            default:
500
                break;
501
        }
502
    }
503

504
    return Continue;
505
}
506

507
int FreehandSelection::locationEvent(const SoLocation2Event* const e, const QPoint& pos)
508
{
509
    // do all the drawing stuff for us
510
    QPoint clPoint = pos;
511

512
    if (polyline.isWorking()) {
513
        // check the position
514
        qreal dpr = _pcView3D->getGLWidget()->devicePixelRatioF();
515
        QRect r = _pcView3D->getGLWidget()->rect();
516
        if (dpr != 1.0) {
517
            r.setHeight(r.height() * dpr);
518
            r.setWidth(r.width() * dpr);
519
        }
520

521
        if (!r.contains(clPoint)) {
522
            if (clPoint.x() < r.left()) {
523
                clPoint.setX(r.left());
524
            }
525

526
            if (clPoint.x() > r.right()) {
527
                clPoint.setX(r.right());
528
            }
529

530
            if (clPoint.y() < r.top()) {
531
                clPoint.setY(r.top());
532
            }
533

534
            if (clPoint.y() > r.bottom()) {
535
                clPoint.setY(r.bottom());
536
            }
537
        }
538

539
        SbVec2s last = _clPoly.back();
540
        SbVec2s curr = e->getPosition();
541

542
        if (abs(last[0] - curr[0]) > 20 || abs(last[1] - curr[1]) > 20) {
543
            _clPoly.push_back(curr);
544
        }
545

546
        polyline.addNode(clPoint);
547
        polyline.setCoords(clPoint.x(), clPoint.y());
548
    }
549

550
    m_iXnew = clPoint.x();
551
    m_iYnew = clPoint.y();
552
    draw();
553
    m_iXold = clPoint.x();
554
    m_iYold = clPoint.y();
555

556
    return Continue;
557
}
558

559
// -----------------------------------------------------------------------------------
560

561
RubberbandSelection::RubberbandSelection()
562
{
563
    rubberband.setColor(1.0, 1.0, 0.0, 0.5);
564
}
565

566
RubberbandSelection::~RubberbandSelection() = default;
567

568
void RubberbandSelection::setColor(float r, float g, float b, float a)
569
{
570
    rubberband.setColor(r, g, b, a);
571
}
572

573
void RubberbandSelection::initialize()
574
{
575
    rubberband.setViewer(_pcView3D);
576
    rubberband.setWorking(false);
577
    _pcView3D->addGraphicsItem(&rubberband);
578
    if (QtGLFramebufferObject::hasOpenGLFramebufferObjects()) {
579
        _pcView3D->setRenderType(View3DInventorViewer::Image);
580
    }
581
    _pcView3D->redraw();
582
}
583

584
void RubberbandSelection::terminate(bool abort)
585
{
586
    Q_UNUSED(abort)
587

588
    _pcView3D->removeGraphicsItem(&rubberband);
589
    if (QtGLFramebufferObject::hasOpenGLFramebufferObjects()) {
590
        _pcView3D->setRenderType(View3DInventorViewer::Native);
591
    }
592
    _pcView3D->redraw();
593
}
594

595
void RubberbandSelection::draw()
596
{
597
    _pcView3D->redraw();
598
}
599

600
int RubberbandSelection::mouseButtonEvent(const SoMouseButtonEvent* const e, const QPoint& pos)
601
{
602
    const int button = e->getButton();
603
    const SbBool press = e->getState() == SoButtonEvent::DOWN ? true : false;
604

605
    int ret = Continue;
606

607
    if (press) {
608
        switch (button) {
609
            case SoMouseButtonEvent::BUTTON1: {
610
                rubberband.setWorking(true);
611
                m_iXold = m_iXnew = pos.x();
612
                m_iYold = m_iYnew = pos.y();
613
            } break;
614

615
            default: {
616
            } break;
617
        }
618
    }
619
    else {
620
        switch (button) {
621
            case SoMouseButtonEvent::BUTTON1: {
622
                rubberband.setWorking(false);
623
                releaseMouseModel();
624
                _clPoly.push_back(e->getPosition());
625
                ret = Finish;
626
            } break;
627

628
            default: {
629
            } break;
630
        }
631
    }
632

633
    return ret;
634
}
635

636
int RubberbandSelection::locationEvent(const SoLocation2Event* const, const QPoint& pos)
637
{
638
    m_iXnew = pos.x();
639
    m_iYnew = pos.y();
640
    rubberband.setCoords(m_iXold, m_iYold, m_iXnew, m_iYnew);
641
    draw();
642
    return Continue;
643
}
644

645
int RubberbandSelection::keyboardEvent(const SoKeyboardEvent* const)
646
{
647
    return Continue;
648
}
649

650
// -----------------------------------------------------------------------------------
651

652
RectangleSelection::RectangleSelection()
653
    : RubberbandSelection()
654
{
655
    rubberband.setColor(0.0, 0.0, 1.0, 1.0);
656
}
657

658
RectangleSelection::~RectangleSelection() = default;
659

660
// -----------------------------------------------------------------------------------
661

662
BoxZoomSelection::BoxZoomSelection() = default;
663

664
BoxZoomSelection::~BoxZoomSelection() = default;
665

666
void BoxZoomSelection::terminate(bool abort)
667
{
668
    RubberbandSelection::terminate(abort);
669
    if (!abort) {
670
        int xmin = std::min<int>(m_iXold, m_iXnew);
671
        int xmax = std::max<int>(m_iXold, m_iXnew);
672
        int ymin = std::min<int>(m_iYold, m_iYnew);
673
        int ymax = std::max<int>(m_iYold, m_iYnew);
674
        SbBox2s box(xmin, ymin, xmax, ymax);
675
        _pcView3D->boxZoom(box);
676
    }
677
}
678

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

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

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

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