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