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>
16
17#include "TClass.h"
18#include "TColor.h"
19
20#include "json.hpp"
21
22using namespace ROOT::Experimental;
23namespace REX = ROOT::Experimental;
24
25/** \class REveSelection
26\ingroup REve
27Make sure there is a SINGLE running REveSelection for each
28selection type (select/highlight).
29*/
30
31////////////////////////////////////////////////////////////////////////////////
32/// Constructor.
33
34REveSelection::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
57}
58
59////////////////////////////////////////////////////////////////////////////////
60/// Destructor
61
63{
66}
67
68////////////////////////////////////////////////////////////////////////////////
69/// Set visible highlight color
70
72{
75}
76
77////////////////////////////////////////////////////////////////////////////////
78/// Set hidden highlight color
80{
83}
84
85////////////////////////////////////////////////////////////////////////////////
86/// Set to 'highlight' mode.
87
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
95}
96
97////////////////////////////////////////////////////////////////////////////////
98/// Select element indicated by the entry and fill its
99/// implied-selected set.
100
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
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
146{
147 return fMap.find(el) != fMap.end();
148}
149
150////////////////////////////////////////////////////////////////////////////////
151/// Check if any elements are selected.
152
154{
155 return ! fMap.empty();
156}
157
158////////////////////////////////////////////////////////////////////////////////
159/// Pre-addition check. Deny addition if el is already selected.
160/// Virtual from REveAunt.
161
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
172{
173 auto res = fMap.emplace(el, Record(el));
174 if (fActive) {
175 DoElementSelect(res.first);
176 SelectionAdded(el);
177 }
179}
180
181////////////////////////////////////////////////////////////////////////////////
182/// Virtual from REveAunt.
183
185{
186 auto i = fMap.find(el);
187
188 if (i != fMap.end())
189 {
190 if (fActive)
191 {
194 }
195 fMap.erase(i);
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
209{
210 if (IsEmpty()) return;
211
212 for (auto i = fMap.begin(); i != fMap.end(); ++i)
213 {
214 i->first->RemoveAunt(this);
216 }
217 fMap.clear();
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
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
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
274{
275 // Top-level selected.
276 {
277 auto i = fMap.find(el);
278 if (i != fMap.end())
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())
290 }
291 }
292}
293
294////////////////////////////////////////////////////////////////////////////////
295/// Emit SelectionAdded signal.
296
298{
299 // XXXX
300 // Emit("SelectionAdded(REveElement*)", (Long_t)el);
301}
302
303////////////////////////////////////////////////////////////////////////////////
304/// Emit SelectionRemoved signal.
305
307{
308 // XXXX
309 // Emit("SelectionRemoved(REveElement*)", (Long_t)el);
310}
311
312////////////////////////////////////////////////////////////////////////////////
313/// Emit SelectionCleared signal.
314
316{
317 // XXXX
318 // Emit("SelectionCleared()");
319}
320
321////////////////////////////////////////////////////////////////////////////////
322/// Emit SelectionRepeated signal.
323
325{
326 // XXXX
327 // Emit("SelectionRepeated(REveElement*)", (Long_t)el);
328}
329
330////////////////////////////////////////////////////////////////////////////////
331/// Activate this selection.
332
334{
335 if (fActive) return;
336
337 fActive = kTRUE;
338 for (auto i = fMap.begin(); i != fMap.end(); ++i) {
340 SelectionAdded(i->first);
341 }
342}
343
344////////////////////////////////////////////////////////////////////////////////
345/// Deactivate this selection.
346
348{
349 if (!fActive) return;
350
351 for (auto i = fMap.begin(); i != fMap.end(); ++i) {
353 }
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
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 }
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
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 }
442 }
443}
444
445////////////////////////////////////////////////////////////////////////////////
446/// Called when element selection is repeated.
447/// XXXX Old interface, not used in EVE-7.
448
450{
451 el = MapPickedToSelected(el);
452 if (el && HasNiece(el))
453 {
456 }
457}
458
459////////////////////////////////////////////////////////////////////////////////
460/// Called when an element is unselected.
461/// XXXX Old interface, not used in EVE-7.
462
464{
465 el = MapPickedToSelected(el);
466 if (el && HasNiece(el))
467 {
468 RemoveNiece(el);
470 }
471}
472
473//==============================================================================
474
475void 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)
579}
580
581////////////////////////////////////////////////////////////////////////////////
582/// Clear selection if not empty.
583
585{
586 if (HasNieces())
587 {
588 RemoveNieces();
590 }
591}
592
593//==============================================================================
594
595////////////////////////////////////////////////////////////////////////////////
596/// Remove pointers to el from implied selected sets.
597
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
621{
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}
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:36
const Bool_t kFALSE
Definition: RtypesCore.h:90
short Color_t
Definition: RtypesCore.h:81
R__EXTERN Int_t gDebug
Definition: RtypesCore.h:117
const Bool_t kTRUE
Definition: RtypesCore.h:89
void Info(const char *location, const char *msgfmt,...)
void Warning(const char *location, const char *msgfmt,...)
R__EXTERN TEveManager * gEve
Definition: TEveManager.h:243
virtual void AddNiece(REveElement *el)
virtual void RemoveNiece(REveElement *el)
TClass * IsA() const
Return class for this element.
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
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.
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)
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:4837
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
basic_json<> json
default JSON class
Definition: REveElement.hxx:88
bool f_is_sec
! is secondary-selected – XXXX do i need it ????