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