Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGImageMap.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id$
2 // Author: Valeriy Onuchin & Fons Rademakers 18/10/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TGImageMap (with TGRegion and TGRegionWithId help classes) //
15 // //
16 // A TGImageMap provides the functionality like a clickable image in //
17 // a web browser with sensitive regions (MAP HTML tag). //
18 // //
19 //////////////////////////////////////////////////////////////////////////
20 
21 #include "TGImageMap.h"
22 #include "TRefCnt.h"
23 #include "TGMenu.h"
24 #include "TGToolTip.h"
25 #include "TList.h"
26 #include "TArrayS.h"
27 
28 
29 ClassImp(TGRegion);
30 ClassImp(TGRegionWithId);
31 ClassImpQ(TGImageMap)
32 
33 
34 TGRegionWithId *gCurrentRegion; // current region
35 
36 static TGRegion *gEmptyRegion = 0;
37 static Int_t gPointerX; // current X mouse position
38 static Int_t gPointerY; // current Y mouse position
39 
40 
41 
42 class TGRegionData : public TRefCnt {
43 
44 friend class TGRegion;
45 
46 private:
47  Region_t fRgn; // region handle
48  Bool_t fIsNull; // true if null region
49 
50 public:
51  TGRegionData() { fRgn = 0; fIsNull = kTRUE; AddReference(); }
52  ~TGRegionData() { }
53  TGRegionData &operator=(const TGRegionData &r);
54 };
55 
56 ////////////////////////////////////////////////////////////////////////////////
57 /// Assignemnt of region data object.
58 
59 TGRegionData &TGRegionData::operator=(const TGRegionData &r)
60 {
61  if (this != &r) {
62  fRefs = r.fRefs;
63  fRgn = r.fRgn;
64  fIsNull = r.fIsNull;
65  }
66  return *this;
67 }
68 
69 
70 ////////////////////////////////////////////////////////////////////////////////
71 ////////////////////////////////////////////////////////////////////////////////
72 /// Create a region object.
73 
74 TGRegion::TGRegion()
75 {
76  if (!gEmptyRegion) // avoid too many allocs
77  gEmptyRegion = new TGRegion(kTRUE);
78 
79  fData = gEmptyRegion->fData;
80  fData->AddReference();
81 }
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// Create empty region.
85 
86 TGRegion::TGRegion(Bool_t is_null)
87 {
88  fData = new TGRegionData;
89  fData->fRgn = gVirtualX->CreateRegion();
90  fData->fIsNull = is_null;
91 }
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 /// Create and initialize a region with a rectangle.
95 
96 TGRegion::TGRegion(Int_t x, Int_t y, UInt_t w, UInt_t h, ERegionType)
97 {
98  fData = new TGRegionData;
99  fData->fRgn = gVirtualX->CreateRegion();
100  fData->fIsNull = kFALSE;
101 
102  Rectangle_t xr;
103  xr.fX = (Short_t) x;
104  xr.fY = (Short_t) y;
105  xr.fWidth = (UShort_t) w;
106  xr.fHeight = (UShort_t) h;
107  gVirtualX->UnionRectWithRegion(&xr, fData->fRgn, fData->fRgn);
108 }
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// Create and intialize a region with a polygon.
112 
113 TGRegion::TGRegion(Int_t n, TPoint *points, Bool_t winding)
114 {
115  fData = new TGRegionData;
116  fData->fIsNull = kFALSE;
117  Point_t *gpoints = new Point_t[n];
118 
119  for (int i = 0; i < n; i++) {
120  gpoints[i].fX = (Short_t) points[i].GetX();
121  gpoints[i].fY = (Short_t) points[i].GetY();
122  }
123 
124  fData->fRgn = gVirtualX->PolygonRegion(gpoints, n, winding);
125 }
126 
127 ////////////////////////////////////////////////////////////////////////////////
128 /// Create and initialize a region with an X and a Y array of points.
129 
130 TGRegion::TGRegion(const TArrayS &x, const TArrayS &y, Bool_t winding)
131 {
132  fData = new TGRegionData;
133  fData->fIsNull = kFALSE;
134 
135  Int_t n = x.GetSize();
136  if (n != y.GetSize()) {
137  Error("TGRegion", "x and y arrays must have same length");
138  return;
139  }
140  Point_t *gpoints = new Point_t[n];
141 
142  for (int i = 0; i < n; i++) {
143  gpoints[i].fX = x.GetArray()[i];
144  gpoints[i].fY = y.GetArray()[i];
145  }
146 
147  fData->fRgn = gVirtualX->PolygonRegion(gpoints, n, winding);
148 }
149 
150 ////////////////////////////////////////////////////////////////////////////////
151 /// Create and initialize a region with an X and Y array of points.
152 
153 TGRegion::TGRegion(Int_t n, Int_t *x, Int_t *y, Bool_t winding)
154 {
155  fData = new TGRegionData;
156  fData->fIsNull = kFALSE;
157  Point_t *gpoints = new Point_t[n];
158 
159  for (int i = 0; i < n; i++) {
160  gpoints[i].fX = x[i];
161  gpoints[i].fY = y[i];
162  }
163 
164  fData->fRgn = gVirtualX->PolygonRegion(gpoints, n, winding);
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// Region copy constructor.
169 
170 TGRegion::TGRegion(const TGRegion &r) : TObject(r)
171 {
172  fData = r.fData;
173  fData->AddReference();
174 }
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 /// Delete a region.
178 
179 TGRegion::~TGRegion()
180 {
181  if (fData->RemoveReference() <= 0) {
182  gVirtualX->DestroyRegion(fData->fRgn);
183  delete fData;
184  }
185 }
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// Region assignment operator.
189 
190 TGRegion &TGRegion::operator=(const TGRegion &r)
191 {
192  if (this != &r) {
193  TObject::operator=(r);
194  r.fData->AddReference();
195 
196  if (fData->RemoveReference() <= 0) {
197  gVirtualX->DestroyRegion(fData->fRgn);
198  delete fData;
199  }
200  fData = r.fData;
201  }
202  return *this;
203 }
204 
205 ////////////////////////////////////////////////////////////////////////////////
206 /// Copy a region.
207 
208 TGRegion TGRegion::CopyRegion() const
209 {
210  TGRegion r(fData->fIsNull);
211  gVirtualX->UnionRegion(fData->fRgn, r.fData->fRgn, r.fData->fRgn);
212  return r;
213 }
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// Return true if region is not set.
217 
218 Bool_t TGRegion::IsNull() const
219 {
220  return fData->fIsNull;
221 }
222 
223 ////////////////////////////////////////////////////////////////////////////////
224 /// Return true if region is empty.
225 
226 Bool_t TGRegion::IsEmpty() const
227 {
228  return fData->fIsNull || gVirtualX->EmptyRegion(fData->fRgn);
229 }
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 /// Return true if point p is contained in the region.
233 
234 Bool_t TGRegion::Contains(const TPoint &p) const
235 {
236  return gVirtualX->PointInRegion((Int_t)p.GetX(), (Int_t)p.GetY(), fData->fRgn);
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// Return true if point (x,y) is contained in the region.
241 
242 Bool_t TGRegion::Contains(Int_t x, Int_t y) const
243 {
244  return gVirtualX->PointInRegion(x, y, fData->fRgn);
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////////
248 /// Return the union of this region with r.
249 
250 TGRegion TGRegion::Unite(const TGRegion &r) const
251 {
252  TGRegion result(kFALSE);
253  gVirtualX->UnionRegion(fData->fRgn, r.fData->fRgn, result.fData->fRgn);
254  return result;
255 }
256 
257 ////////////////////////////////////////////////////////////////////////////////
258 /// Returns a region which is the intersection of this region and r.
259 
260 TGRegion TGRegion::Intersect(const TGRegion &r) const
261 {
262  TGRegion result(kFALSE);
263  gVirtualX->IntersectRegion(fData->fRgn, r.fData->fRgn, result.fData->fRgn);
264  return result;
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Returns a region which is r subtracted from this region.
269 
270 TGRegion TGRegion::Subtract(const TGRegion &r) const
271 {
272  TGRegion result(kFALSE);
273  gVirtualX->SubtractRegion(fData->fRgn, r.fData->fRgn, result.fData->fRgn);
274  return result;
275 }
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 /// Returns a region which is the difference between the union and
279 /// intersection this region and r.
280 
281 TGRegion TGRegion::Eor(const TGRegion &r) const
282 {
283  TGRegion result(kFALSE);
284  gVirtualX->XorRegion(fData->fRgn, r.fData->fRgn, result.fData->fRgn);
285  return result;
286 }
287 
288 ////////////////////////////////////////////////////////////////////////////////
289 /// Return dimension of region (widht, height).
290 
291 TGDimension TGRegion::GetDimension() const
292 {
293  Rectangle_t r = { 0, 0, 0, 0 };
294  gVirtualX->GetRegionBox(fData->fRgn, &r);
295  return TGDimension(r.fWidth, r.fHeight);
296 }
297 
298 ////////////////////////////////////////////////////////////////////////////////
299 /// Return position of region (x, y).
300 
301 TGPosition TGRegion::GetPosition() const
302 {
303  Rectangle_t r = { 0, 0, 0, 0 };
304  gVirtualX->GetRegionBox(fData->fRgn, &r);
305  return TGPosition(r.fX, r.fY);
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Region == operator.
310 
311 Bool_t TGRegion::operator==(const TGRegion &r) const
312 {
313  return fData == r.fData ?
314  kTRUE : gVirtualX->EqualRegion(fData->fRgn, r.fData->fRgn);
315 }
316 
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 ////////////////////////////////////////////////////////////////////////////////
320 /// Create GUI region (with id and possible tooltip).
321 
322 TGRegionWithId::TGRegionWithId() : TGRegion()
323 {
324  fId = 0;
325  fTip = 0;
326  fPopup = 0;
327 }
328 
329 ////////////////////////////////////////////////////////////////////////////////
330 /// Create GUI region (with id and possible tooltip).
331 
332 TGRegionWithId::TGRegionWithId(Int_t id, Int_t x, Int_t y,
333  UInt_t w, UInt_t h, ERegionType type) :
334  TGRegion(x, y, w, h, type)
335 {
336  fId = id;
337  fTip = 0;
338  fPopup = 0;
339 }
340 
341 ////////////////////////////////////////////////////////////////////////////////
342 /// Create GUI region (with id and possible tooltip).
343 
344 TGRegionWithId::TGRegionWithId(Int_t id, Int_t n, TPoint *points,
345  Bool_t winding) :
346  TGRegion(n, points, winding)
347 {
348  fId = id;
349  fTip = 0;
350  fPopup = 0;
351 }
352 
353 ////////////////////////////////////////////////////////////////////////////////
354 /// Copy constructor.
355 
356 TGRegionWithId::TGRegionWithId(const TGRegionWithId &reg) : TGRegion(reg)
357 {
358  fId = reg.GetId();
359  fTip = 0;
360  fPopup = 0;
361 }
362 
363 ////////////////////////////////////////////////////////////////////////////////
364 /// Copy ctor which allows setting of new id.
365 
366 TGRegionWithId::TGRegionWithId(const TGRegion &reg, Int_t id) :
367  TGRegion(reg)
368 {
369  fId = id;
370  fTip = 0;
371  fPopup = 0;
372 }
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 /// Cleanup.
376 
377 TGRegionWithId::~TGRegionWithId()
378 {
379  delete fTip;
380 }
381 
382 ////////////////////////////////////////////////////////////////////////////////
383 /// Display popup menu associated with this region.
384 
385 void TGRegionWithId::DisplayPopup()
386 {
387  if (fPopup) fPopup->PlaceMenu(gPointerX, gPointerY, kTRUE, kTRUE);
388 }
389 
390 ////////////////////////////////////////////////////////////////////////////////
391 /// Set tool tip text associated with this region. The delay is in
392 /// milliseconds (minimum 250). To remove tool tip call method with
393 /// text = 0.
394 
395 void TGRegionWithId::SetToolTipText(const char *text, Long_t delayms,
396  const TGFrame *frame)
397 {
398  if (fTip) {
399  delete fTip;
400  fTip = 0;
401  }
402 
403  if (text && strlen(text))
404  fTip = new TGToolTip(gClient->GetDefaultRoot(), frame, text, delayms);
405 }
406 
407 ////////////////////////////////////////////////////////////////////////////////
408 ////////////////////////////////////////////////////////////////////////////////
409 /// Create an image map widget.
410 
411 TGImageMap::TGImageMap(const TGWindow *p, const TGPicture *pic) :
412  TGPictureButton(p, pic)
413 {
414  fCursorMouseOut = kPointer;
415  fCursorMouseOver = kHand;
416  fListOfRegions = new TList;
417  fTrash = new TList;
418  fMainTip = 0;
419  fLastVisited = 0;
420  fNavMode = kNavRegions;
421 
422  SetDisabledPicture(fPic);
423  SetState(kButtonDisabled);
424 
425  gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
426  kButtonPressMask | kButtonReleaseMask |
427  kPointerMotionMask, kNone, kNone);
428 
429  AddInput(kKeyPressMask | kKeyReleaseMask | kPointerMotionMask |
430  kStructureNotifyMask | kLeaveWindowMask);
431  SetWindowName();
432 }
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 /// Create an image map widget.
436 
437 TGImageMap::TGImageMap(const TGWindow *p, const TString &pic) :
438  TGPictureButton(p, pic.Data())
439 {
440  fCursorMouseOut = kPointer;
441  fCursorMouseOver = kHand;
442  fListOfRegions = new TList;
443  fTrash = new TList;
444  fMainTip = 0;
445  fLastVisited = 0;
446  fNavMode = kNavRegions;
447 
448  SetDisabledPicture(fPic);
449  SetState(kButtonDisabled);
450 
451  gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
452  kButtonPressMask | kButtonReleaseMask |
453  kPointerMotionMask, kNone, kNone);
454 
455  AddInput(kKeyPressMask | kKeyReleaseMask | kPointerMotionMask |
456  kStructureNotifyMask | kLeaveWindowMask);
457  SetWindowName();
458 }
459 
460 ////////////////////////////////////////////////////////////////////////////////
461 /// Cleanup image map widget.
462 
463 TGImageMap::~TGImageMap()
464 {
465  delete fMainTip;
466  fTrash->Delete();
467  delete fTrash;
468  fListOfRegions->Delete();
469  delete fListOfRegions;
470 }
471 
472 ////////////////////////////////////////////////////////////////////////////////
473 /// Add a region to the image map.
474 
475 void TGImageMap::AddRegion(const TGRegion &region, Int_t id)
476 {
477  fListOfRegions->Add(new TGRegionWithId(region, id));
478 }
479 
480 ////////////////////////////////////////////////////////////////////////////////
481 /// Create popoup menu or returns existing for regions with specified id.
482 
483 TGPopupMenu *TGImageMap::CreatePopup(Int_t id)
484 {
485  TIter next(fListOfRegions);
486  TGRegionWithId *region;
487  TGPopupMenu *popup = 0;
488  TGPopupMenu *newpopup = 0;
489 
490  while ((region = (TGRegionWithId*)next())) {
491  if (id == region->GetId()) {
492  popup = region->GetPopup();
493  if (!popup && !newpopup) {
494  newpopup = new TGPopupMenu(this);
495  fTrash->Add(newpopup);
496  }
497  if (newpopup) region->SetPopup(newpopup);
498  }
499  }
500  return newpopup ? newpopup : popup;
501 }
502 
503 ////////////////////////////////////////////////////////////////////////////////
504 /// Return popup for regions with specified id.
505 
506 TGPopupMenu *TGImageMap::GetPopup(Int_t id)
507 {
508  TIter next(fListOfRegions);
509  TGRegionWithId *region;
510 
511  while ((region = (TGRegionWithId*)next())) {
512  if (id == region->GetId()) return region->GetPopup();
513  }
514  return 0;
515 }
516 
517 ////////////////////////////////////////////////////////////////////////////////
518 /// Handle mouse motion events.
519 
520 Bool_t TGImageMap::HandleMotion(Event_t *event)
521 {
522  TIter next(fListOfRegions);
523  TGRegionWithId *region;
524 
525  if (fNavMode != kNavRegions) return kTRUE;
526  gPointerX = event->fX;
527  gPointerY = event->fY;
528 
529  while ((region = (TGRegionWithId*)next())) {
530  if (region->Contains(gPointerX, gPointerY)) {
531  if (fLastVisited == region->GetId()) return kTRUE;
532  if (fLastVisited) OnMouseOut(fLastVisited);
533  fLastVisited = region->GetId();
534  fTip = region->GetToolTipText();
535  gCurrentRegion = region;
536  OnMouseOver(fLastVisited);
537  return kTRUE;
538  }
539  }
540 
541  if (fLastVisited) {
542  OnMouseOut(fLastVisited);
543  fTip = fMainTip;
544  }
545  fLastVisited = 0; // main
546  return kTRUE;
547 }
548 
549 ////////////////////////////////////////////////////////////////////////////////
550 /// Handle double click events.
551 
552 Bool_t TGImageMap::HandleDoubleClick(Event_t *event)
553 {
554  TIter next(fListOfRegions);
555  TGRegionWithId *region;
556 
557  if (fTip) fTip->Hide();
558  if (event->fCode != kButton1 ) return kTRUE;
559  if (fNavMode != kNavRegions) return kTRUE;
560 
561  gPointerX = event->fX;
562  gPointerY = event->fY;
563 
564  while ((region = (TGRegionWithId*)next())) {
565  if (region->Contains(gPointerX, gPointerY)) {
566  DoubleClicked(region->GetId());
567  gCurrentRegion = region;
568  return kTRUE;
569  }
570  }
571  DoubleClicked();
572  return kTRUE;
573 }
574 
575 ////////////////////////////////////////////////////////////////////////////////
576 /// Handle button events.
577 
578 Bool_t TGImageMap::HandleButton(Event_t *event)
579 {
580  TIter next(fListOfRegions);
581  TGRegionWithId *region;
582  TGPopupMenu *pop;
583 
584  if (fTip) fTip->Hide();
585  if (fNavMode != kNavRegions) return kTRUE;
586 
587  gPointerX = event->fX;
588  gPointerY = event->fY;
589 
590  while ((region = (TGRegionWithId*)next())) {
591  if (region->Contains(gPointerX, gPointerY)) {
592  gCurrentRegion = region;
593  if (event->fType == kButtonPress) {
594  if (event->fCode == kButton1 )
595  RegionClicked(region->GetId());
596  else if (event->fCode == kButton3 ) {
597  pop = region->GetPopup();
598  if (pop) pop->PlaceMenu(gPointerX, gPointerY, kTRUE, kTRUE);
599  }
600  }
601  return kTRUE;
602  }
603  }
604  if (event->fType == kButtonPress)
605  Clicked();
606  return kTRUE;
607 }
608 
609 ////////////////////////////////////////////////////////////////////////////////
610 /// Set tooltip text for main region.
611 
612 void TGImageMap::SetToolTipText(const char *text, Long_t delayms)
613 {
614  if (fMainTip) delete fMainTip;
615  fMainTip = 0;
616 
617  if (text && strlen(text))
618  fMainTip = new TGToolTip(fClient->GetDefaultRoot(), this, text, delayms);
619 }
620 
621 ////////////////////////////////////////////////////////////////////////////////
622 /// Set tooltip text for regions with specified id.
623 
624 void TGImageMap::SetToolTipText(Int_t id, const char *text, Long_t delayms)
625 {
626  TIter next(fListOfRegions);
627  TGRegionWithId *region;
628 
629  while ((region = (TGRegionWithId*)next())) {
630  if (id == region->GetId())
631  region->SetToolTipText(text, delayms, this);
632  }
633 }
634 
635 ////////////////////////////////////////////////////////////////////////////////
636 /// Handle when mouse moves over region id. Emits signal
637 /// OnMouseOver(Int_t).
638 
639 void TGImageMap::OnMouseOver(Int_t id)
640 {
641  if (fTip) fTip->Reset();
642  if (fMainTip) fMainTip->Hide();
643  gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(fCursorMouseOver));
644  Emit("OnMouseOver(Int_t)", id);
645 }
646 
647 ////////////////////////////////////////////////////////////////////////////////
648 /// Handle when mouse moves from region id. Emits signal
649 /// OnMouseOut(Int_t).
650 
651 void TGImageMap::OnMouseOut(Int_t id)
652 {
653  if(fTip) fTip->Hide();
654  if(fMainTip) fMainTip->Reset();
655  gVirtualX->SetCursor(fId,gVirtualX->CreateCursor(fCursorMouseOut));
656  Emit("OnMouseOut(Int_t)",id);
657 }
658 
659 ////////////////////////////////////////////////////////////////////////////////
660 /// Handle when mouse was clicked on region id. Emits signal
661 /// RegionClicked(Int_t).
662 
663 void TGImageMap::RegionClicked(Int_t id)
664 {
665  Emit("RegionClicked(Int_t)",id);
666 }
667 
668 ////////////////////////////////////////////////////////////////////////////////
669 /// Handle when mouse is double clicked on main map. Emits signal
670 /// DoubleClicked().
671 
672 void TGImageMap::DoubleClicked()
673 {
674  Emit("DoubleClicked()");
675 }
676 
677 ////////////////////////////////////////////////////////////////////////////////
678 /// Handle when mouse is double clicked on region id. Emits signal
679 /// DoubleClicked(Int_t).
680 
681 void TGImageMap::DoubleClicked(Int_t id)
682 {
683  Emit("DoubleClicked(Int_t)",id);
684 }