Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
REveSelection.cxx
Go to the documentation of this file.
1 // @(#)root/eve7:$Id$
2 // Author: Matevz Tadel 2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <ROOT/REveSelection.hxx>
14 #include <ROOT/REveCompound.hxx>
15 #include <ROOT/REveManager.hxx>
16 
17 #include "TClass.h"
18 #include "TColor.h"
19 
20 #include "json.hpp"
21 
22 using namespace ROOT::Experimental;
23 namespace REX = ROOT::Experimental;
24 
25 /** \class REveSelection
26 \ingroup REve
27 Make sure there is a SINGLE running REveSelection for each
28 selection type (select/highlight).
29 */
30 
31 ////////////////////////////////////////////////////////////////////////////////
32 /// Constructor.
33 
34 REveSelection::REveSelection(const std::string& n, const std::string& t,
35  Color_t col_visible, Color_t col_hidden) :
36  REveElement (n, t),
37  fVisibleEdgeColor (col_visible),
38  fHiddenEdgeColor (col_hidden),
39  fActive (kTRUE),
40  fIsMaster (kTRUE)
41 {
42  // Managing complete selection state on element level.
43  //
44  // Method pointers for propagation of selected / implied selected state
45  // to elements. This has to be done differently now -- and kept within
46  // REveSelection.
47  //
48  // Also, see REveManager::PreDeleteElement. We might need some sort of
49  // implied-selected-count after all (global, for all selections,
50  // highlights) ... and traverse all selections if the element gets zapped.
51  // Yup, we have it ...
52  // XXXX but ... we can also go up to master and check there directly !!!!!
53 
54  AddPickToSelect(kPS_Master);
55  AddPickToSelect(kPS_PableCompound);
56  AddPickToSelect(kPS_Element);
57 }
58 
59 ////////////////////////////////////////////////////////////////////////////////
60 /// Destructor
61 
62 REveSelection::~REveSelection()
63 {
64  DeactivateSelection();
65  RemoveNieces();
66 }
67 
68 ////////////////////////////////////////////////////////////////////////////////
69 /// Set visible highlight color
70 
71 void REveSelection::SetVisibleEdgeColorRGB(UChar_t r, UChar_t g, UChar_t b)
72 {
73  fVisibleEdgeColor = TColor::GetColor(r, g, b);
74  StampObjProps();
75 }
76 
77 ////////////////////////////////////////////////////////////////////////////////
78 /// Set hidden highlight color
79 void REveSelection::SetHiddenEdgeColorRGB(UChar_t r, UChar_t g, UChar_t b)
80 {
81  fHiddenEdgeColor = TColor::GetColor(r, g, b);
82  StampObjProps();
83 }
84 
85 ////////////////////////////////////////////////////////////////////////////////
86 /// Set to 'highlight' mode.
87 
88 void REveSelection::SetHighlightMode()
89 {
90  // Most importantly, this sets the pointers-to-function-members in
91  // REveElement that are used to mark elements as (un)selected and
92  // implied-(un)selected.
93 
94  fIsMaster = kFALSE;
95 }
96 
97 ////////////////////////////////////////////////////////////////////////////////
98 /// Select element indicated by the entry and fill its
99 /// implied-selected set.
100 
101 void REveSelection::DoElementSelect(SelMap_i &entry)
102 {
103  Set_t &imp_set = entry->second.f_implied;
104 
105  entry->first->FillImpliedSelectedSet(imp_set);
106 
107  auto i = imp_set.begin();
108  while (i != imp_set.end())
109  {
110  if ((*i)->GetElementId() == 0)
111  {
112  if (gDebug > 0)
113  {
114  Info("REveSelection::DoElementSelect",
115  "Element '%s' [%s] with 0 id detected and removed.",
116  (*i)->GetCName(), (*i)->IsA()->GetName());
117  }
118  auto j = i++;
119  imp_set.erase(j);
120  }
121  else
122  {
123  (*i)->IncImpliedSelected();
124  ++i;
125  }
126  }
127 }
128 
129 ////////////////////////////////////////////////////////////////////////////////
130 /// Deselect element indicated by the entry and clear its
131 /// implied-selected set.
132 
133 void REveSelection::DoElementUnselect(SelMap_i &entry)
134 {
135  Set_t &imp_set = entry->second.f_implied;
136 
137  for (auto &imp_el: imp_set) imp_el->DecImpliedSelected();
138 
139  imp_set.clear();
140 }
141 
142 ////////////////////////////////////////////////////////////////////////////////
143 /// Check if elemenet el is selected (not implied selected).
144 
145 bool REveSelection::HasNiece(REveElement *el) const
146 {
147  return fMap.find(el) != fMap.end();
148 }
149 
150 ////////////////////////////////////////////////////////////////////////////////
151 /// Check if any elements are selected.
152 
153 bool REveSelection::HasNieces() const
154 {
155  return ! fMap.empty();
156 }
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 /// Pre-addition check. Deny addition if el is already selected.
160 /// Virtual from REveAunt.
161 
162 bool REveSelection::AcceptNiece(REveElement* el)
163 {
164  return el != this && fMap.find(el) == fMap.end() &&
165  el->IsA()->InheritsFrom(TClass::GetClass<REveSelection>()) == kFALSE;
166 }
167 
168 ////////////////////////////////////////////////////////////////////////////////
169 /// Add an element into selection, virtual from REveAunt
170 
171 void REveSelection::AddNieceInternal(REveElement* el)
172 {
173  auto res = fMap.emplace(el, Record(el));
174  if (fActive) {
175  DoElementSelect(res.first);
176  SelectionAdded(el);
177  }
178  StampObjPropsPreChk();
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 /// Virtual from REveAunt.
183 
184 void REveSelection::RemoveNieceInternal(REveElement* el)
185 {
186  auto i = fMap.find(el);
187 
188  if (i != fMap.end())
189  {
190  if (fActive)
191  {
192  DoElementUnselect(i);
193  SelectionRemoved(el);
194  }
195  fMap.erase(i);
196  StampObjPropsPreChk();
197  }
198  else
199  {
200  Warning("REveSelection::RemoveNieceLocal", "element not found in map.");
201  }
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 /// Add an element into selection, virtual from REveAunt.
206 /// Overriden here just so that a signal can be emitted.
207 
208 void REveSelection::RemoveNieces()
209 {
210  if (IsEmpty()) return;
211 
212  for (auto i = fMap.begin(); i != fMap.end(); ++i)
213  {
214  i->first->RemoveAunt(this);
215  if (fActive) DoElementUnselect(i);
216  }
217  fMap.clear();
218  if (fActive) SelectionCleared();
219  StampObjPropsPreChk();
220 }
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 /// Remove element from all implied-selected sets.
224 ///
225 /// This is called as part of the element destruction from
226 /// REveManager::PreDeleteElement() and should not be called
227 /// directly.
228 
229 void REveSelection::RemoveImpliedSelected(REveElement *el)
230 {
231  bool changed = false;
232 
233  for (auto &i : fMap)
234  {
235  auto j = i.second.f_implied.find(el);
236  if (j != i.second.f_implied.end())
237  {
238  i.second.f_implied.erase(j);
239  changed = true;
240  }
241  }
242 
243  if (changed) StampObjPropsPreChk();
244 }
245 
246 ////////////////////////////////////////////////////////////////////////////////
247 /// Recalculate implied-selected state for given selection entry.
248 /// Add new elements to implied-selected set and increase their
249 /// implied-selected count.
250 
251 void REveSelection::RecheckImpliedSet(SelMap_i &smi)
252 {
253  bool changed = false;
254  Set_t set;
255  smi->first->FillImpliedSelectedSet(set);
256  for (auto &i: set)
257  {
258  if (smi->second.f_implied.find(i) == smi->second.f_implied.end())
259  {
260  smi->second.f_implied.insert(i);
261  i->IncImpliedSelected();
262  changed = true;
263  }
264  }
265 
266  if (changed) StampObjPropsPreChk();
267 }
268 
269 ////////////////////////////////////////////////////////////////////////////////
270 /// If given element is selected or implied-selected within this
271 /// selection then recheck implied-set for given selection entry.
272 
273 void REveSelection::RecheckImpliedSetForElement(REveElement *el)
274 {
275  // Top-level selected.
276  {
277  auto i = fMap.find(el);
278  if (i != fMap.end())
279  RecheckImpliedSet(i);
280  }
281 
282  // Implied selected (we can not tell if by this selection or some other),
283  // then we need to loop over all.
284  if (el->GetImpliedSelected() > 0)
285  {
286  for (auto i = fMap.begin(); i != fMap.end(); ++i)
287  {
288  if (i->second.f_implied.find(el) != i->second.f_implied.end())
289  RecheckImpliedSet(i);
290  }
291  }
292 }
293 
294 ////////////////////////////////////////////////////////////////////////////////
295 /// Emit SelectionAdded signal.
296 
297 void REveSelection::SelectionAdded(REveElement* /*el*/)
298 {
299  // XXXX
300  // Emit("SelectionAdded(REveElement*)", (Long_t)el);
301 }
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 /// Emit SelectionRemoved signal.
305 
306 void REveSelection::SelectionRemoved(REveElement* /*el*/)
307 {
308  // XXXX
309  // Emit("SelectionRemoved(REveElement*)", (Long_t)el);
310 }
311 
312 ////////////////////////////////////////////////////////////////////////////////
313 /// Emit SelectionCleared signal.
314 
315 void REveSelection::SelectionCleared()
316 {
317  // XXXX
318  // Emit("SelectionCleared()");
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Emit SelectionRepeated signal.
323 
324 void REveSelection::SelectionRepeated(REveElement* /*el*/)
325 {
326  // XXXX
327  // Emit("SelectionRepeated(REveElement*)", (Long_t)el);
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 /// Activate this selection.
332 
333 void REveSelection::ActivateSelection()
334 {
335  if (fActive) return;
336 
337  fActive = kTRUE;
338  for (auto i = fMap.begin(); i != fMap.end(); ++i) {
339  DoElementSelect(i);
340  SelectionAdded(i->first);
341  }
342 }
343 
344 ////////////////////////////////////////////////////////////////////////////////
345 /// Deactivate this selection.
346 
347 void REveSelection::DeactivateSelection()
348 {
349  if (!fActive) return;
350 
351  for (auto i = fMap.begin(); i != fMap.end(); ++i) {
352  DoElementUnselect(i);
353  }
354  SelectionCleared();
355  fActive = kFALSE;
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// Given element el that was picked or clicked by the user, find
360 /// the parent/ancestor element that should actually become the main
361 /// selected element according to current selection mode.
362 
363 REveElement* REveSelection::MapPickedToSelected(REveElement* el)
364 {
365  if (el == nullptr)
366  return nullptr;
367 
368  for (int pick_to_select : fPickToSelect)
369  {
370  switch (pick_to_select)
371  {
372  case kPS_Ignore:
373  {
374  return nullptr;
375  }
376  case kPS_Element:
377  {
378  return el;
379  }
380  case kPS_Projectable:
381  {
382  REveProjected* pted = dynamic_cast<REveProjected*>(el);
383  if (pted)
384  return dynamic_cast<REveElement*>(pted->GetProjectable());
385  break;
386  }
387  case kPS_Compound:
388  {
389  REveElement* cmpnd = el->GetCompound();
390  if (cmpnd)
391  return cmpnd;
392  break;
393  }
394  case kPS_PableCompound:
395  {
396  REveProjected* pted = dynamic_cast<REveProjected*>(el);
397  if (pted)
398  el = dynamic_cast<REveElement*>(pted->GetProjectable());
399  REveElement* cmpnd = el->GetCompound();
400  if (cmpnd)
401  return cmpnd;
402  if (pted)
403  return el;
404  break;
405  }
406  case kPS_Master:
407  {
408  REveElement* mstr = el->GetSelectionMaster();
409  if (mstr)
410  return mstr;
411  break;
412  }
413  }
414  }
415 
416  return el;
417 }
418 
419 ////////////////////////////////////////////////////////////////////////////////
420 /// Called when user picks/clicks on an element. If multi is true,
421 /// the user is requiring a multiple selection (usually this is
422 /// associated with control-key being pressed at the time of pick
423 /// event).
424 /// XXXX Old interface, not used in EVE-7.
425 
426 void REveSelection::UserPickedElement(REveElement* el, Bool_t multi)
427 {
428  el = MapPickedToSelected(el);
429 
430  if (el || NotEmpty())
431  {
432  if ( ! multi)
433  RemoveNieces();
434  if (el)
435  {
436  if (HasNiece(el))
437  RemoveNiece(el);
438  else
439  AddNiece(el);
440  }
441  StampObjProps();
442  }
443 }
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 /// Called when element selection is repeated.
447 /// XXXX Old interface, not used in EVE-7.
448 
449 void REveSelection::UserRePickedElement(REveElement* el)
450 {
451  el = MapPickedToSelected(el);
452  if (el && HasNiece(el))
453  {
454  SelectionRepeated(el);
455  StampObjProps();
456  }
457 }
458 
459 ////////////////////////////////////////////////////////////////////////////////
460 /// Called when an element is unselected.
461 /// XXXX Old interface, not used in EVE-7.
462 
463 void REveSelection::UserUnPickedElement(REveElement* el)
464 {
465  el = MapPickedToSelected(el);
466  if (el && HasNiece(el))
467  {
468  RemoveNiece(el);
469  StampObjProps();
470  }
471 }
472 
473 //==============================================================================
474 
475 void REveSelection::NewElementPicked(ElementId_t id, bool multi, bool secondary, const std::set<int>& secondary_idcs)
476 {
477  static const REveException eh("REveSelection::NewElementPicked ");
478 
479  REveElement *pel = nullptr, *el = nullptr;
480 
481  if (id > 0)
482  {
483  pel = REX::gEve->FindElementById(id);
484 
485  if ( ! pel) throw eh + "picked element id=" + id + " not found.";
486 
487  el = MapPickedToSelected(pel);
488  }
489 
490  if (gDebug > 0) {
491  std::string debug_secondary;
492  if (secondary) {
493  debug_secondary = " {";
494  for (auto si : secondary_idcs) {
495  debug_secondary.append(" ");
496  debug_secondary.append(std::to_string(si));
497  }
498  debug_secondary.append(" }");
499  }
500  ::Info("REveSelection::NewElementPicked", "%p -> %p, multi: %d, secondary: %d %s", pel, el, multi, secondary, debug_secondary.c_str());
501  }
502 
503  Record *rec = find_record(el);
504 
505  bool changed = true;
506 
507  if (multi)
508  {
509  if (el)
510  {
511  if (rec)
512  {
513  if (secondary || rec->is_secondary()) // ??? should actually be && ???
514  {
515  // XXXX union or difference:
516  // - if all secondary_idcs are already in the record, toggle
517  // - if final result is empty set, remove element from selection
518  // - otherwise union
519  }
520  else
521  {
522  RemoveNiece(el);
523  }
524  }
525  else
526  {
527  AddNiece(el);
528  }
529  }
530  else
531  {
532  // Multiple selection with 0 element ... do nothing, I think.
533  changed = false;
534  }
535  }
536  else // single selection (not multi)
537  {
538  if (el)
539  {
540  if (rec)
541  {
542  if (secondary)
543  {
544  // Could check rec->is_secondary() and compare indices.
545  // if sets are identical, issue SelectionRepeated()
546  // else modify record for the new one, issue Repeated
547 
548  rec->f_is_sec = true;
549  rec->f_sec_idcs = secondary_idcs;
550  }
551  else
552  {
553  RemoveNiece(el);
554  }
555  }
556  else
557  {
558  if (HasNieces()) RemoveNieces();
559  AddNiece(el);
560  if (secondary)
561  {
562  rec = find_record(el);
563  rec->f_is_sec = true;
564  rec->f_sec_idcs = secondary_idcs;
565  }
566  }
567  }
568  else // Single selection with zero element --> clear selection.
569  {
570  if (HasNieces())
571  RemoveNieces();
572  else
573  changed = false;
574  }
575  }
576 
577  if (changed)
578  StampObjProps();
579 }
580 
581 ////////////////////////////////////////////////////////////////////////////////
582 /// Clear selection if not empty.
583 
584 void REveSelection::ClearSelection()
585 {
586  if (HasNieces())
587  {
588  RemoveNieces();
589  StampObjProps();
590  }
591 }
592 
593 //==============================================================================
594 
595 ////////////////////////////////////////////////////////////////////////////////
596 /// Remove pointers to el from implied selected sets.
597 
598 int REveSelection::RemoveImpliedSelectedReferencesTo(REveElement *el)
599 {
600  int count = 0;
601 
602  for (auto &i : fMap)
603  {
604  auto j = i.second.f_implied.find(el);
605 
606  if (j != i.second.f_implied.end())
607  {
608  i.second.f_implied.erase(j);
609  el->DecImpliedSelected();
610  ++count;
611  }
612  }
613 
614  return count;
615 }
616 
617 ////////////////////////////////////////////////////////////////////////////////
618 /// Write core json. If rnr_offset negative, render data will not be written
619 
620 Int_t REveSelection::WriteCoreJson(nlohmann::json &j, Int_t /* rnr_offset */)
621 {
622  REveElement::WriteCoreJson(j, -1);
623 
624  j["fVisibleEdgeColor"] = fVisibleEdgeColor;
625  j["fHiddenEdgeColor"] = fHiddenEdgeColor;
626 
627  nlohmann::json sel_list = nlohmann::json::array();
628 
629  for (auto &i : fMap)
630  {
631  nlohmann::json rec = {}, imp = nlohmann::json::array(), sec = nlohmann::json::array();
632 
633  rec["primary"] = i.first->GetElementId();
634 
635  // XXX if not empty ???
636  for (auto &imp_el : i.second.f_implied) imp.push_back(imp_el->GetElementId());
637  rec["implied"] = imp;
638 
639  // XXX if not empty / f_is_sec is false ???
640  for (auto &sec_id : i.second.f_sec_idcs) sec.push_back(sec_id);
641  rec["sec_idcs"] = sec;
642 
643  sel_list.push_back(rec);
644  }
645 
646  j["sel_list"] = sel_list;
647 
648  j["UT_PostStream"] = "UT_Selection_Refresh_State"; // XXXX to be canonized
649 
650  // std::cout << j.dump(4) << std::endl;
651 
652  return 0;
653 }