Logo ROOT  
Reference Guide
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
14#include <ROOT/REveCompound.hxx>
15#include <ROOT/REveManager.hxx>
17
18#include "TClass.h"
19#include "TColor.h"
20
21#include <iostream>
22#include <regex>
23
24#include <nlohmann/json.hpp>
25
26using namespace ROOT::Experimental;
27namespace REX = ROOT::Experimental;
28
29/** \class REveSelection
30\ingroup REve
31Make sure there is a SINGLE running REveSelection for each
32selection type (select/highlight).
33*/
34
35////////////////////////////////////////////////////////////////////////////////
36/// Constructor.
37
38REveSelection::REveSelection(const std::string& n, const std::string& t,
39 Color_t col_visible, Color_t col_hidden) :
40 REveElement (n, t),
41 fVisibleEdgeColor (col_visible),
42 fHiddenEdgeColor (col_hidden),
43 fActive (kTRUE),
44 fIsMaster (kTRUE)
45{
46 // Managing complete selection state on element level.
47 //
48 // Method pointers for propagation of selected / implied selected state
49 // to elements. This has to be done differently now -- and kept within
50 // REveSelection.
51 //
52 // Also, see REveManager::PreDeleteElement. We might need some sort of
53 // implied-selected-count after all (global, for all selections,
54 // highlights) ... and traverse all selections if the element gets zapped.
55 // Yup, we have it ...
56 // XXXX but ... we can also go up to master and check there directly !!!!!
57
61}
62
63////////////////////////////////////////////////////////////////////////////////
64/// Destructor
65
67{
70}
71
72////////////////////////////////////////////////////////////////////////////////
73/// Set visible highlight color
74
76{
79}
80
81////////////////////////////////////////////////////////////////////////////////
82/// Set hidden highlight color
84{
87}
88
89////////////////////////////////////////////////////////////////////////////////
90/// Set to 'highlight' mode.
91
93{
94 // Most importantly, this sets the pointers-to-function-members in
95 // REveElement that are used to mark elements as (un)selected and
96 // implied-(un)selected.
97
99}
100
101////////////////////////////////////////////////////////////////////////////////
102/// Select element indicated by the entry and fill its
103/// implied-selected set.
104
106{
107 Set_t &imp_set = entry->second.f_implied;
108
109 entry->first->FillImpliedSelectedSet(imp_set, entry->second.f_sec_idcs);
110
111 auto i = imp_set.begin();
112 while (i != imp_set.end())
113 {
114 if ((*i)->GetElementId() == 0)
115 {
116 if (gDebug > 0)
117 {
118 Info("REveSelection::DoElementSelect",
119 "Element '%s' [%s] with 0 id detected and removed.",
120 (*i)->GetCName(), (*i)->IsA()->GetName());
121 }
122 auto j = i++;
123 imp_set.erase(j);
124 }
125 else
126 {
127 (*i)->IncImpliedSelected();
128 ++i;
129 }
130 }
131}
132
133////////////////////////////////////////////////////////////////////////////////
134/// Deselect element indicated by the entry and clear its
135/// implied-selected set.
136
138{
139 Set_t &imp_set = entry->second.f_implied;
140
141 for (auto &imp_el: imp_set) imp_el->DecImpliedSelected();
142
143 imp_set.clear();
144}
145
146////////////////////////////////////////////////////////////////////////////////
147/// Check if elemenet el is selected (not implied selected).
148
150{
151 return fMap.find(el) != fMap.end();
152}
153
154////////////////////////////////////////////////////////////////////////////////
155/// Check if any elements are selected.
156
158{
159 return ! fMap.empty();
160}
161
162////////////////////////////////////////////////////////////////////////////////
163/// Pre-addition check. Deny addition if el is already selected.
164/// Virtual from REveAunt.
165
167{
168 return el != this && fMap.find(el) == fMap.end() &&
169 el->IsA()->InheritsFrom(TClass::GetClass<REveSelection>()) == kFALSE;
170}
171
172////////////////////////////////////////////////////////////////////////////////
173/// Add an element into selection, virtual from REveAunt
174
176{
177 fMap.emplace(el, Record(el));
178}
179
180////////////////////////////////////////////////////////////////////////////////
181///
182void REveSelection::AddNieceForSelection(REveElement* el, bool secondary, const std::set<int>& sec_idcs)
183{
184 AddNiece(el);
185
186 auto i = fMap.find(el);
187 i->second.f_is_sec = secondary;
188 i->second.f_sec_idcs = sec_idcs;
189
190 if (fActive) {
192 SelectionAdded(el);
193 }
195}
196
197////////////////////////////////////////////////////////////////////////////////
198/// Virtual from REveAunt.
199
201{
202 auto i = fMap.find(el);
203
204 if (i != fMap.end())
205 {
206 if (fActive)
207 {
210 }
211 fMap.erase(i);
213 }
214 else
215 {
216 Warning("REveSelection::RemoveNieceLocal", "element not found in map.");
217 }
218}
219
220////////////////////////////////////////////////////////////////////////////////
221/// Add an element into selection, virtual from REveAunt.
222/// Overriden here just so that a signal can be emitted.
223
225{
226 if (IsEmpty()) return;
227
228 for (auto i = fMap.begin(); i != fMap.end(); ++i)
229 {
230 i->first->RemoveAunt(this);
232 }
233 fMap.clear();
236}
237
238////////////////////////////////////////////////////////////////////////////////
239/// Remove element from all implied-selected sets.
240///
241/// This is called as part of the element destruction from
242/// REveManager::PreDeleteElement() and should not be called
243/// directly.
244
246{
247 bool changed = false;
248
249 for (auto &i : fMap)
250 {
251 auto j = i.second.f_implied.find(el);
252 if (j != i.second.f_implied.end())
253 {
254 i.second.f_implied.erase(j);
255 changed = true;
256 }
257 }
258
259 if (changed) StampObjPropsPreChk();
260}
261
262////////////////////////////////////////////////////////////////////////////////
263/// Recalculate implied-selected state for given selection entry.
264/// Add new elements to implied-selected set and increase their
265/// implied-selected count.
266
268{
269 bool changed = false;
270 Set_t set;
271 smi->first->FillImpliedSelectedSet(set, smi->second.f_sec_idcs);
272 for (auto &i: set)
273 {
274 if (smi->second.f_implied.find(i) == smi->second.f_implied.end())
275 {
276 smi->second.f_implied.insert(i);
277 i->IncImpliedSelected();
278 changed = true;
279 }
280 }
281
282 if (changed) StampObjPropsPreChk();
283}
284
285////////////////////////////////////////////////////////////////////////////////
286/// If given element is selected or implied-selected within this
287/// selection then recheck implied-set for given selection entry.
288
290{
291 // Top-level selected.
292 {
293 auto i = fMap.find(el);
294 if (i != fMap.end())
296 }
297
298 // Implied selected (we can not tell if by this selection or some other),
299 // then we need to loop over all.
300 if (el->GetImpliedSelected() > 0)
301 {
302 for (auto i = fMap.begin(); i != fMap.end(); ++i)
303 {
304 if (i->second.f_implied.find(el) != i->second.f_implied.end())
306 }
307 }
308}
309
310////////////////////////////////////////////////////////////////////////////////
311/// Emit SelectionAdded signal.
312
314{
315 // XXXX
316 // Emit("SelectionAdded(REveElement*)", (Long_t)el);
317}
318
319////////////////////////////////////////////////////////////////////////////////
320/// Emit SelectionRemoved signal.
321
323{
324 // XXXX
325 // Emit("SelectionRemoved(REveElement*)", (Long_t)el);
326}
327
328////////////////////////////////////////////////////////////////////////////////
329/// Emit SelectionCleared signal.
330
332{
333 // XXXX
334 // Emit("SelectionCleared()");
335}
336
337////////////////////////////////////////////////////////////////////////////////
338/// Emit SelectionRepeated signal.
339
341{
342 // XXXX
343 // Emit("SelectionRepeated(REveElement*)", (Long_t)el);
344}
345
346////////////////////////////////////////////////////////////////////////////////
347/// Activate this selection.
348
350{
351 if (fActive) return;
352
353 fActive = kTRUE;
354 for (auto i = fMap.begin(); i != fMap.end(); ++i) {
356 SelectionAdded(i->first);
357 }
358}
359
360////////////////////////////////////////////////////////////////////////////////
361/// Deactivate this selection.
362
364{
365 if (!fActive) return;
366
367 for (auto i = fMap.begin(); i != fMap.end(); ++i) {
369 }
371 fActive = kFALSE;
372}
373
374////////////////////////////////////////////////////////////////////////////////
375/// Given element el that was picked or clicked by the user, find
376/// the parent/ancestor element that should actually become the main
377/// selected element according to current selection mode.
378
380{
381 if (el == nullptr)
382 return nullptr;
383
384 for (int pick_to_select : fPickToSelect)
385 {
386 switch (pick_to_select)
387 {
388 case kPS_Ignore:
389 {
390 return nullptr;
391 }
392 case kPS_Element:
393 {
394 return el;
395 }
396 case kPS_Projectable:
397 {
398 REveProjected* pted = dynamic_cast<REveProjected*>(el);
399 if (pted)
400 return dynamic_cast<REveElement*>(pted->GetProjectable());
401 break;
402 }
403 case kPS_Compound:
404 {
405 REveElement* cmpnd = el->GetCompound();
406 if (cmpnd)
407 return cmpnd;
408 break;
409 }
411 {
412 REveProjected* pted = dynamic_cast<REveProjected*>(el);
413 if (pted)
414 el = dynamic_cast<REveElement*>(pted->GetProjectable());
415 REveElement* cmpnd = el->GetCompound();
416 if (cmpnd)
417 return cmpnd;
418 if (pted)
419 return el;
420 break;
421 }
422 case kPS_Master:
423 {
424 REveElement* mstr = el->GetSelectionMaster();
425 if (mstr)
426 return mstr;
427 break;
428 }
429 }
430 }
431
432 return el;
433}
434
435////////////////////////////////////////////////////////////////////////////////
436/// Called when user picks/clicks on an element. If multi is true,
437/// the user is requiring a multiple selection (usually this is
438/// associated with control-key being pressed at the time of pick
439/// event).
440/// XXXX Old interface, not used in EVE-7.
441
443{
444 el = MapPickedToSelected(el);
445
446 if (el || NotEmpty())
447 {
448 if ( ! multi)
449 RemoveNieces();
450 if (el)
451 {
452 if (HasNiece(el))
453 RemoveNiece(el);
454 else
455 AddNiece(el);
456 }
458 }
459}
460
461////////////////////////////////////////////////////////////////////////////////
462/// Called when element selection is repeated.
463/// XXXX Old interface, not used in EVE-7.
464
466{
467 el = MapPickedToSelected(el);
468 if (el && HasNiece(el))
469 {
472 }
473}
474
475////////////////////////////////////////////////////////////////////////////////
476/// Called when an element is unselected.
477/// XXXX Old interface, not used in EVE-7.
478
480{
481 el = MapPickedToSelected(el);
482 if (el && HasNiece(el))
483 {
484 RemoveNiece(el);
486 }
487}
488
489//==============================================================================
490
491////////////////////////////////////////////////////////////////////////////////
492/// Called from GUI when user picks or un-picks an element.
493
494void REveSelection::NewElementPicked(ElementId_t id, bool multi, bool secondary, const std::set<int> &secondary_idcs)
495{
496 static const REveException eh("REveSelection::NewElementPicked ");
497
498 REveElement *pel = nullptr, *el = nullptr;
499
500 if (id > 0) {
501 pel = REX::gEve->FindElementById(id);
502
503 if (!pel)
504 throw eh + "picked element id=" + id + " not found.";
505
506 el = MapPickedToSelected(pel);
507 }
508
509 if (fDeviator && fDeviator->DeviateSelection(this, el, multi, secondary, secondary_idcs))
510 {
511 return;
512 }
513 else
514 {
515 NewElementPickedInternal(el, multi, secondary, secondary_idcs);
516 }
517}
518
519//==============================================================================
520
521////////////////////////////////////////////////////////////////////////////////
522/// Called from NewElementPicked or Deviator::DeviateSelection
523
524void REveSelection::NewElementPickedInternal(REveElement* el, bool multi, bool secondary, const std::set<int>& secondary_idcs)
525{
526 if (gDebug > 0) {
527 std::string debug_secondary;
528 if (secondary) {
529 debug_secondary = " {";
530 for (auto si : secondary_idcs) {
531 debug_secondary.append(" ");
532 debug_secondary.append(std::to_string(si));
533 }
534 debug_secondary.append(" }");
535 }
536 ::Info("REveSelection::NewElementPickedInternal", " %p, multi: %d, secondary: %d %s", el, multi, secondary, debug_secondary.c_str());
537 }
538
539 Record *rec = find_record(el);
540
541 bool changed = true;
542
543 if (multi)
544 {
545 if (el)
546 {
547 if (rec)
548 {
549 assert(secondary == rec->is_secondary());
550 if (secondary || rec->is_secondary())
551 {
552 std::set<int> dup;
553 for (auto &ns : secondary_idcs)
554 {
555 int nsi = ns;
556 auto ir = rec->f_sec_idcs.insert(nsi);
557 if (!ir.second)
558 dup.insert(nsi);
559 }
560
561 // erase duplicates
562 for (auto &dit : dup)
563 rec->f_sec_idcs.erase(dit);
564
565 // re-adding is needed to refresh implied selected
566 std::set<int> newSet = rec->f_sec_idcs;
567 RemoveNiece(el);
568 if (!newSet.empty()) {
569 AddNieceForSelection(el, secondary, newSet);
570 }
571 }
572 else
573 {
574 RemoveNiece(el);
575 }
576 }
577 else
578 {
579 AddNieceForSelection(el, secondary, secondary_idcs);
580 }
581 }
582 else
583 {
584 // Multiple selection with 0 element ... do nothing, I think.
585 changed = false;
586 }
587 }
588 else // single selection (not multi)
589 {
590 if (el)
591 {
592 if (rec)
593 {
594 if (secondary)
595 {
596 bool modified = (rec->f_sec_idcs != secondary_idcs);
597 RemoveNieces();
598 // re-adding is needed to refresh implied selected
599 if (modified) {
600 AddNieceForSelection(el, secondary, secondary_idcs);
601 }
602 }
603 else
604 {
605 RemoveNiece(el);
606 }
607 }
608 else
609 {
610 if (HasNieces()) RemoveNieces();
611 AddNieceForSelection(el, secondary, secondary_idcs);
612 }
613 }
614 else // Single selection with zero element --> clear selection.
615 {
616 if (HasNieces())
617 RemoveNieces();
618 else
619 changed = false;
620 }
621 }
622
623 if (changed)
625}
626
627///////////////////////////////////////////////////////////////////////////////////
628/// Wrapper for NewElementPickedStr that takes secondary indices as C-style string.
629/// Needed to be able to use TMethodCall interface.
630
631void REveSelection::NewElementPickedStr(ElementId_t id, bool multi, bool secondary, const char* secondary_idcs)
632{
633 static const REveException eh("REveSelection::NewElementPickedStr ");
634
635 if (secondary_idcs == 0 || secondary_idcs[0] == 0)
636 {
637 NewElementPicked(id, multi, secondary);
638 return;
639 }
640
641 static const std::regex comma_re("\\s*,\\s*", std::regex::optimize);
642 std::string str(secondary_idcs);
643 std::set<int> sis;
644 std::sregex_token_iterator itr(str.begin(), str.end(), comma_re, -1);
645 std::sregex_token_iterator end;
646
647 try {
648 while (itr != end) sis.insert(std::stoi(*itr++));
649 }
650 catch (const std::invalid_argument&) {
651 throw eh + "invalid secondary index argument '" + *itr + "' - must be int.";
652 }
653
654 NewElementPicked(id, multi, secondary, sis);
655}
656
657////////////////////////////////////////////////////////////////////////////////
658/// Clear selection if not empty.
659
661{
662 if (HasNieces())
663 {
664 RemoveNieces();
666 }
667}
668
669//==============================================================================
670
671////////////////////////////////////////////////////////////////////////////////
672/// Remove pointers to el from implied selected sets.
673
675{
676 int count = 0;
677
678 for (auto &i : fMap)
679 {
680 auto j = i.second.f_implied.find(el);
681
682 if (j != i.second.f_implied.end())
683 {
684 i.second.f_implied.erase(j);
685 el->DecImpliedSelected();
686 ++count;
687 }
688 }
689
690 return count;
691}
692
693////////////////////////////////////////////////////////////////////////////////
694/// Write core json. If rnr_offset negative, render data will not be written
695
697{
699
700 j["fVisibleEdgeColor"] = fVisibleEdgeColor;
701 j["fHiddenEdgeColor"] = fHiddenEdgeColor;
702
703 nlohmann::json sel_list = nlohmann::json::array();
704
705 for (auto &i : fMap)
706 {
707 nlohmann::json rec = {}, imp = nlohmann::json::array(), sec = nlohmann::json::array();
708
709 rec["primary"] = i.first->GetElementId();
710
711 // XXX if not empty / f_is_sec is false ???
712 for (auto &sec_id : i.second.f_sec_idcs)
713 sec.push_back(sec_id);
714
715 // XXX if not empty ???
716 for (auto &imp_el : i.second.f_implied) {
717 imp.push_back(imp_el->GetElementId());
718 imp_el->FillExtraSelectionData(rec["extra"], sec);
719
720 }
721 rec["implied"] = imp;
722
723
724 if (i.first->RequiresExtraSelectionData()) {
725 i.first->FillExtraSelectionData(rec["extra"], sec);
726 }
727
728 rec["sec_idcs"] = sec;
729
730 // stream tooltip in highlight type
731 if (!fIsMaster)
732 rec["tooltip"] = i.first->GetHighlightTooltip(i.second.f_sec_idcs);
733
734 sel_list.push_back(rec);
735 }
736
737 j["sel_list"] = sel_list;
738
739 j["UT_PostStream"] = "UT_Selection_Refresh_State"; // XXXX to be canonized
740
741 // std::cout << j.dump(4) << std::endl;
742
743 return 0;
744}
short Color_t
Definition: RtypesCore.h:92
unsigned char UChar_t
Definition: RtypesCore.h:38
const Bool_t kFALSE
Definition: RtypesCore.h:101
const Bool_t kTRUE
Definition: RtypesCore.h:100
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition: TError.cxx:221
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition: TError.cxx:232
R__EXTERN TEveManager * gEve
Definition: TEveManager.h:243
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t b
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t g
Int_t gDebug
Definition: TROOT.cxx:585
virtual void AddNiece(REveElement *el)
virtual void RemoveNiece(REveElement *el)
TClass * IsA() const
Return class for this element.
virtual REveElement * GetSelectionMaster()
Returns the master element - that is:
virtual Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset)
Write core json.
std::set< REveElement * > Set_t
REveException Exception-type thrown by Eve classes.
Definition: REveTypes.hxx:41
REveProjectable * GetProjectable() const
void RemoveNieceInternal(REveElement *el) override
Virtual from REveAunt.
void NewElementPicked(ElementId_t id, bool multi, bool secondary, const std::set< int > &secondary_idcs={})
Called from GUI when user picks or un-picks an element.
bool HasNiece(REveElement *el) const override
Check if elemenet el is selected (not implied selected).
bool AcceptNiece(REveElement *el) override
Pre-addition check.
std::shared_ptr< Deviator > fDeviator
!
void AddNieceForSelection(REveElement *, bool secondary, const std::set< int > &)
void AddNieceInternal(REveElement *el) override
Add an element into selection, virtual from REveAunt.
REveElement * MapPickedToSelected(REveElement *el)
Given element el that was picked or clicked by the user, find the parent/ancestor element that should...
void RemoveImpliedSelected(REveElement *el)
Remove element from all implied-selected sets.
int RemoveImpliedSelectedReferencesTo(REveElement *el)
Remove pointers to el from implied selected sets.
void SelectionRemoved(REveElement *el)
Emit SelectionRemoved signal.
void SetHiddenEdgeColorRGB(UChar_t r, UChar_t g, UChar_t b)
Set hidden highlight color.
virtual ~REveSelection()
Destructor.
REveSelection(const REveSelection &)=delete
void SetVisibleEdgeColorRGB(UChar_t r, UChar_t g, UChar_t b)
Set visible highlight color.
virtual void ActivateSelection()
Activate this selection.
bool HasNieces() const override
Check if any elements are selected.
void SetHighlightMode()
Set to 'highlight' mode.
void SelectionCleared()
Emit SelectionCleared signal.
virtual void DeactivateSelection()
Deactivate this selection.
void DoElementSelect(SelMap_i &entry)
Select element indicated by the entry and fill its implied-selected set.
Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset) override
Write core json. If rnr_offset negative, render data will not be written.
Record * find_record(REveElement *el)
void NewElementPickedInternal(REveElement *el, bool multi, bool secondary, const std::set< int > &secondary_idcs)
Called from NewElementPicked or Deviator::DeviateSelection.
virtual void UserRePickedElement(REveElement *el)
Called when element selection is repeated.
virtual void UserPickedElement(REveElement *el, Bool_t multi=kFALSE)
Called when user picks/clicks on an element.
void RecheckImpliedSetForElement(REveElement *el)
If given element is selected or implied-selected within this selection then recheck implied-set for g...
void SelectionRepeated(REveElement *el)
Emit SelectionRepeated signal.
void RecheckImpliedSet(SelMap_i &entry)
Recalculate implied-selected state for given selection entry.
void SelectionAdded(REveElement *el)
Emit SelectionAdded signal.
void NewElementPickedStr(ElementId_t id, bool multi, bool secondary, const char *secondary_idcs="")
Wrapper for NewElementPickedStr that takes secondary indices as C-style string.
void RemoveNieces() override
Add an element into selection, virtual from REveAunt.
void DoElementUnselect(SelMap_i &entry)
Deselect element indicated by the entry and clear its implied-selected set.
void ClearSelection()
Clear selection if not empty.
virtual void UserUnPickedElement(REveElement *el)
Called when an element is unselected.
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition: TClass.cxx:4863
static Int_t GetColor(const char *hexcolor)
Static method returning color number for color specified by hex color string of form: "#rrggbb",...
Definition: TColor.cxx:1823
const Int_t n
Definition: legend1.C:16
static constexpr double ns
basic_json<> json
Definition: REveElement.hxx:62