ATLAS Offline Software
Loading...
Searching...
No Matches
SoCooperativeSelection.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Class: SoCooperativeSelection.
6// Author: Thomas.Kittelmann@cern.ch
7// Initial version: October 2007
8
10
11#include <Inventor/actions/SoHandleEventAction.h>
12#include <Inventor/lists/SoCallbackList.h>
13#include <Inventor/SoPickedPoint.h>
14#include <Inventor/events/SoMouseButtonEvent.h>
15
16
17SO_NODE_SOURCE(SoCooperativeSelection)
18
19//____________________________________________________________________
21{
22 SO_NODE_INIT_CLASS(SoCooperativeSelection,SoSelection,"CooperativeSelection");
23}
24
25//____________________________________________________________________
27{
28 [[maybe_unused]] static const bool needsinit = [&]() {
29 initClass();
30 return false;
31 }();
32}
33
34//____________________________________________________________________
36 : SoSelection()
37{
38 init();
39}
40
41//____________________________________________________________________
43 : SoSelection(nChildren)
44{
45 init();
46}
47
48//____________________________________________________________________
50{
51 SO_NODE_CONSTRUCTOR(SoCooperativeSelection);
52
53 SO_NODE_ADD_FIELD(activePolicy, (SoCooperativeSelection::ACTIVE));
54 SO_NODE_DEFINE_ENUM_VALUE(ActivePolicy, INERT);
55 SO_NODE_DEFINE_ENUM_VALUE(ActivePolicy, ACTIVE);
56 SO_NODE_SET_SF_ENUM_TYPE(activePolicy, ActivePolicy);
57
58 setNodeType(EXTENSION);
59 m_clickoutsideCBList = new SoCallbackList;
60
61}
62
63//____________________________________________________________________
65{
66 if (this->mouseDownPickPath)
67 this->mouseDownPickPath->unref();
69}
70
71//____________________________________________________________________
73{
74 for (int i = 0; i < path->getLength(); ++i) {
75 if (path->getNodeFromTail(i)->getTypeId().isDerivedFrom(SoCooperativeSelection::getClassTypeId())) {
76 SoCooperativeSelection* sel = static_cast<SoCooperativeSelection*>(path->getNodeFromTail(i));
77 if (sel->activePolicy.getValue() == ACTIVE)
78 return sel;
79 }
80 }
81 return 0;
82}
83
84//____________________________________________________________________
86{
87 m_clickoutsideCBList->addCallback((SoCallbackListCB *)f, userData);
88}
89
90//____________________________________________________________________
92{
93 m_clickoutsideCBList->removeCallback((SoCallbackListCB *)f, userData);
94}
95
96//____________________________________________________________________
97void SoCooperativeSelection::handleEvent(SoHandleEventAction * action)
98{
99 // Overridden to do selection picking.
100 SoSeparator::handleEvent(action);//Skip the SoSelection impl and go directly to the SoSeparator action!!
101
102 if (activePolicy.getValue()==INERT)
103 return;
104
105 const SoEvent * event = action->getEvent();
106
107 SbBool haltaction = FALSE;
108 if (SO_MOUSE_PRESS_EVENT(event, BUTTON1)) {
109 if (this->mouseDownPickPath) {
110 this->mouseDownPickPath->unref();
111 this->mouseDownPickPath = NULL;
112 }
113 const SoPickedPoint * pp = action->getPickedPoint();
114 if (!pp)
115 m_clickoutsideCBList->invokeCallbacks(this);
116 if (pp) {
117 SoPath * selectionpath = pp->getPath();
118 if (!selectionpath)
119 return;
120 // call pick filter callback also for mouse down events
121 if (this->pickCBFunc && (!this->callPickCBOnlyIfSelectable ||
122 selectionpath->findNode(this) >= 0)) {
123 selectionpath = this->pickCBFunc(this->pickCBData, pp);
124 }
125
126 SoCooperativeSelection * lastsoselectionfrompath = getLastActiveSoSelectionFromPath(selectionpath);
127
128 if (lastsoselectionfrompath==this) {
129 //We are the selection node furthest down the path => handle the event.
130 this->mouseDownPickPath = selectionpath;
131 this->mouseDownPickPath->ref();
132 action->setHandled();
133 }
134 }
135 }
136 else if (SO_MOUSE_RELEASE_EVENT(event, BUTTON1)) {
137
138 SbBool ignorepick = FALSE;
139 // call pick filter callback (called from getSelectionPath()) even
140 // if the event was handled by a child node.
141 SoPath * selpath = this->getSelectionPath(action, ignorepick, haltaction);
142
143 if (action->isHandled()) {
144 // if the event was handled by a child node we should not invoke
145 // the selection policy
146 if (selpath) {
147 selpath->ref();
148 selpath->unref();
149 }
150 }
151 else {
152 if (haltaction) action->setHandled();
153
154 if (!ignorepick) {
155 if (selpath) selpath->ref();
156 this->startCBList->invokeCallbacks(this);
157 this->invokeSelectionPolicy(selpath, event->wasShiftDown());
158 this->finishCBList->invokeCallbacks(this);
159 if (selpath) selpath->unref();
160 }
161 }
162 if (this->mouseDownPickPath) {
163 this->mouseDownPickPath->unref();
164 this->mouseDownPickPath = NULL;
165 }
166 }
167}
168
169
170//Implementation of getSelectionPath is copied verbatim from
171//SoSelection.cpp. If only it was protected rather than private...
172
173SoPath *
174SoCooperativeSelection::getSelectionPath(SoHandleEventAction * action, SbBool & ignorepick,
175 SbBool & haltaction)
176{
177 //
178 // handled like described in the man-pages for SoSelection
179 //
180
181 haltaction = FALSE;
182 ignorepick = FALSE;
183 if (this->pickMatching && this->mouseDownPickPath == NULL) {
184 return NULL;
185 }
186 const SoPickedPoint * pp = action->getPickedPoint();
187 SoPath * selectionpath = NULL;
188 if (pp) {
189 selectionpath = pp->getPath();
190 // if there's no pickCBFunc we can just test against
191 // mouseDownPickPath and (possibly) return here.
192 if (this->pickMatching && !this->pickCBFunc) {
193 if (*(this->mouseDownPickPath) != *selectionpath) {
194 ignorepick = TRUE;
195 return NULL;
196 }
197 }
198 // if we have a pickCBFunc we have to get the pick filter path
199 // before comparing the mouse press and mouse release paths
200 if (this->pickCBFunc && (!this->callPickCBOnlyIfSelectable ||
201 selectionpath->findNode(this) >= 0)) {
202 selectionpath = this->pickCBFunc(this->pickCBData, pp);
203
204 // From the SoSelection man-pages:
205 // Possible return values from pickCBFunc:
206 // 1) NULL - behave as if nothing was picked, halt action
207 // 2) path through the selection node - select/deselect path
208 // 3) path containing only the selection node - as 1, but do not halt action
209 // 4) path not through the selection node - ignore event
210 if (selectionpath) {
211 if (selectionpath->getLength() == 1 &&
212 selectionpath->getNode(0) == this) {
213 selectionpath->ref();
214 selectionpath->unref();
215 selectionpath = NULL;
216 }
217 else if (selectionpath->findNode(this) >= 0) {
218 if (*(this->mouseDownPickPath) == *selectionpath) {
219 // pick matched
220 haltaction = TRUE;
221 }
222 else {
223 // mouse release didn't match mouse down
224 ignorepick = TRUE;
225 selectionpath->ref();
226 selectionpath->unref();
227 ignorepick = TRUE;
228 }
229 }
230 else { // path with this not in the path (most probably an empty path)
231 selectionpath->ref();
232 selectionpath->unref();
233 selectionpath = NULL;
234 ignorepick = TRUE;
235 }
236 }
237 else { // pickCBFunc returned NULL
238 haltaction = TRUE;
239 }
240 }
241 else { // no pickCBFunc or not a valid path
242 haltaction = FALSE;
243 }
244 }
245 else if (this->mouseDownPickPath) {
246 ignorepick = TRUE;
247 }
248 return selectionpath;
249}
void SoCooperativeSelectionClickOutsideCB(void *data, SoCooperativeSelection *sel)
SoPath * getSelectionPath(SoHandleEventAction *action, SbBool &ignorepick, SbBool &haltaction)
void addClickOutsideCallback(SoCooperativeSelectionClickOutsideCB *f, void *userData=0)
SoCallbackList * m_clickoutsideCBList
SoCooperativeSelection * getLastActiveSoSelectionFromPath(SoPath *) const
void removeClickOutsideCallback(SoCooperativeSelectionClickOutsideCB *f, void *userData=0)
virtual void handleEvent(SoHandleEventAction *action)