1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkContextScene.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #include "vtkContextScene.h"
17 
18 #include "vtkContextItem.h"
19 #include "vtkContext2D.h"
20 #include "vtkTransform2D.h"
21 #include "vtkMatrix3x3.h"
22 #include "vtkContextScenePrivate.h"
23 #include "vtkContextMouseEvent.h"
24 #include "vtkContextKeyEvent.h"
25 #include "vtkNew.h"
26 
27 // Get my new commands
28 #include "vtkCommand.h"
29 
30 #include "vtkAnnotationLink.h"
31 #include "vtkRenderWindowInteractor.h"
32 #include "vtkRenderWindow.h"
33 #include "vtkRenderer.h"
34 #include "vtkObjectFactory.h"
35 #include "vtkAbstractContextBufferId.h"
36 
37 // My STL containers
38 #include <cassert>
39 
40 //-----------------------------------------------------------------------------
41 // Minimal storage class for STL containers etc.
42 class vtkContextScene::Private
43 {
44 public:
Private()45   Private()
46     {
47     this->Event.SetButton(vtkContextMouseEvent::NO_BUTTON);
48     this->IsDirty = true;
49     }
~Private()50   ~Private()
51     {
52     }
53 
54   // The item with a current mouse down
55   vtkWeakPointer<vtkAbstractContextItem> itemMousePressCurrent;
56   // Item the mouse was last over
57   vtkWeakPointer<vtkAbstractContextItem> itemPicked;
58   // Mouse event structure
59   vtkContextMouseEvent Event;
60   bool IsDirty;
61 };
62 
63 //-----------------------------------------------------------------------------
64 vtkStandardNewMacro(vtkContextScene);
65 vtkCxxSetObjectMacro(vtkContextScene, AnnotationLink, vtkAnnotationLink);
66 
67 //-----------------------------------------------------------------------------
vtkContextScene()68 vtkContextScene::vtkContextScene()
69 {
70   this->Storage = new Private;
71   this->AnnotationLink = NULL;
72   this->Geometry[0] = 0;
73   this->Geometry[1] = 0;
74   this->BufferId=0;
75   this->BufferIdDirty=true;
76   this->BufferIdSupportTested=false;
77   this->BufferIdSupported=false;
78   this->UseBufferId = true;
79   this->ScaleTiles = true;
80   this->Transform = NULL;
81   this->Children = new vtkContextScenePrivate(NULL);
82   this->Children->SetScene(this);
83 }
84 
85 //-----------------------------------------------------------------------------
~vtkContextScene()86 vtkContextScene::~vtkContextScene()
87 {
88   delete this->Storage;
89   this->Storage = NULL;
90   this->SetAnnotationLink(NULL);
91   if(this->BufferId!=0)
92     {
93     this->BufferId->Delete();
94     }
95   if (this->Transform)
96     {
97     this->Transform->Delete();
98     }
99   delete this->Children;
100 }
101 
102 //-----------------------------------------------------------------------------
SetRenderer(vtkRenderer * r)103 void vtkContextScene::SetRenderer(vtkRenderer *r)
104 {
105   this->Renderer=r;
106   this->BufferIdSupportTested=false;
107 }
108 
109 //-----------------------------------------------------------------------------
Paint(vtkContext2D * painter)110 bool vtkContextScene::Paint(vtkContext2D *painter)
111 {
112   vtkDebugMacro("Paint event called.");
113   size_t size = this->Children->size();
114   if (size && this->Transform)
115     {
116     painter->PushMatrix();
117     painter->SetTransform(this->Transform);
118     }
119   this->Children->PaintItems(painter);
120   if (size && this->Transform)
121     {
122     painter->PopMatrix();
123     }
124   if(this->Storage->IsDirty)
125     {
126     this->BufferIdDirty=true;
127     }
128   this->Storage->IsDirty = false;
129   this->LastPainter=painter;
130   return true;
131 }
132 
133 //-----------------------------------------------------------------------------
PaintIds()134 void vtkContextScene::PaintIds()
135 {
136   vtkDebugMacro("PaintId called.");
137   size_t size = this->Children->size();
138 
139   if(size>16777214) // 24-bit limit, 0 reserved for background encoding.
140     {
141     vtkWarningMacro(<<"picking will not work properly as there are two many items. Items over 16777214 will be ignored.");
142     size=16777214;
143     }
144   for (size_t i = 0; i < size; ++i)
145     {
146     this->LastPainter->ApplyId(i+1);
147     (*this->Children)[i]->Paint(this->LastPainter);
148     }
149   this->Storage->IsDirty = false;
150 }
151 
152 //-----------------------------------------------------------------------------
AddItem(vtkAbstractContextItem * item)153 unsigned int vtkContextScene::AddItem(vtkAbstractContextItem *item)
154 {
155   return this->Children->AddItem(item);
156 }
157 
158 //-----------------------------------------------------------------------------
RemoveItem(vtkAbstractContextItem * item)159 bool vtkContextScene::RemoveItem(vtkAbstractContextItem* item)
160 {
161   return this->Children->RemoveItem(item);
162 }
163 
164 //-----------------------------------------------------------------------------
RemoveItem(unsigned int index)165 bool vtkContextScene::RemoveItem(unsigned int index)
166 {
167   return this->Children->RemoveItem(index);
168 }
169 
170 //-----------------------------------------------------------------------------
GetItem(unsigned int index)171 vtkAbstractContextItem * vtkContextScene::GetItem(unsigned int index)
172 {
173   if (index < this->Children->size())
174     {
175     return this->Children->at(index);
176     }
177   else
178     {
179     return 0;
180     }
181 }
182 
183 //-----------------------------------------------------------------------------
GetNumberOfItems()184 unsigned int vtkContextScene::GetNumberOfItems()
185 {
186   return static_cast<unsigned int>(this->Children->size());
187 }
188 
189 //-----------------------------------------------------------------------------
ClearItems()190 void vtkContextScene::ClearItems()
191 {
192   this->Children->Clear();
193 }
194 
195 
196 //-----------------------------------------------------------------------------
GetViewWidth()197 int vtkContextScene::GetViewWidth()
198 {
199   if (this->Renderer)
200     {
201     return this->Renderer->GetRenderWindow()->GetSize()[0];
202     }
203   else
204     {
205     return 0;
206     }
207 }
208 
209 //-----------------------------------------------------------------------------
GetViewHeight()210 int vtkContextScene::GetViewHeight()
211 {
212   if (this->Renderer)
213     {
214     return this->Renderer->GetRenderWindow()->GetSize()[1];
215     }
216   else
217     {
218     return 0;
219     }
220 }
221 
222 //-----------------------------------------------------------------------------
GetSceneWidth()223 int vtkContextScene::GetSceneWidth()
224 {
225   return this->Geometry[0];
226 }
227 
228 //-----------------------------------------------------------------------------
GetSceneHeight()229 int vtkContextScene::GetSceneHeight()
230 {
231   return this->Geometry[1];
232 }
233 
234 //-----------------------------------------------------------------------------
SetDirty(bool isDirty)235 void vtkContextScene::SetDirty(bool isDirty)
236 {
237   if (this->Storage->IsDirty == isDirty)
238     {
239     return;
240     }
241   this->Storage->IsDirty = isDirty;
242   if(this->Storage->IsDirty)
243     {
244     this->BufferIdDirty=true;
245     }
246   this->Modified();
247 }
248 
249 
250 //-----------------------------------------------------------------------------
GetDirty() const251 bool vtkContextScene::GetDirty() const
252 {
253   return this->Storage->IsDirty;
254 }
255 
256 // ----------------------------------------------------------------------------
ReleaseGraphicsResources()257 void vtkContextScene::ReleaseGraphicsResources()
258 {
259   if(this->BufferId!=0)
260     {
261     this->BufferId->ReleaseGraphicsResources();
262     }
263   for(vtkContextScenePrivate::const_iterator it = this->Children->begin();
264     it != this->Children->end(); ++it)
265     {
266     (*it)->ReleaseGraphicsResources();
267     }
268 }
269 
270 //-----------------------------------------------------------------------------
GetLastPainter()271 vtkWeakPointer<vtkContext2D> vtkContextScene::GetLastPainter()
272 {
273   return this->LastPainter;
274 }
275 
276 //-----------------------------------------------------------------------------
GetBufferId()277 vtkAbstractContextBufferId *vtkContextScene::GetBufferId()
278 {
279   return this->BufferId;
280 }
281 
282 //-----------------------------------------------------------------------------
SetTransform(vtkTransform2D * transform)283 void vtkContextScene::SetTransform(vtkTransform2D* transform)
284 {
285   if (this->Transform == transform)
286     {
287     return;
288     }
289   this->Transform->Delete();
290   this->Transform = transform;
291   this->Transform->Register(this);
292 }
293 
294 //-----------------------------------------------------------------------------
GetTransform()295 vtkTransform2D* vtkContextScene::GetTransform()
296 {
297   if (this->Transform)
298     {
299     return this->Transform;
300     }
301   else
302     {
303     this->Transform = vtkTransform2D::New();
304     return this->Transform;
305     }
306 }
307 
308 //-----------------------------------------------------------------------------
ProcessSelectionEvent(unsigned int rect[5])309 bool vtkContextScene::ProcessSelectionEvent(unsigned int rect[5])
310 {
311   cout << "ProcessSelectionEvent called! " << endl;
312   cout << "Rect:";
313   for (int i = 0; i < 5; ++i)
314     {
315     cout << "\t" << rect[i];
316     }
317   cout << endl;
318   return false;
319 }
320 
321 // ----------------------------------------------------------------------------
TestBufferIdSupport()322 void vtkContextScene::TestBufferIdSupport()
323 {
324   if (!this->BufferIdSupportTested)
325     {
326     vtkNew<vtkAbstractContextBufferId> b;
327     b->SetContext(this->Renderer->GetRenderWindow());
328     this->BufferIdSupported = b->IsSupported();
329     b->ReleaseGraphicsResources();
330     this->BufferIdSupportTested = true;
331     }
332 }
333 
334 // ----------------------------------------------------------------------------
UpdateBufferId()335 void vtkContextScene::UpdateBufferId()
336 {
337   int lowerLeft[2];
338   int width;
339   int height;
340   this->Renderer->GetTiledSizeAndOrigin(&width,&height,lowerLeft,
341                                         lowerLeft+1);
342 
343   if (this->BufferId==0 || this->BufferIdDirty ||
344       width!=this->BufferId->GetWidth() ||
345       height!=this->BufferId->GetHeight())
346     {
347     if (this->BufferId == 0)
348       {
349       this->BufferId = vtkAbstractContextBufferId::New();
350       this->BufferId->SetContext(this->Renderer->GetRenderWindow());
351       }
352     this->BufferId->SetWidth(width);
353     this->BufferId->SetHeight(height);
354     this->BufferId->Allocate();
355 
356     this->LastPainter->BufferIdModeBegin(this->BufferId);
357     this->PaintIds();
358     this->LastPainter->BufferIdModeEnd();
359 
360     this->BufferIdDirty = false;
361     }
362 }
363 
364 // ----------------------------------------------------------------------------
GetPickedItem()365 vtkAbstractContextItem* vtkContextScene::GetPickedItem()
366 {
367   vtkContextMouseEvent &event = this->Storage->Event;
368   for(vtkContextScenePrivate::const_reverse_iterator it =
369       this->Children->rbegin(); it != this->Children->rend(); ++it)
370     {
371     vtkAbstractContextItem* item = (*it)->GetPickedItem(event);
372     if (item)
373       {
374       return item;
375       }
376     }
377   return NULL;
378 }
379 
380 // ----------------------------------------------------------------------------
GetPickedItem(int x,int y)381 vtkIdType vtkContextScene::GetPickedItem(int x, int y)
382 {
383   vtkIdType result = -1;
384   this->TestBufferIdSupport();
385   if (this->UseBufferId && this->BufferIdSupported)
386     {
387     this->UpdateBufferId();
388     result=this->BufferId->GetPickedItem(x,y);
389     }
390   else
391     {
392     size_t i = this->Children->size()-1;
393     vtkContextMouseEvent &event = this->Storage->Event;
394     for(vtkContextScenePrivate::const_reverse_iterator it =
395         this->Children->rbegin(); it != this->Children->rend(); ++it, --i)
396       {
397       if ((*it)->Hit(event))
398         {
399         result = static_cast<vtkIdType>(i);
400         break;
401         }
402       }
403     }
404 
405   // Work-around for Qt bug under Linux (and maybe other platforms), 4.5.2
406   // or 4.6.2 :
407   // when the cursor leaves the window, Qt returns an extra mouse move event
408   // with coordinates out of the window area. The problem is that the pixel
409   // underneath is not owned by the OpenGL context, hence the bufferid contains
410   // garbage (see OpenGL pixel ownership test).
411   // As a workaround, any value out of the scope of
412   // [-1,this->GetNumberOfItems()-1] is set to -1 (<=> no hit)
413 
414   if(result<-1 || result>=static_cast<vtkIdType>(this->GetNumberOfItems()))
415     {
416     result=-1;
417     }
418 
419   assert("post: valid_result" && result>=-1 &&
420          result<static_cast<vtkIdType>(this->GetNumberOfItems()));
421   return result;
422 }
423 
424 //-----------------------------------------------------------------------------
MouseMoveEvent(const vtkContextMouseEvent & e)425 bool vtkContextScene::MouseMoveEvent(const vtkContextMouseEvent &e)
426 {
427   bool res = false;
428   vtkContextMouseEvent &event = this->Storage->Event;
429   this->EventCopy(e);
430 
431   vtkAbstractContextItem* newItemPicked = this->GetPickedItem();
432 #if 0
433   if (newItemPicked)
434     {
435     cerr << "picked a " << newItemPicked->GetClassName() << endl;
436     }
437   else
438     {
439     cerr << "picked nothing" << endl;
440     }
441 #endif
442   if (this->Storage->itemPicked.GetPointer() != newItemPicked)
443     {
444     if (this->Storage->itemPicked.GetPointer())
445       {
446       // Make sure last picked object is still part of this scene.
447       if (this->Storage->itemPicked->GetScene() == this)
448         {
449         vtkAbstractContextItem* cur = this->Storage->itemPicked;
450         res = this->ProcessItem(cur, event, &vtkAbstractContextItem::MouseLeaveEvent) || res;
451         }
452       }
453     if (newItemPicked)
454       {
455       vtkAbstractContextItem* cur = newItemPicked;
456       res = this->ProcessItem(cur, event, &vtkAbstractContextItem::MouseEnterEvent) || res;
457       }
458     }
459 
460   this->Storage->itemPicked = newItemPicked;
461 
462   // Fire mouse move event regardless of where it occurred.
463 
464   // Check if there is a selected item that needs to receive a move event
465   if (this->Storage->itemMousePressCurrent.GetPointer() &&
466       this->Storage->itemMousePressCurrent->GetScene() == this)
467     {
468     vtkAbstractContextItem* cur = this->Storage->itemMousePressCurrent;
469     res = this->ProcessItem(cur, event, &vtkAbstractContextItem::MouseMoveEvent) || res;
470     }
471   else if (this->Storage->itemPicked.GetPointer())
472     {
473     vtkAbstractContextItem* cur = this->Storage->itemPicked;
474     res = this->ProcessItem(cur, event, &vtkAbstractContextItem::MouseMoveEvent) || res;
475     }
476 
477   // Update the last positions now
478   event.SetLastScreenPos(event.GetScreenPos());
479   event.SetLastScenePos(event.GetScenePos());
480   event.SetLastPos(event.GetPos());
481   return res;
482 }
483 
484 //-----------------------------------------------------------------------------
ButtonPressEvent(const vtkContextMouseEvent & e)485 bool vtkContextScene::ButtonPressEvent(const vtkContextMouseEvent &e)
486 {
487   switch (e.GetButton())
488     {
489     case vtkContextMouseEvent::LEFT_BUTTON:
490       this->InvokeEvent(vtkCommand::LeftButtonPressEvent);
491       break;
492     case vtkContextMouseEvent::MIDDLE_BUTTON:
493       this->InvokeEvent(vtkCommand::MiddleButtonPressEvent);
494       break;
495     case vtkContextMouseEvent::RIGHT_BUTTON:
496       this->InvokeEvent(vtkCommand::RightButtonPressEvent);
497       break;
498     default:
499       break;
500     }
501 
502   bool res = false;
503   vtkContextMouseEvent &event = this->Storage->Event;
504   this->EventCopy(e);
505   event.SetLastScreenPos(event.GetScreenPos());
506   event.SetLastScenePos(event.GetScenePos());
507   event.SetLastPos(event.GetPos());
508   event.SetButton(e.GetButton());
509 
510   vtkAbstractContextItem* newItemPicked = this->GetPickedItem();
511   if (newItemPicked)
512     {
513     vtkAbstractContextItem* cur = newItemPicked;
514     res = this->ProcessItem(cur, event,
515                             &vtkAbstractContextItem::MouseButtonPressEvent);
516     }
517   this->Storage->itemMousePressCurrent = newItemPicked;
518   return res;
519 }
520 
521 //-----------------------------------------------------------------------------
ButtonReleaseEvent(const vtkContextMouseEvent & e)522 bool vtkContextScene::ButtonReleaseEvent(const vtkContextMouseEvent &e)
523 {
524   switch (e.GetButton())
525     {
526     case vtkContextMouseEvent::LEFT_BUTTON:
527       this->InvokeEvent(vtkCommand::LeftButtonReleaseEvent);
528       break;
529     case vtkContextMouseEvent::MIDDLE_BUTTON:
530       this->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent);
531       break;
532     case vtkContextMouseEvent::RIGHT_BUTTON:
533       this->InvokeEvent(vtkCommand::RightButtonReleaseEvent);
534       break;
535     default:
536       break;
537     }
538 
539   bool res = false;
540   if (this->Storage->itemMousePressCurrent.GetPointer())
541     {
542     vtkContextMouseEvent &event = this->Storage->Event;
543     this->EventCopy(e);
544     event.SetButton(e.GetButton());
545     vtkAbstractContextItem* cur = this->Storage->itemMousePressCurrent;
546     res = this->ProcessItem(cur, event,
547                             &vtkAbstractContextItem::MouseButtonReleaseEvent);
548     this->Storage->itemMousePressCurrent = NULL;
549     }
550   this->Storage->Event.SetButton(vtkContextMouseEvent::NO_BUTTON);
551   return res;
552 }
553 
554 //-----------------------------------------------------------------------------
DoubleClickEvent(const vtkContextMouseEvent & e)555 bool vtkContextScene::DoubleClickEvent(const vtkContextMouseEvent &e)
556 {
557   bool res = false;
558   vtkContextMouseEvent &event = this->Storage->Event;
559   this->EventCopy(e);
560   event.SetLastScreenPos(event.GetScreenPos());
561   event.SetLastScenePos(event.GetScenePos());
562   event.SetLastPos(event.GetPos());
563   event.SetButton(e.GetButton());
564 
565   vtkAbstractContextItem* newItemPicked = this->GetPickedItem();
566   if (newItemPicked)
567     {
568     vtkAbstractContextItem* cur = newItemPicked;
569     res = this->ProcessItem(cur, event,
570                             &vtkAbstractContextItem::MouseDoubleClickEvent);
571     }
572   return res;
573 }
574 
575 //-----------------------------------------------------------------------------
MouseWheelEvent(int delta,const vtkContextMouseEvent & e)576 bool vtkContextScene::MouseWheelEvent(int delta,const vtkContextMouseEvent &e)
577 {
578   bool res = false;
579   vtkContextMouseEvent &event = this->Storage->Event;
580   this->EventCopy(e);
581   event.SetLastScreenPos(event.GetScreenPos());
582   event.SetLastScenePos(event.GetScenePos());
583   event.SetLastPos(event.GetPos());
584   event.SetButton(vtkContextMouseEvent::NO_BUTTON);
585 
586   vtkAbstractContextItem* newItemPicked = this->GetPickedItem();
587   if (newItemPicked)
588     {
589     vtkContextMouseEvent itemEvent = event;
590     vtkAbstractContextItem* cur = newItemPicked;
591     itemEvent.SetPos(cur->MapFromScene(event.GetPos()));
592     itemEvent.SetLastPos(cur->MapFromScene(event.GetLastPos()));
593     while (cur && !cur->MouseWheelEvent(itemEvent, delta))
594       {
595       cur = cur->GetParent();
596       if (cur)
597         {
598         itemEvent.SetPos(cur->MapToParent(itemEvent.GetPos()));
599         itemEvent.SetLastPos(cur->MapToParent(itemEvent.GetLastPos()));
600         }
601       }
602     res = (cur != 0);
603     }
604   return res;
605 }
606 
607 //-----------------------------------------------------------------------------
KeyPressEvent(const vtkContextKeyEvent & keyEvent)608 bool vtkContextScene::KeyPressEvent(const vtkContextKeyEvent &keyEvent)
609 {
610   vtkContextMouseEvent &event = this->Storage->Event;
611   event.SetScreenPos(keyEvent.GetPosition());
612   vtkAbstractContextItem* newItemPicked = this->GetPickedItem();
613   if (newItemPicked)
614     {
615     return newItemPicked->KeyPressEvent(keyEvent);
616     }
617   return false;
618 }
619 
620 //-----------------------------------------------------------------------------
KeyReleaseEvent(const vtkContextKeyEvent & keyEvent)621 bool vtkContextScene::KeyReleaseEvent(const vtkContextKeyEvent &keyEvent)
622 {
623   vtkContextMouseEvent &event = this->Storage->Event;
624   event.SetScreenPos(keyEvent.GetPosition());
625   vtkAbstractContextItem* newItemPicked = this->GetPickedItem();
626   if (newItemPicked)
627     {
628     return newItemPicked->KeyReleaseEvent(keyEvent);
629     }
630   return false;
631 }
632 
633 //-----------------------------------------------------------------------------
ProcessItem(vtkAbstractContextItem * cur,const vtkContextMouseEvent & event,MouseEvents eventPtr)634 inline bool vtkContextScene::ProcessItem(vtkAbstractContextItem* cur,
635                                          const vtkContextMouseEvent& event,
636                                          MouseEvents eventPtr)
637 {
638   bool res = false;
639   vtkContextMouseEvent itemEvent = event;
640   itemEvent.SetPos(cur->MapFromScene(event.GetPos()));
641   itemEvent.SetLastPos(cur->MapFromScene(event.GetLastPos()));
642   while (cur && !(cur->*eventPtr)(itemEvent))
643     {
644     cur = cur->GetParent();
645     if (cur)
646       {
647       itemEvent.SetPos(cur->MapToParent(itemEvent.GetPos()));
648       itemEvent.SetLastPos(cur->MapToParent(itemEvent.GetLastPos()));
649       }
650     }
651   res = (cur != 0);
652   return res;
653 }
654 
655 //-----------------------------------------------------------------------------
EventCopy(const vtkContextMouseEvent & e)656 inline void vtkContextScene::EventCopy(const vtkContextMouseEvent &e)
657 {
658   vtkContextMouseEvent &event = this->Storage->Event;
659   event.SetPos(e.GetPos());
660   event.SetScreenPos(vtkVector2i(e.GetPos().Cast<int>().GetData()));
661   event.SetScenePos(e.GetPos());
662   event.SetInteractor(e.GetInteractor());
663 }
664 
665 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)666 void vtkContextScene::PrintSelf(ostream &os, vtkIndent indent)
667 {
668   this->Superclass::PrintSelf(os, indent);
669   // Print out the chart's geometry if it has been set
670   os << indent << "Widthxheight: " << this->Geometry[0] << "\t" << this->Geometry[1]
671      << endl;
672 }
673