52f99d93 |
1 | // Created on: 2012-05-28 |
2 | // |
3 | // Copyright (c) 2011-2014 OPEN CASCADE SAS |
4 | // |
5 | // This file is part of Open CASCADE Technology software library. |
6 | // |
7 | // This library is free software; you can redistribute it and/or modify it under |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
9 | // by the Free Software Foundation, with special exception defined in the file |
10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
11 | // distribution for complete text of the license and disclaimer of any warranty. |
12 | // |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
15 | |
16 | #ifdef _WIN32 |
17 | #define _WIN32_WINNT 0x0400 // for trackmouseevent support requires Win95 with IE 3.0 or greater. |
18 | #include <windows.h> |
19 | #include <vtkWin32RenderWindowInteractor.h> |
20 | #include <vtkWin32OpenGLRenderWindow.h> |
21 | #endif |
22 | |
23 | #include <IVtkTools_ShapePicker.hxx> |
24 | #include <IVtkTools_SubPolyDataFilter.hxx> |
25 | #include <IVtkTools_DisplayModeFilter.hxx> |
26 | #include <IVtkTools_ShapeObject.hxx> |
27 | #include <IVtkTools_ShapeDataSource.hxx> |
28 | #include <IVtkDraw_Interactor.hxx> |
29 | |
30 | #include <Message.hxx> |
31 | #include <Message_Messenger.hxx> |
32 | |
33 | #include <vtkActor.h> |
34 | #include <vtkActorCollection.h> |
35 | #include <vtkCommand.h> |
36 | #include <vtkObjectFactory.h> |
37 | #include <vtkSmartPointer.h> |
38 | |
39 | #ifndef _WIN32 |
40 | #include <X11/X.h> |
41 | #include <X11/Shell.h> |
42 | #include <X11/Xlib.h> |
43 | #include <GL/glx.h> |
44 | #include <vtkXRenderWindowInteractor.h> |
45 | #include <vtkXOpenGLRenderWindow.h> |
46 | #include <X11/Xutil.h> |
47 | #include <tk.h> |
48 | #endif |
49 | |
50 | //=========================================================== |
51 | // Function : ClearHighlightAndSelection |
52 | // Purpose : |
53 | //=========================================================== |
54 | static void ClearHighlightAndSelection (const Handle(ShapePipelineMap)& theMap, |
55 | const Standard_Boolean doHighlighting, |
56 | const Standard_Boolean doSelection) |
57 | { |
58 | if (!doHighlighting && !doSelection) |
59 | { |
60 | return; |
61 | } |
62 | |
63 | for (ShapePipelineMap::Iterator anIt (*theMap); anIt.More(); anIt.Next()) |
64 | { |
65 | const Handle(IVtkDraw_HighlightAndSelectionPipeline)& aPL = anIt.Value(); |
66 | |
67 | if (doHighlighting) |
68 | { |
69 | aPL->ClearHighlightFilters(); |
70 | } |
71 | |
72 | if (doSelection) |
73 | { |
74 | aPL->ClearSelectionFilters(); |
75 | } |
76 | } |
77 | } |
78 | |
79 | vtkStandardNewMacro(IVtkDraw_Interactor); |
80 | |
81 | //=========================================================== |
82 | // Function : Constructor |
83 | // Purpose : |
84 | //=========================================================== |
85 | IVtkDraw_Interactor::IVtkDraw_Interactor() |
86 | : |
87 | #ifdef _WIN32 |
88 | myWindowId (NULL), |
89 | myMouseInWindow (0) |
90 | #else |
91 | myIsLeftButtonPressed (Standard_False) |
92 | #endif |
93 | { } |
94 | |
95 | //=========================================================== |
96 | // Function : Destructor |
97 | // Purpose : |
98 | //=========================================================== |
99 | IVtkDraw_Interactor::~IVtkDraw_Interactor() |
100 | { |
101 | } |
102 | |
52f99d93 |
103 | //=========================================================== |
104 | // Function : SetShapePicker |
105 | // Purpose : |
106 | //=========================================================== |
107 | void IVtkDraw_Interactor::SetShapePicker (const PSelector& theSelector) |
108 | { |
109 | mySelector = theSelector; |
110 | } |
111 | |
112 | //=========================================================== |
113 | // Function : SetPipelines |
114 | // Purpose : |
115 | //=========================================================== |
116 | void IVtkDraw_Interactor::SetPipelines (const Handle(ShapePipelineMap)& thePipelines) |
117 | { |
118 | myPipelines = thePipelines; |
119 | } |
120 | |
121 | //=========================================================== |
122 | // Function : SetOCCWindow |
123 | // Purpose : |
124 | //=========================================================== |
125 | void IVtkDraw_Interactor::SetOCCWindow (const Handle(Aspect_Window)& theWindow) |
126 | { |
127 | myWindow = theWindow; |
128 | } |
129 | |
130 | //=========================================================== |
131 | // Function : GetOCCWindow |
132 | // Purpose : |
133 | //=========================================================== |
134 | const Handle(Aspect_Window)& IVtkDraw_Interactor::GetOCCWindow() const |
135 | { |
136 | return myWindow; |
137 | } |
138 | |
139 | //=========================================================== |
140 | // Function : IsEnabled |
141 | // Purpose : |
142 | //=========================================================== |
143 | Standard_Boolean IVtkDraw_Interactor::IsEnabled() const |
144 | { |
145 | return Enabled; |
146 | } |
147 | |
148 | //=========================================================== |
149 | // Function : Initialize |
150 | // Purpose : |
151 | //=========================================================== |
152 | void IVtkDraw_Interactor::Initialize() |
153 | { |
154 | // Make sure we have a RenderWindow and camera |
155 | if (!this->RenderWindow) |
156 | { |
157 | vtkErrorMacro(<<"No renderer defined!"); |
158 | return; |
159 | } |
160 | |
161 | if (this->Initialized) |
162 | { |
163 | return; |
164 | } |
165 | |
166 | this->Initialized = 1; |
167 | |
168 | // Get the info we need from the RenderingWindow |
169 | Standard_Integer *aSize; |
170 | #ifdef _WIN32 |
171 | vtkWin32OpenGLRenderWindow *aRenWin; |
172 | aRenWin = (vtkWin32OpenGLRenderWindow *)(this->RenderWindow); |
173 | aRenWin->Start(); |
174 | aSize = aRenWin->GetSize(); |
175 | aRenWin->GetPosition(); |
176 | this->myWindowId = aRenWin->GetWindowId(); |
177 | #else |
178 | vtkXOpenGLRenderWindow *aRenWin; |
179 | aRenWin = static_cast<vtkXOpenGLRenderWindow *>(this->RenderWindow); |
180 | this->myDisplayId = aRenWin->GetDisplayId(); |
181 | this->myWindowId = aRenWin->GetWindowId(); |
182 | aSize = aRenWin->GetSize(); |
183 | aRenWin->Start(); |
184 | #endif |
185 | |
186 | this->Enable(); |
187 | this->Size[0] = aSize[0]; |
188 | this->Size[1] = aSize[1]; |
189 | } |
190 | |
191 | //=========================================================== |
192 | // Function : Enable |
193 | // Purpose : |
194 | //=========================================================== |
195 | void IVtkDraw_Interactor::Enable() |
196 | { |
197 | if (this->Enabled) |
198 | { |
199 | return; |
200 | } |
201 | |
202 | // Add event handlers |
203 | #ifdef _WIN32 |
204 | SetWindowLongPtr(this->myWindowId, GWLP_USERDATA, (LONG_PTR)this); |
205 | SetWindowLongPtr(this->myWindowId, GWLP_WNDPROC, (LONG_PTR)WndProc); |
206 | #else |
207 | #if TCL_MAJOR_VERSION < 8 |
208 | Tk_CreateFileHandler((void*)ConnectionNumber(this->myDisplayId), |
209 | TK_READABLE, ProcessEvents, (ClientData) this); |
210 | #else |
211 | Tk_CreateFileHandler(ConnectionNumber(this->myDisplayId), |
212 | TK_READABLE, ProcessEvents, (ClientData) this); |
213 | #endif |
214 | #endif |
215 | |
216 | this->Enabled = 1; |
217 | this->Modified(); |
218 | } |
219 | |
220 | //=========================================================== |
221 | // Function : MoveTo |
222 | // Purpose : |
223 | //=========================================================== |
224 | void IVtkDraw_Interactor::MoveTo (Standard_Integer theX, Standard_Integer theY) |
225 | { |
226 | // Processing highlighting |
227 | mySelector->Pick (theX, theY, 0.0); |
228 | vtkActorCollection* anActorCollection = mySelector->GetPickedActors(); |
229 | |
230 | if (anActorCollection) |
231 | { |
232 | // Highlight picked subshapes |
233 | ClearHighlightAndSelection (myPipelines, Standard_True, Standard_False); |
234 | anActorCollection->InitTraversal(); |
235 | while (vtkActor* anActor = anActorCollection->GetNextActor()) |
236 | { |
237 | IVtkTools_ShapeDataSource* aDataSource = IVtkTools_ShapeObject::GetShapeSource (anActor); |
238 | if (!aDataSource) |
239 | { |
240 | continue; |
241 | } |
242 | |
243 | IVtkOCC_Shape::Handle anOccShape = aDataSource->GetShape(); |
244 | if (anOccShape.IsNull()) |
245 | { |
246 | continue; |
247 | } |
248 | |
249 | IVtk_IdType aShapeID = anOccShape->GetId(); |
250 | Handle(Message_Messenger) anOutput = Message::DefaultMessenger(); |
251 | if (!myPipelines->IsBound(aShapeID)) |
252 | { |
253 | anOutput << "Warning: there is no VTK pipeline registered for highlighted shape" << endl; |
254 | continue; |
255 | } |
256 | |
257 | const Handle(IVtkDraw_HighlightAndSelectionPipeline)& aPL = myPipelines->Find (aShapeID); |
258 | |
259 | // Add a subpolydata filter to the highlight pipeline for the shape data source. |
260 | IVtkTools_SubPolyDataFilter* aFilter = aPL->GetHighlightFilter(); |
261 | |
262 | // Set the selected sub-shapes ids to subpolydata filter. |
263 | IVtk_ShapeIdList aSubShapeIds = mySelector->GetPickedSubShapesIds(aShapeID); |
264 | |
265 | // Get ids of cells for picked subshapes. |
266 | IVtk_ShapeIdList aSubIds; |
267 | IVtk_ShapeIdList::Iterator aMetaIds (aSubShapeIds); |
268 | for (; aMetaIds.More(); aMetaIds.Next()) |
269 | { |
270 | IVtk_ShapeIdList aSubSubIds = anOccShape->GetSubIds (aMetaIds.Value()); |
271 | aSubIds.Append (aSubSubIds); |
272 | } |
273 | |
274 | aFilter->SetDoFiltering (!aSubIds.IsEmpty()); |
275 | aFilter->SetData (aSubIds); |
276 | if (!aFilter->GetInput()) |
277 | { |
278 | aFilter->SetInputConnection (aDataSource->GetOutputPort()); |
279 | } |
280 | aFilter->Modified(); |
281 | } |
282 | } |
283 | this->Render(); |
284 | } |
285 | |
286 | //=========================================================== |
287 | // Function : OnSelection |
288 | // Purpose : |
289 | //=========================================================== |
290 | void IVtkDraw_Interactor::OnSelection() |
291 | { |
292 | // Processing selection |
293 | vtkActorCollection* anActorCollection = mySelector->GetPickedActors(); |
294 | |
295 | if (anActorCollection) |
296 | { |
297 | // Highlight picked subshapes. |
298 | ClearHighlightAndSelection (myPipelines, Standard_False, Standard_True); |
299 | anActorCollection->InitTraversal(); |
300 | while (vtkActor* anActor = anActorCollection->GetNextActor()) |
301 | { |
302 | IVtkTools_ShapeDataSource* aDataSource = IVtkTools_ShapeObject::GetShapeSource (anActor); |
303 | if (!aDataSource) |
304 | { |
305 | continue; |
306 | } |
307 | |
308 | IVtkOCC_Shape::Handle anOccShape = aDataSource->GetShape(); |
309 | if (anOccShape.IsNull()) |
310 | { |
311 | continue; |
312 | } |
313 | |
314 | IVtk_IdType aShapeID = anOccShape->GetId(); |
315 | Handle(Message_Messenger) anOutput = Message::DefaultMessenger(); |
316 | if (!myPipelines->IsBound (aShapeID)) |
317 | { |
318 | anOutput << "Warning: there is no VTK pipeline registered for picked shape" << endl; |
319 | continue; |
320 | } |
321 | |
322 | const Handle(IVtkDraw_HighlightAndSelectionPipeline)& aPL = myPipelines->Find (aShapeID); |
323 | |
324 | // Add a subpolydata filter to the selection pipeline for the shape data source. |
325 | IVtkTools_SubPolyDataFilter* aFilter = aPL->GetSelectionFilter(); |
326 | |
327 | // Set the selected sub-shapes ids to subpolydata filter. |
328 | IVtk_ShapeIdList aSubShapeIds = mySelector->GetPickedSubShapesIds(aShapeID); |
329 | |
330 | // Get ids of cells for picked subshapes. |
331 | IVtk_ShapeIdList aSubIds; |
332 | IVtk_ShapeIdList::Iterator aMetaIds (aSubShapeIds); |
333 | for (; aMetaIds.More(); aMetaIds.Next()) |
334 | { |
335 | IVtk_ShapeIdList aSubSubIds = anOccShape->GetSubIds (aMetaIds.Value()); |
336 | aSubIds.Append (aSubSubIds); |
337 | } |
338 | |
339 | aFilter->SetDoFiltering (!aSubIds.IsEmpty()); |
340 | aFilter->SetData (aSubIds); |
341 | if (!aFilter->GetInput()) |
342 | { |
343 | aFilter->SetInputConnection (aDataSource->GetOutputPort()); |
344 | } |
345 | aFilter->Modified(); |
346 | } |
347 | } |
348 | this->Render(); |
349 | } |
350 | |
351 | #ifdef _WIN32 |
352 | |
353 | //=========================================================== |
354 | // Function : OnMouseMove |
355 | // Purpose : |
356 | //=========================================================== |
357 | void IVtkDraw_Interactor::OnMouseMove (HWND theHWnd, UINT theNFlags, |
358 | Standard_Integer theX, |
359 | Standard_Integer theY) |
360 | { |
361 | if (!this->Enabled) |
362 | { |
363 | return; |
364 | } |
365 | |
366 | this->SetEventInformationFlipY (theX, |
367 | theY, |
368 | theNFlags & MK_CONTROL, |
369 | theNFlags & MK_SHIFT); |
370 | this->SetAltKey(GetKeyState(VK_MENU) & (~1)); |
371 | if (!this->myMouseInWindow && |
372 | (theX >= 0 && theX < this->Size[0] && theY >= 0 && theY < this->Size[1])) |
373 | { |
374 | this->InvokeEvent (vtkCommand::EnterEvent, NULL); |
375 | this->myMouseInWindow = 1; |
376 | // request WM_MOUSELEAVE generation |
377 | TRACKMOUSEEVENT aTme; |
378 | aTme.cbSize = sizeof (TRACKMOUSEEVENT); |
379 | aTme.dwFlags = TME_LEAVE; |
380 | aTme.hwndTrack = theHWnd; |
381 | TrackMouseEvent (&aTme); |
382 | } |
383 | |
384 | if (!(theNFlags & MK_LBUTTON)) |
385 | this->MoveTo (theX, this->Size[1] - theY - 1); |
386 | |
387 | this->InvokeEvent (vtkCommand::MouseMoveEvent, NULL); |
388 | } |
389 | |
390 | //=========================================================== |
391 | // Function : OnMouseWheelForward |
392 | // Purpose : |
393 | //=========================================================== |
394 | void IVtkDraw_Interactor::OnMouseWheelForward (HWND, UINT theNFlags, |
395 | Standard_Integer theX, |
396 | Standard_Integer theY) |
397 | { |
398 | if (!this->Enabled) |
399 | { |
400 | return; |
401 | } |
402 | |
403 | this->SetEventInformationFlipY (theX, |
404 | theY, |
405 | theNFlags & MK_CONTROL, |
406 | theNFlags & MK_SHIFT); |
407 | |
408 | this->SetAltKey (GetKeyState(VK_MENU) & (~1)); |
409 | this->InvokeEvent (vtkCommand::MouseWheelForwardEvent, NULL); |
410 | } |
411 | |
412 | //=========================================================== |
413 | // Function : OnMouseWheelBackward |
414 | // Purpose : |
415 | //=========================================================== |
416 | void IVtkDraw_Interactor::OnMouseWheelBackward (HWND, UINT theNFlags, |
417 | Standard_Integer theX, |
418 | Standard_Integer theY) |
419 | { |
420 | if (!this->Enabled) |
421 | { |
422 | return; |
423 | } |
424 | |
425 | this->SetEventInformationFlipY (theX, |
426 | theY, |
427 | theNFlags & MK_CONTROL, |
428 | theNFlags & MK_SHIFT); |
429 | |
430 | this->SetAltKey (GetKeyState(VK_MENU) & (~1)); |
431 | this->InvokeEvent (vtkCommand::MouseWheelBackwardEvent, NULL); |
432 | } |
433 | |
434 | //=========================================================== |
435 | // Function : OnLButtonDown |
436 | // Purpose : |
437 | //=========================================================== |
438 | void IVtkDraw_Interactor::OnLButtonDown (HWND theHWnd, UINT theNFlags, |
439 | Standard_Integer theX, |
440 | Standard_Integer theY, |
441 | Standard_Integer theRepeat) |
442 | { |
443 | if (!this->Enabled) |
444 | { |
445 | return; |
446 | } |
447 | SetFocus (theHWnd); |
448 | SetCapture (theHWnd); |
449 | this->SetEventInformationFlipY (theX, |
450 | theY, |
451 | theNFlags & MK_CONTROL, |
452 | theNFlags & MK_SHIFT, |
453 | 0, theRepeat); |
454 | this->SetAltKey (GetKeyState(VK_MENU) & (~1)); |
455 | |
456 | OnSelection (); |
457 | |
458 | this->InvokeEvent (vtkCommand::LeftButtonPressEvent, NULL); |
459 | } |
460 | |
461 | //=========================================================== |
462 | // Function : OnLButtonUp |
463 | // Purpose : |
464 | //=========================================================== |
465 | void IVtkDraw_Interactor::OnLButtonUp (HWND, UINT theNFlags, |
466 | Standard_Integer theX, |
467 | Standard_Integer theY) |
468 | { |
469 | if (!this->Enabled) |
470 | { |
471 | return; |
472 | } |
473 | |
474 | this->SetEventInformationFlipY (theX, |
475 | theY, |
476 | theNFlags & MK_CONTROL, |
477 | theNFlags & MK_SHIFT); |
478 | |
479 | this->SetAltKey (GetKeyState(VK_MENU) & (~1)); |
480 | this->InvokeEvent (vtkCommand::LeftButtonReleaseEvent, NULL); |
481 | ReleaseCapture(); |
482 | } |
483 | |
484 | //=========================================================== |
485 | // Function : OnMButtonDown |
486 | // Purpose : |
487 | //=========================================================== |
488 | void IVtkDraw_Interactor::OnMButtonDown (HWND theHWnd, UINT theNFlags, |
489 | Standard_Integer theX, |
490 | Standard_Integer theY, |
491 | Standard_Integer theRepeat) |
492 | { |
493 | if (!this->Enabled) |
494 | { |
495 | return; |
496 | } |
497 | |
498 | SetFocus (theHWnd); |
499 | SetCapture (theHWnd); |
500 | this->SetEventInformationFlipY (theX, |
501 | theY, |
502 | theNFlags & MK_CONTROL, |
503 | theNFlags & MK_SHIFT, |
504 | 0, theRepeat); |
505 | this->SetAltKey (GetKeyState(VK_MENU) & (~1)); |
506 | this->InvokeEvent (vtkCommand::MiddleButtonPressEvent, NULL); |
507 | } |
508 | |
509 | //=========================================================== |
510 | // Function : OnMButtonUp |
511 | // Purpose : |
512 | //=========================================================== |
513 | void IVtkDraw_Interactor::OnMButtonUp (HWND, UINT theNFlags, |
514 | Standard_Integer theX, |
515 | Standard_Integer theY) |
516 | { |
517 | if (!this->Enabled) |
518 | { |
519 | return; |
520 | } |
521 | this->SetEventInformationFlipY (theX, |
522 | theY, |
523 | theNFlags & MK_CONTROL, |
524 | theNFlags & MK_SHIFT); |
525 | |
526 | this->SetAltKey (GetKeyState(VK_MENU) & (~1)); |
527 | this->InvokeEvent (vtkCommand::MiddleButtonReleaseEvent, NULL); |
528 | ReleaseCapture(); |
529 | } |
530 | |
531 | //=========================================================== |
532 | // Function : OnRButtonDown |
533 | // Purpose : |
534 | //=========================================================== |
535 | void IVtkDraw_Interactor::OnRButtonDown (HWND theHWnd, UINT theNFlags, |
536 | Standard_Integer theX, |
537 | Standard_Integer theY, |
538 | Standard_Integer theRepeat) |
539 | { |
540 | if (!this->Enabled) |
541 | { |
542 | return; |
543 | } |
544 | |
545 | SetFocus(theHWnd); |
546 | SetCapture(theHWnd); |
547 | this->SetEventInformationFlipY (theX, |
548 | theY, |
549 | theNFlags & MK_CONTROL, |
550 | theNFlags & MK_SHIFT, |
551 | 0, theRepeat); |
552 | |
553 | this->SetAltKey (GetKeyState(VK_MENU) & (~1)); |
554 | this->InvokeEvent (vtkCommand::RightButtonPressEvent, NULL); |
555 | } |
556 | |
557 | //=========================================================== |
558 | // Function : OnRButtonUp |
559 | // Purpose : |
560 | //=========================================================== |
561 | void IVtkDraw_Interactor::OnRButtonUp (HWND, UINT theNFlags, |
562 | Standard_Integer theX, |
563 | Standard_Integer theY) |
564 | { |
565 | if (!this->Enabled) |
566 | { |
567 | return; |
568 | } |
569 | this->SetEventInformationFlipY (theX, |
570 | theY, |
571 | theNFlags & MK_CONTROL, |
572 | theNFlags & MK_SHIFT); |
573 | |
574 | this->SetAltKey (GetKeyState(VK_MENU) & (~1)); |
575 | this->InvokeEvent (vtkCommand::RightButtonReleaseEvent, NULL); |
576 | ReleaseCapture(); |
577 | } |
578 | |
579 | //=========================================================== |
580 | // Function : OnSize |
581 | // Purpose : |
582 | //=========================================================== |
583 | void IVtkDraw_Interactor::OnSize (HWND, UINT, |
584 | Standard_Integer theX, |
585 | Standard_Integer theY) |
586 | { |
587 | this->UpdateSize (theX, theY); |
588 | if (this->Enabled) |
589 | { |
590 | this->InvokeEvent (vtkCommand::ConfigureEvent, NULL); |
591 | } |
592 | } |
593 | |
594 | //=========================================================== |
595 | // Function : OnTimer |
596 | // Purpose : |
597 | //=========================================================== |
598 | void IVtkDraw_Interactor::OnTimer (HWND, UINT theTimerId) |
599 | { |
600 | if (!this->Enabled) |
601 | { |
602 | return; |
603 | } |
604 | |
605 | Standard_Integer aTid = static_cast<Standard_Integer>(theTimerId); |
606 | this->InvokeEvent (vtkCommand::TimerEvent, (void*)&aTid); |
607 | |
608 | // Here we deal with one-shot versus repeating timers |
609 | if (this->IsOneShotTimer(aTid)) |
610 | { |
611 | KillTimer (this->myWindowId, aTid); //'cause windows timers are always repeating |
612 | } |
613 | } |
614 | |
615 | //=========================================================== |
616 | // Function : WndProc |
617 | // Purpose : |
618 | //=========================================================== |
619 | LRESULT CALLBACK WndProc (HWND theHWnd,UINT theUMsg, |
620 | WPARAM theWParam, |
621 | LPARAM theLParam) |
622 | { |
623 | LRESULT aRes = 0; |
624 | IVtkDraw_Interactor *anInteractor = 0; |
625 | |
626 | anInteractor = (IVtkDraw_Interactor *)GetWindowLongPtr (theHWnd, GWLP_USERDATA); |
627 | |
628 | if (anInteractor && anInteractor->GetReferenceCount() > 0) |
629 | { |
630 | anInteractor->Register (anInteractor); |
631 | aRes = ViewerWindowProc (theHWnd, theUMsg, theWParam, theLParam, anInteractor); |
632 | anInteractor->UnRegister (anInteractor); |
633 | } |
634 | |
635 | return aRes; |
636 | } |
637 | |
638 | //=========================================================== |
639 | // Function : ViewerWindowProc |
640 | // Purpose : |
641 | //=========================================================== |
642 | LRESULT CALLBACK ViewerWindowProc (HWND theHWnd, |
643 | UINT theMsg, |
644 | WPARAM theWParam, |
645 | LPARAM theLParam, |
646 | IVtkDraw_Interactor *theInteractor) |
647 | { |
648 | switch (theMsg) |
649 | { |
650 | case WM_CLOSE: |
651 | theInteractor->GetOCCWindow ()->Unmap (); |
652 | return 0; |
653 | case WM_PAINT: |
654 | theInteractor->Render(); |
655 | break; |
656 | case WM_SIZE: |
657 | theInteractor->OnSize (theHWnd, theWParam, LOWORD(theLParam), HIWORD(theLParam)); |
658 | break; |
659 | case WM_LBUTTONDBLCLK: |
660 | theInteractor->OnLButtonDown (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 1); |
661 | break; |
662 | case WM_LBUTTONDOWN: |
663 | theInteractor->OnLButtonDown (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 0); |
664 | break; |
665 | case WM_LBUTTONUP: |
666 | theInteractor->OnLButtonUp (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y); |
667 | break; |
668 | case WM_MBUTTONDBLCLK: |
669 | theInteractor->OnMButtonDown (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 1); |
670 | break; |
671 | case WM_MBUTTONDOWN: |
672 | theInteractor->OnMButtonDown (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 0); |
673 | break; |
674 | case WM_MBUTTONUP: |
675 | theInteractor->OnMButtonUp (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y); |
676 | break; |
677 | case WM_RBUTTONDBLCLK: |
678 | theInteractor->OnRButtonDown (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 1); |
679 | break; |
680 | case WM_RBUTTONDOWN: |
681 | theInteractor->OnRButtonDown (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 0); |
682 | break; |
683 | case WM_RBUTTONUP: |
684 | theInteractor->OnRButtonUp (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y); |
685 | break; |
686 | case WM_MOUSELEAVE: |
687 | { |
688 | theInteractor->InvokeEvent (vtkCommand::LeaveEvent, NULL); |
689 | theInteractor->myMouseInWindow = 0; |
690 | } |
691 | break; |
692 | case WM_MOUSEMOVE: |
693 | theInteractor->OnMouseMove (theHWnd, theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y); |
694 | break; |
695 | case WM_MOUSEWHEEL: |
696 | { |
697 | POINT pt; |
698 | pt.x = MAKEPOINTS(theLParam).x; |
699 | pt.y = MAKEPOINTS(theLParam).y; |
700 | ::ScreenToClient(theHWnd, &pt); |
701 | if( GET_WHEEL_DELTA_WPARAM(theWParam) > 0) |
702 | { |
703 | theInteractor->OnMouseWheelForward (theHWnd, theWParam, pt.x, pt.y); |
704 | } |
705 | else |
706 | { |
707 | theInteractor->OnMouseWheelBackward (theHWnd, theWParam, pt.x, pt.y); |
708 | } |
709 | } |
710 | break; |
711 | case WM_TIMER: |
712 | theInteractor->OnTimer (theHWnd, theWParam); |
713 | break; |
714 | } |
715 | return DefWindowProc(theHWnd, theMsg, theWParam, theLParam); |
716 | } |
717 | |
718 | #else |
719 | |
720 | //=========================================================== |
721 | // Function : GetDisplayId |
722 | // Purpose : |
723 | //=========================================================== |
724 | Display* IVtkDraw_Interactor::GetDisplayId() const |
725 | { |
726 | return myDisplayId; |
727 | } |
728 | |
729 | //=========================================================== |
730 | // Function : GetMousePosition |
731 | // Purpose : |
732 | //=========================================================== |
733 | void IVtkDraw_Interactor::GetMousePosition (Standard_Integer *theX, |
734 | Standard_Integer *theY) |
735 | { |
736 | Window aRoot, aChild; |
737 | Standard_Integer aRoot_x, aRoot_y; |
738 | unsigned int aKeys; |
739 | |
740 | XQueryPointer (this->myDisplayId, this->myWindowId, |
741 | &aRoot, &aChild, &aRoot_x, &aRoot_y, theX, theY, &aKeys); |
742 | |
743 | } |
744 | |
745 | //=========================================================== |
746 | // Function : ViewerMainLoop |
747 | // Purpose : |
748 | //=========================================================== |
749 | Standard_Integer IVtkDraw_Interactor::ViewerMainLoop (Standard_Integer theArgNum, const char** /*theArgs*/) |
750 | { |
751 | Standard_Integer aXp, aYp; |
752 | Standard_Boolean aPick = theArgNum > 0; |
753 | |
754 | static XEvent anEvent; |
755 | XNextEvent (myDisplayId, &anEvent); |
756 | |
757 | switch (anEvent.type) |
758 | { |
759 | case Expose: |
760 | { |
761 | if (!this->Enabled) |
762 | { |
763 | return aPick; |
764 | } |
765 | XEvent aResult; |
766 | while (XCheckTypedWindowEvent (this->myDisplayId, |
767 | this->myWindowId, |
768 | Expose, |
769 | &aResult)) |
770 | { |
771 | // just getting the expose configure event |
772 | anEvent = aResult; |
773 | } |
774 | |
775 | this->SetEventSize (anEvent.xexpose.width, anEvent.xexpose.height); |
776 | |
777 | |
778 | aXp = anEvent.xexpose.x; |
779 | aYp = this->Size[1] - anEvent.xexpose.y - 1; |
780 | this->SetEventPosition (aXp, aYp); |
781 | |
782 | // only render if we are currently accepting events |
783 | if (this->Enabled) |
784 | { |
785 | this->InvokeEvent(vtkCommand::ExposeEvent,NULL); |
786 | this->Render(); |
787 | } |
788 | } |
789 | break; |
790 | |
791 | case MapNotify: |
792 | { |
793 | // only render if we are currently accepting events |
794 | if (this->Enabled && this->GetRenderWindow()->GetNeverRendered()) |
795 | { |
796 | this->Render(); |
797 | } |
798 | } |
799 | break; |
800 | |
801 | case ConfigureNotify: |
802 | { |
803 | XEvent aResult; |
804 | while (XCheckTypedWindowEvent(this->myDisplayId, |
805 | this->myWindowId, |
806 | ConfigureNotify, |
807 | &aResult)) |
808 | { |
809 | // just getting the last configure event |
810 | anEvent = aResult; |
811 | } |
812 | Standard_Integer aWidth = anEvent.xconfigure.width; |
813 | Standard_Integer aHeight = anEvent.xconfigure.height; |
814 | if (aWidth != this->Size[0] || aHeight != this->Size[1]) |
815 | { |
816 | Standard_Boolean toResizeSmaller = aWidth <= this->Size[0] && aHeight <= this->Size[1]; |
817 | this->UpdateSize (aWidth, aHeight); |
818 | aXp = anEvent.xbutton.x; |
819 | aYp = anEvent.xbutton.y; |
820 | |
821 | SetEventPosition (aXp, this->Size[1] - aYp - 1); |
822 | |
823 | // only render if we are currently accepting events |
824 | if (Enabled) |
825 | { |
826 | this->InvokeEvent(vtkCommand::ConfigureEvent,NULL); |
827 | if (toResizeSmaller) |
828 | { |
829 | // Don't call Render when the window is resized to be larger: |
830 | // |
831 | // - if the window is resized to be larger, an Expose event will |
832 | // be trigged by the X server which will trigger a call to |
833 | // Render(). |
834 | // - if the window is resized to be smaller, no Expose event will |
835 | // be trigged by the X server, as no new area become visible. |
836 | // only in this case, we need to explicitly call Render() |
837 | // in ConfigureNotify. |
838 | this->Render(); |
839 | } |
840 | } |
841 | } |
842 | } |
843 | break; |
844 | |
845 | case ButtonPress: |
846 | { |
847 | if (!this->Enabled) |
848 | { |
849 | return aPick; |
850 | } |
851 | |
852 | Standard_Integer aCtrl = anEvent.xbutton.state & ControlMask ? 1 : 0; |
853 | Standard_Integer aShift = anEvent.xbutton.state & ShiftMask ? 1 : 0; |
854 | Standard_Integer anAlt = anEvent.xbutton.state & Mod1Mask ? 1 : 0; |
855 | aXp = anEvent.xbutton.x; |
856 | aYp = anEvent.xbutton.y; |
857 | |
858 | // check for double click |
859 | static Standard_Integer aMousePressTime = 0; |
860 | Standard_Integer aRepeat = 0; |
861 | // 400 ms threshold by default is probably good to start |
862 | Standard_Integer anEventTime = static_cast<int>(anEvent.xbutton.time); |
863 | if ((anEventTime - aMousePressTime) < 400) |
864 | { |
865 | aMousePressTime -= 2000; // no double click next time |
866 | aRepeat = 1; |
867 | } |
868 | else |
869 | { |
870 | aMousePressTime = anEventTime; |
871 | } |
872 | |
873 | this->SetEventInformationFlipY (aXp, aYp, aCtrl, aShift, 0, aRepeat); |
874 | this->SetAltKey (anAlt); |
875 | |
876 | switch (anEvent.xbutton.button) |
877 | { |
878 | case Button1: |
879 | this->OnSelection (); |
880 | this->myIsLeftButtonPressed = 1; |
881 | this->InvokeEvent (vtkCommand::LeftButtonPressEvent,NULL); |
882 | break; |
883 | case Button2: |
884 | this->InvokeEvent (vtkCommand::MiddleButtonPressEvent,NULL); |
885 | break; |
886 | case Button3: |
887 | this->InvokeEvent (vtkCommand::RightButtonPressEvent,NULL); |
888 | break; |
889 | case Button4: |
890 | this->InvokeEvent (vtkCommand::MouseWheelForwardEvent,NULL); |
891 | break; |
892 | case Button5: |
893 | this->InvokeEvent (vtkCommand::MouseWheelBackwardEvent,NULL); |
894 | break; |
895 | } |
896 | this->Render(); |
897 | } |
898 | break; |
899 | |
900 | case ButtonRelease: |
901 | { |
902 | if (!this->Enabled) |
903 | { |
904 | return aPick; |
905 | } |
906 | Standard_Integer aCtrl = anEvent.xbutton.state & ControlMask ? 1 : 0; |
907 | Standard_Integer aShift = anEvent.xbutton.state & ShiftMask ? 1 : 0; |
908 | Standard_Integer anAlt = anEvent.xbutton.state & Mod1Mask ? 1 : 0; |
909 | aXp = anEvent.xbutton.x; |
910 | aYp = anEvent.xbutton.y; |
911 | |
912 | this->SetEventInformationFlipY (aXp, aYp, aCtrl, aShift); |
913 | this->SetAltKey (anAlt); |
914 | switch (anEvent.xbutton.button) |
915 | { |
916 | case Button1: |
917 | this->InvokeEvent (vtkCommand::LeftButtonReleaseEvent,NULL); |
918 | this->myIsLeftButtonPressed = False; |
919 | break; |
920 | case Button2: |
921 | this->InvokeEvent (vtkCommand::MiddleButtonReleaseEvent,NULL); |
922 | break; |
923 | case Button3: |
924 | this->InvokeEvent (vtkCommand::RightButtonReleaseEvent,NULL); |
925 | break; |
926 | } |
927 | this->Render(); |
928 | } |
929 | break; |
930 | |
931 | case EnterNotify: |
932 | { |
933 | if (this->Enabled) |
934 | { |
935 | XEnterWindowEvent *anEnterEvent = reinterpret_cast<XEnterWindowEvent *>(&anEvent); |
936 | this->SetEventInformationFlipY (anEnterEvent->x, |
937 | anEnterEvent->y, |
938 | (anEnterEvent->state & ControlMask) != 0, |
939 | (anEnterEvent->state & ShiftMask) != 0); |
940 | |
941 | this->SetAltKey (anEvent.xbutton.state & Mod1Mask ? 1 : 0); |
942 | this->InvokeEvent (vtkCommand::EnterEvent, NULL); |
943 | } |
944 | this->Render(); |
945 | } |
946 | break; |
947 | |
948 | case LeaveNotify: |
949 | { |
950 | if (this->Enabled) |
951 | { |
952 | XLeaveWindowEvent *aLeaveEvent = reinterpret_cast<XLeaveWindowEvent *>(&anEvent); |
953 | this->SetEventInformationFlipY (aLeaveEvent->x, |
954 | aLeaveEvent->y, |
955 | (aLeaveEvent->state & ControlMask) != 0, |
956 | (aLeaveEvent->state & ShiftMask) != 0); |
957 | |
958 | this->SetAltKey (anEvent.xbutton.state & Mod1Mask ? 1 : 0); |
959 | this->InvokeEvent(vtkCommand::LeaveEvent, NULL); |
960 | } |
961 | this->Render(); |
962 | } |
963 | break; |
964 | |
965 | case MotionNotify: |
966 | { |
967 | if (!this->Enabled) |
968 | { |
969 | return aPick; |
970 | } |
971 | |
972 | Standard_Integer aCtrl = anEvent.xbutton.state & ControlMask ? 1 : 0; |
973 | Standard_Integer aShift = anEvent.xbutton.state & ShiftMask ? 1 : 0; |
974 | Standard_Integer anAlt = anEvent.xbutton.state & Mod1Mask ? 1 : 0; |
975 | |
976 | // Note that even though the (x,y) location of the pointer is event structure, |
977 | // we must call XQueryPointer for the hints (motion event compression) to |
978 | // work properly. |
979 | this->GetMousePosition (&aXp, &aYp); |
980 | this->SetEventInformationFlipY (aXp, aYp, aCtrl, aShift); |
981 | this->SetAltKey (anAlt); |
982 | if (!myIsLeftButtonPressed) |
983 | MoveTo (aXp, this->Size[1]- aYp - 1); |
984 | this->InvokeEvent (vtkCommand::MouseMoveEvent, NULL); |
985 | } |
986 | break; |
987 | } |
988 | |
989 | return aPick; |
990 | } |
991 | |
992 | //=========================================================== |
993 | // Function : ProcessEvents |
994 | // Purpose : |
995 | //=========================================================== |
996 | void IVtkDraw_Interactor::ProcessEvents (ClientData theData, int) |
997 | { |
998 | IVtkDraw_Interactor *anInteractor = (IVtkDraw_Interactor *)theData; |
999 | // test for X Event |
1000 | while (XPending(anInteractor->GetDisplayId())) |
1001 | { |
1002 | anInteractor->ViewerMainLoop (0, NULL); |
1003 | } |
1004 | } |
1005 | |
1006 | #endif |