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