1
/***************************************************************************
2
* Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
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. *
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. *
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 *
21
***************************************************************************/
23
#include "PreCompiled.h"
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>
35
#include "MouseSelection.h"
36
#include "View3DInventorViewer.h"
41
AbstractMouseSelection::AbstractMouseSelection()
47
m_selectedRole = SelectionRole::None;
50
void AbstractMouseSelection::grabMouseModel(Gui::View3DInventorViewer* viewer)
53
m_cPrevCursor = _pcView3D->getWidget()->cursor();
55
// do initialization of your mousemodel
59
void AbstractMouseSelection::releaseMouseModel(bool abort)
62
// do termination of your mousemodel
65
_pcView3D->getWidget()->setCursor(m_cPrevCursor);
71
int AbstractMouseSelection::handleEvent(const SoEvent* const ev, const SbViewportRegion& vp)
75
const SbVec2s& sz = vp.getWindowSize();
79
SbVec2s loc = ev->getPosition();
82
y = h - y; // the origin is at the left bottom corner (instead of left top corner)
84
if (ev->getTypeId().isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
85
const auto event = (const SoMouseButtonEvent*)ev;
86
const SbBool press = event->getState() == SoButtonEvent::DOWN ? true : false;
89
_clPoly.push_back(ev->getPosition());
90
ret = mouseButtonEvent(static_cast<const SoMouseButtonEvent*>(ev), QPoint(x, y));
93
ret = mouseButtonEvent(static_cast<const SoMouseButtonEvent*>(ev), QPoint(x, y));
96
else if (ev->getTypeId().isDerivedFrom(SoLocation2Event::getClassTypeId())) {
97
ret = locationEvent(static_cast<const SoLocation2Event*>(ev), QPoint(x, y));
99
else if (ev->getTypeId().isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
100
ret = keyboardEvent(static_cast<const SoKeyboardEvent*>(ev));
103
if (ret == Restart) {
110
// -----------------------------------------------------------------------------------
112
BaseMouseSelection::BaseMouseSelection()
113
: AbstractMouseSelection()
117
static const char* cursor_cut_scissors[]= {
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
"................................"
160
PolyPickerSelection::PolyPickerSelection()
162
lastConfirmed = false;
165
void PolyPickerSelection::setColor(float r, float g, float b, float a)
167
polyline.setColor(r, g, b, a);
170
void PolyPickerSelection::setLineWidth(float l)
172
polyline.setLineWidth(l);
175
void PolyPickerSelection::initialize()
177
QPixmap p(cursor_cut_scissors);
178
QCursor cursor(p, 4, 4);
179
_pcView3D->getWidget()->setCursor(cursor);
181
polyline.setViewer(_pcView3D);
183
_pcView3D->addGraphicsItem(&polyline);
184
_pcView3D->redraw(); // needed to get an up-to-date image
185
_pcView3D->setRenderType(View3DInventorViewer::Image);
188
lastConfirmed = false;
191
void PolyPickerSelection::terminate(bool abort)
195
_pcView3D->removeGraphicsItem(&polyline);
196
_pcView3D->setRenderType(View3DInventorViewer::Native);
200
void PolyPickerSelection::draw()
205
PolyPickerSelection::~PolyPickerSelection() = default;
207
int PolyPickerSelection::popupMenu()
210
QAction* fi = menu.addAction(QObject::tr("Finish"));
211
menu.addAction(QObject::tr("Clear"));
212
QAction* ca = menu.addAction(QObject::tr("Cancel"));
214
if (getPositions().size() < 3) {
215
fi->setEnabled(false);
218
QAction* id = menu.exec(QCursor::pos());
231
int PolyPickerSelection::mouseButtonEvent(const SoMouseButtonEvent* const e, const QPoint& pos)
233
const int button = e->getButton();
234
const SbBool press = e->getState() == SoButtonEvent::DOWN ? true : false;
238
case SoMouseButtonEvent::BUTTON1: {
239
if (!polyline.isWorking()) {
240
polyline.setWorking(true);
243
polyline.addNode(pos);
244
lastConfirmed = true;
251
case SoMouseButtonEvent::BUTTON2: {
252
polyline.addNode(pos);
266
case SoMouseButtonEvent::BUTTON2: {
267
QCursor cur = _pcView3D->getWidget()->cursor();
268
_pcView3D->getWidget()->setCursor(m_cPrevCursor);
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();
275
if (id == Finish || id == Cancel) {
278
else if (id == Restart) {
279
_pcView3D->getWidget()->setCursor(cur);
282
polyline.setWorking(false);
294
int PolyPickerSelection::locationEvent(const SoLocation2Event* const, const QPoint& pos)
296
// do all the drawing stuff for us
297
QPoint clPoint = pos;
299
if (polyline.isWorking()) {
300
// check the position
301
qreal dpr = _pcView3D->getGLWidget()->devicePixelRatioF();
302
QRect r = _pcView3D->getGLWidget()->rect();
304
r.setHeight(r.height() * dpr);
305
r.setWidth(r.width() * dpr);
308
if (!r.contains(clPoint)) {
309
if (clPoint.x() < r.left()) {
310
clPoint.setX(r.left());
313
if (clPoint.x() > r.right()) {
314
clPoint.setX(r.right());
317
if (clPoint.y() < r.top()) {
318
clPoint.setY(r.top());
321
if (clPoint.y() > r.bottom()) {
322
clPoint.setY(r.bottom());
326
QPoint newPos = _pcView3D->getGLWidget()->mapToGlobal(clPoint);
327
QCursor::setPos(newPos);
331
if (!lastConfirmed) {
334
polyline.addNode(clPoint);
335
lastConfirmed = false;
340
m_iXnew = clPoint.x();
341
m_iYnew = clPoint.y();
346
int PolyPickerSelection::keyboardEvent(const SoKeyboardEvent* const)
351
// -----------------------------------------------------------------------------------
353
PolyClipSelection::PolyClipSelection()
355
selectionBits.set(1);
356
selectionBits.set(2);
359
PolyClipSelection::~PolyClipSelection() = default;
361
int PolyClipSelection::popupMenu()
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"));
369
ci->setVisible(testRole(SelectionRole::Inner));
370
co->setVisible(testRole(SelectionRole::Outer));
371
cs->setVisible(testRole(SelectionRole::Split));
373
if (getPositions().size() < 3) {
374
ci->setEnabled(false);
375
co->setEnabled(false);
378
QAction* id = menu.exec(QCursor::pos());
381
m_selectedRole = SelectionRole::Inner;
385
m_selectedRole = SelectionRole::Outer;
389
m_selectedRole = SelectionRole::Split;
393
m_selectedRole = SelectionRole::None;
397
m_selectedRole = SelectionRole::None;
402
// -----------------------------------------------------------------------------------
404
FreehandSelection::FreehandSelection() = default;
406
FreehandSelection::~FreehandSelection() = default;
408
void FreehandSelection::setClosed(bool on)
410
polyline.setClosed(on);
411
polyline.setCloseStippled(true);
414
int FreehandSelection::popupMenu()
417
QAction* fi = menu.addAction(QObject::tr("Finish"));
418
menu.addAction(QObject::tr("Clear"));
419
QAction* ca = menu.addAction(QObject::tr("Cancel"));
421
if (getPositions().size() < 3) {
422
fi->setEnabled(false);
425
QAction* id = menu.exec(QCursor::pos());
437
int FreehandSelection::mouseButtonEvent(const SoMouseButtonEvent* const e, const QPoint& pos)
439
const int button = e->getButton();
440
const SbBool press = e->getState() == SoButtonEvent::DOWN ? true : false;
444
case SoMouseButtonEvent::BUTTON1: {
445
if (!polyline.isWorking()) {
446
polyline.setWorking(true);
450
polyline.addNode(pos);
451
polyline.setCoords(pos.x(), pos.y());
458
case SoMouseButtonEvent::BUTTON2: {
459
polyline.addNode(pos);
473
case SoMouseButtonEvent::BUTTON1:
474
if (polyline.isWorking()) {
479
case SoMouseButtonEvent::BUTTON2: {
480
QCursor cur = _pcView3D->getWidget()->cursor();
481
_pcView3D->getWidget()->setCursor(m_cPrevCursor);
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();
488
if (id == Finish || id == Cancel) {
491
else if (id == Restart) {
492
_pcView3D->getWidget()->setCursor(cur);
495
polyline.setWorking(false);
507
int FreehandSelection::locationEvent(const SoLocation2Event* const e, const QPoint& pos)
509
// do all the drawing stuff for us
510
QPoint clPoint = pos;
512
if (polyline.isWorking()) {
513
// check the position
514
qreal dpr = _pcView3D->getGLWidget()->devicePixelRatioF();
515
QRect r = _pcView3D->getGLWidget()->rect();
517
r.setHeight(r.height() * dpr);
518
r.setWidth(r.width() * dpr);
521
if (!r.contains(clPoint)) {
522
if (clPoint.x() < r.left()) {
523
clPoint.setX(r.left());
526
if (clPoint.x() > r.right()) {
527
clPoint.setX(r.right());
530
if (clPoint.y() < r.top()) {
531
clPoint.setY(r.top());
534
if (clPoint.y() > r.bottom()) {
535
clPoint.setY(r.bottom());
539
SbVec2s last = _clPoly.back();
540
SbVec2s curr = e->getPosition();
542
if (abs(last[0] - curr[0]) > 20 || abs(last[1] - curr[1]) > 20) {
543
_clPoly.push_back(curr);
546
polyline.addNode(clPoint);
547
polyline.setCoords(clPoint.x(), clPoint.y());
550
m_iXnew = clPoint.x();
551
m_iYnew = clPoint.y();
553
m_iXold = clPoint.x();
554
m_iYold = clPoint.y();
559
// -----------------------------------------------------------------------------------
561
RubberbandSelection::RubberbandSelection()
563
rubberband.setColor(1.0, 1.0, 0.0, 0.5);
566
RubberbandSelection::~RubberbandSelection() = default;
568
void RubberbandSelection::setColor(float r, float g, float b, float a)
570
rubberband.setColor(r, g, b, a);
573
void RubberbandSelection::initialize()
575
rubberband.setViewer(_pcView3D);
576
rubberband.setWorking(false);
577
_pcView3D->addGraphicsItem(&rubberband);
578
if (QtGLFramebufferObject::hasOpenGLFramebufferObjects()) {
579
_pcView3D->setRenderType(View3DInventorViewer::Image);
584
void RubberbandSelection::terminate(bool abort)
588
_pcView3D->removeGraphicsItem(&rubberband);
589
if (QtGLFramebufferObject::hasOpenGLFramebufferObjects()) {
590
_pcView3D->setRenderType(View3DInventorViewer::Native);
595
void RubberbandSelection::draw()
600
int RubberbandSelection::mouseButtonEvent(const SoMouseButtonEvent* const e, const QPoint& pos)
602
const int button = e->getButton();
603
const SbBool press = e->getState() == SoButtonEvent::DOWN ? true : false;
609
case SoMouseButtonEvent::BUTTON1: {
610
rubberband.setWorking(true);
611
m_iXold = m_iXnew = pos.x();
612
m_iYold = m_iYnew = pos.y();
621
case SoMouseButtonEvent::BUTTON1: {
622
rubberband.setWorking(false);
624
_clPoly.push_back(e->getPosition());
636
int RubberbandSelection::locationEvent(const SoLocation2Event* const, const QPoint& pos)
640
rubberband.setCoords(m_iXold, m_iYold, m_iXnew, m_iYnew);
645
int RubberbandSelection::keyboardEvent(const SoKeyboardEvent* const)
650
// -----------------------------------------------------------------------------------
652
RectangleSelection::RectangleSelection()
653
: RubberbandSelection()
655
rubberband.setColor(0.0, 0.0, 1.0, 1.0);
658
RectangleSelection::~RectangleSelection() = default;
660
// -----------------------------------------------------------------------------------
662
BoxZoomSelection::BoxZoomSelection() = default;
664
BoxZoomSelection::~BoxZoomSelection() = default;
666
void BoxZoomSelection::terminate(bool abort)
668
RubberbandSelection::terminate(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);