NCBI C++ ToolKit
gl_widget_base.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: gl_widget_base.cpp 47479 2023-05-02 13:24:02Z ucko $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Andrey Yazhuk
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
35 
41 
42 #include <gui/opengl/glfont.hpp>
43 
44 #include <gui/utils/command.hpp> //TODO for command definitions only
45 
46 #include <gui/types.hpp>
47 
48 #include <list>
49 
50 #include <wx/event.h>
51 #include <wx/sizer.h>
52 #include <wx/menu.h>
53 #include <wx/app.h>
54 
55 #define WIDGET_PANE_ENTER_TIMER 6310
56 
58 
59 BEGIN_EVENT_TABLE( CGlWidgetPane, C3DCanvas )
60  EVT_SIZE(CGlWidgetPane::OnSize)
61  EVT_ENTER_WINDOW(CGlWidgetPane::OnEnterWindow)
63  EVT_LEFT_DOWN(CGlWidgetPane::OnMouseDown)
64  EVT_RIGHT_DOWN(CGlWidgetPane::OnMouseDown)
65  EVT_LEFT_DCLICK(CGlWidgetPane::OnMouseDown)
66  EVT_RIGHT_DCLICK(CGlWidgetPane::OnMouseDown)
67  EVT_MIDDLE_DOWN(CGlWidgetPane::OnMouseDown)
68  EVT_LEFT_UP(CGlWidgetPane::OnMouseUp)
69  EVT_RIGHT_UP(CGlWidgetPane::OnMouseUp)
70  EVT_MIDDLE_UP(CGlWidgetPane::OnMouseUp)
71  EVT_MOTION(CGlWidgetPane::OnMotion)
72  EVT_MOUSEWHEEL(CGlWidgetPane::OnMouseWheel)
73  EVT_MOUSE_CAPTURE_LOST(CGlWidgetPane::OnMouseCaptureLost)
74  EVT_LEAVE_WINDOW(CGlWidgetPane::OnLeaveWindow)
75 
76  EVT_KEY_DOWN(CGlWidgetPane::OnKeyEvent)
77  EVT_KEY_UP(CGlWidgetPane::OnKeyEvent)
78 
79  EVT_SET_FOCUS(CGlWidgetPane::OnSetFocus)
80  EVT_KILL_FOCUS(CGlWidgetPane::OnKillFocus)
81 
84  wxEVT_COMMAND_BUTTON_CLICKED,
85  CGlWidgetPane::OnCmdEvent)
86  EVT_BUTTON(eCmdTipRemoved, CGlWidgetPane::OnTipRemoved)
88 
89 
90 void CGlWidgetPane::GHH_Redraw()
91 {
92  Refresh();
93 }
94 
95 
96 void CGlWidgetPane::GHH_SetCursor(const wxCursor& cursor)
97 {
98  SetCursor(cursor);
99 }
100 
101 //static int capture_count = 0;
102 
104 {
105  //_ASSERT(capture_count >= 0);
106  //capture_count++;
107  //LOG_POST("CGlWidgetPane::GHH_CaptureMouse() " << capture_count);
108 
109 // _ASSERT(! HasCapture());
110  if (HasCapture()) {
111  ReleaseMouse();
112  }
113  CaptureMouse();
114 }
115 
116 
118 {
119  //_ASSERT(capture_count > 0);
120  //capture_count--;
121  //LOG_POST("CGlWidgetPane::GHH_ReleaseMouse() " << capture_count);
122 
123  if(HasCapture()) {
124  ReleaseMouse();
125  }
126 }
127 
128 
129 bool CGlWidgetPane::TC_NeedTooltip(const wxPoint & pt)
130 {
131  return false;
132 }
133 
134 
135 string CGlWidgetPane::TC_GetTooltip(const wxRect & rect)
136 {
137  return "";
138 }
139 
140 
142 {
143  return this;
144 }
145 
147 {
148  bool grab = false;
149 
150  wxWindow* w = wxWindow::FindFocus();
151 
152  // By default only grab it from a sticky tooltip since we generally want
153  // to restore focus to the underlying window when coming off a tooltip. Other
154  // windows (especially text widgets) will not want to lose their focus just
155  // because you hovered over something else.
156  if (w != NULL) {
157  while (w != NULL && !grab) {
158  if (w != NULL) {
159  if (w->GetName() == wxT("Sticky Tooltip"))
160  grab = true;
161  //_TRACE("Focus Parent: " << w->GetClassInfo()->GetClassName()
162  // << " " << w->GetName());
163  }
164 
165  w = w->GetParent();
166  }
167  //_TRACE(" ");
168  }
169 
170  return grab;
171 }
172 
173 
174 
175 void CGlWidgetPane::OnEnterWindow(wxMouseEvent& /*event*/)
176 {
177  // Doing this allows features such as minimap to work after the currsor
178  // enters the window without having to first click on the window
179  // to make it active. It also allows focus to return to the window after
180  // user mouses over a tooltip window. In both cases it also means that
181  // hotkeys for the window will work since the window having focus is
182  // needed for hotkeys to be active.
183 
184  // There may be situations when you do not want the window to 'steal' focus
185  // though, such as when you are in an edit control (this causes the cursor
186  // to suddenly 'disappear' from the edit control)
187 
188  if (x_GrabFocus())
189  this->SetFocus();
190 
191  // Can't just do fix here since sometimes window (like tooltip from project
192  // view) is still displayed when this event occurs.
194 }
195 
196 void CGlWidgetPane::OnTimer(wxTimerEvent& event)
197 {
198  if (event.GetId() == WIDGET_PANE_ENTER_TIMER) {
199  DlgOverlayFix();
200  Refresh();
201  }
202 }
203 
205 {
206  // If we just entered the window, reset window to deal with opengl/window overlay error
207  // in vista (and later versions of windows).
208  if (m_EnterTimer.IsRunning()) {
209  // Try to make sure windows are fully deleted before executing the fix
210  wxTheApp->ProcessIdle();
211 
212  // If time is insufficient, may still have problem (quick click after entering).
213  double delta = m_EnterTimer.Elapsed();
215  if (delta < 0.7) {
216  // We still try to reset display, but recognize it may not work so we will
217  // retry after 0.7 seconds
218  DlgOverlayFix();
219  int delay = static_cast<int>((0.7-delta)*1000.0);
220  if (m_GLOverlapFixTimer.IsRunning())
221  m_GLOverlapFixTimer.Stop();
222 
223  m_GLOverlapFixTimer.Start(delay, true);
224  }
225  else {
226  DlgOverlayFix();
227  }
228  }
229 }
230 
231 void CGlWidgetPane::OnMouseDown(wxMouseEvent& event)
232 {
233  SetFocus();
234 
236 
237  wxPoint pos = event.GetPosition();
238  int area = x_GetAreaByWindowPos(pos);
239  if( ! x_Handlers_handle(event, area)) {
240  event.Skip();
241  }
242 }
243 
244 
245 void CGlWidgetPane::OnMouseUp(wxMouseEvent& event)
246 {
247  bool handled = false;
248  if (m_pCurrHandlerRec) {
250  }
251  if( ! handled) {
252  wxPoint pos = event.GetPosition();
253  int area = x_GetAreaByWindowPos(pos);
254  if( !x_Handlers_handle(event, area))
255  event.Skip();
256  }
257 
259 }
260 
261 static bool trace = false;
262 
263 void CGlWidgetPane::OnMotion(wxMouseEvent& event)
264 {
265 
266  bool handled = false;
267  if(m_pCurrHandlerRec) {
269  }
270  if (!handled) {
271  wxPoint pos = event.GetPosition();
272  int area = x_GetAreaByWindowPos(pos);
273  handled = x_Handlers_handle(event, area);
274  }
275  if( ! handled) {
276  event.Skip();
277  }
278  else {
280  }
281 }
282 
283 
284 void CGlWidgetPane::OnMouseWheel(wxMouseEvent& event)
285 {
286  // When user scrolls check for dialog overlay fix just like we do for
287  // mouse down (since window has been updated)
289 
290  if ( ! x_Handlers_handle(event, 0xFFFFFFFF, false)) {
291  event.Skip();
292  }
293 }
294 
295 
296 void CGlWidgetPane::OnMouseCaptureLost(wxMouseCaptureLostEvent& event)
297 {
298  /// only currently active handler can capture mouse
299  if(m_pCurrHandlerRec) {
301  }
302 }
303 
304 void CGlWidgetPane::OnLeaveWindow(wxMouseEvent& event)
305 {
306  if ( ! x_Handlers_handle(event, 0xFFFFFFFF, false)) {
307  event.Skip();
308  }
309 }
310 
311 void CGlWidgetPane::OnKeyEvent(wxKeyEvent& event)
312 {
313 #ifdef ATTRIB_MENU_SUPPORT
314  if (event.GetEventType() == wxEVT_KEY_DOWN) {
315  if (CAttribMenuInstance::GetInstance().KeyPress( event.GetKeyCode() )) {
316  Refresh();
317  return;
318  }
319  }
320 #endif
321 
322  x_HandleAccels(event);
323 
324  //trace = true;
325  if ( ! x_Handlers_handle(event, 0xFFFFFFFF, false)) {
326  event.Skip();
327  }
328  trace = false;
329 }
330 
331 
332 void CGlWidgetPane::OnSetFocus(wxFocusEvent& event)
333 {
334  Refresh();
335 }
336 
337 
338 void CGlWidgetPane::OnKillFocus(wxFocusEvent& event)
339 {
340  x_Handlers_handle(event, 0xFFFFFFFF, false);
341 
342  Refresh();
343 }
344 
345 void CGlWidgetPane::OnSize(wxSizeEvent& event)
346 {
347  if( ! x_Handlers_handle(event, 0xFFFFFFFF, true)) {
348  event.Skip();
349  }
350 
351  // This is for use in subclasses that want to know if size event was just
352  // part of the opengl fix.
353  m_PseudoSized = false;
354 }
355 
356 void CGlWidgetPane::OnCmdEvent(wxCommandEvent& event)
357 {
358  if( ! x_Handlers_handle(event, 0xFFFFFFFF, true)) {
359  event.Skip();
360  }
361 }
362 
363 void CGlWidgetPane::OnTipRemoved(wxCommandEvent& event)
364 {
365  // For (occasional) windows gaphics driver issue with overlapping windows. When
366  // an overlapping tooltip is removed you may not get an 'enterwindow' event since
367  // the cursor may not have gone inside the window.
369 
370  event.Skip();
371 }
372 
374 {
375  // Sometimes the size event will be handled before
376  // DlgGLWinOverlay returns, sometimes not. Make
377  // sure m_PseudoSized is set either way by setting it before
378  // function is called.
379 #ifdef __WXMSW__
380  m_PseudoSized = true;
381  DlgGLWinOverlayFix(this);
382 #endif
383 }
384 
385 CGlWidgetPane::CGlWidgetPane(wxWindow* parent, wxWindowID id,
386  const wxPoint& pos,
387  const wxSize& size,
388  long style)
389  : C3DCanvas(parent, id, pos, size, style)
390  , m_pCurrHandlerRec(NULL)
391  , m_PopupMenuDisplayed(false)
392  , m_GLOverlapFixTimer(this, WIDGET_PANE_ENTER_TIMER)
393  , m_PseudoSized(false)
394 {
395  SetBackgroundColour(wxColour(255, 255, 255));
396  // May need to access opengl here so make sure context has been
397  // initialized (e.g. for font metrics using texture fonts)
399 
400  // Initialize tooltip handler (virtual functions do not allow initialization in ctor)
401  TTHH_Init();
402 }
403 
404 
406 {
407 }
408 
409 
410 int CGlWidgetPane::x_GetAreaByWindowPos(const wxPoint& pos)
411 {
412  int w, h;
413  GetClientSize(&w, &h);
414  int vp_y = h - pos.y;
415  return x_GetAreaByVPPos(pos.x, vp_y);
416 }
417 
418 
419 // default implementation, to be overriden on derived classes
420 int CGlWidgetPane::x_GetAreaByVPPos(int vp_x, int vp_y)
421 {
422  return 0xFFFFFFFF;
423 }
424 
425 
426 ///////////////////////////////////////////////////////////////////////////////
427 // Handlers management
429  int area, CGlPane* pane, int index)
430 {
431  _ASSERT(handler && area);
433  if(it->m_pHandler == handler &&
434  it->m_Area == area &&
435  it->m_pPane == pane)
436  return false; // already registered
437  }
438  SHandlerRec rec;
439  rec.m_pHandler = handler;
440  rec.m_Area = area;
441  rec.m_pPane = pane;
442 
443  // Inserts handler into position index or at end of list
444  // if index >= inumber of handlers.
445  if (index >= 0 && index < (int)m_lsHandlerRecs.size()) {
446  int idx = 0;
448  if (idx++ == index) {
449  m_lsHandlerRecs.insert(it, rec);
450  return true;
451  }
452  }
453  } else {
454  m_lsHandlerRecs.push_back(rec);
455  }
456  return true;
457 }
458 
459 
461 {
463  if(it->m_pHandler == handler) {
466  m_lsHandlerRecs.erase(it);
467  return true;
468  }
469  }
470  return false; // not registered
471 }
472 
473 
475 {
476  m_pCurrHandlerRec = rec;
477 }
478 
479 
480 bool CGlWidgetPane::x_Handlers_handle(wxEvent& event, int area, bool ignore_curr)
481 {
482  if(trace) {
483  LOG_POST(Info << "CGlWidgetPane::x_Handlers_handle()");
484  }
485  bool res = false;
486 
487  SHandlerRec* p_first = ignore_curr ? NULL : m_pCurrHandlerRec;
488  if(p_first) {
489  res = x_DispatchEventToHandler(event, p_first);
490  if(trace) {
491  LOG_POST(Info << "first handler res " << res);
492  }
493  if(res) {
494  x_SetCurrHandler(p_first);
495  return res;
496  }
497  }
498  if(res == 0) {
499  if(trace) {
500  LOG_POST(Info << "iterating by handlers");
501  }
502  // event was not handled by current handler - iterate through over handlers
504  IGlEventHandler* handler = it->m_pHandler;
505  if(trace) {
506  LOG_POST(Info << " handler " << handler << " " << typeid(*handler).name());
507  LOG_POST(Info << " p_first->m_pHandler " << (p_first ? p_first->m_pHandler : NULL));
508  }
509  if((it->m_Area & area)
510  && (p_first == NULL || handler != p_first->m_pHandler) ) {
511  if(trace) {
512  LOG_POST(Info << "x_DispatchEventToHandler " << typeid(*handler).name());
513  }
514  res = x_DispatchEventToHandler(event, &*it);
515  if(res) {
516  x_SetCurrHandler(&(*it));
517  return res;
518  }
519  }
520  }
521  if(trace) {
522  LOG_POST(Info << "iterating by handlers - END");
523  }
524  }
525  return false;
526 }
527 
528 
529 void CGlWidgetPane::x_HandleAccels(wxKeyEvent& event)
530 {
531 // Attribute menus also use these keys. Attribute menu support should be enabled only
532 // for local debugging (not checked in)
533 #ifndef ATTRIB_MENU_SUPPORT
534  if (GetParent() && event.GetEventType() == wxEVT_KEY_DOWN) {
535  // Allow either = or + to be used for zoom in. This will then work for
536  // either 'ctrl+' or just '+' Of course the plus key is also '=' so we
537  // accept either.
538  if ((event.GetKeyCode() == WXK_NUMPAD_ADD) || (event.GetKeyCode() == int('='))){
539  wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, eCmdZoomIn);
540  GetParent()->GetEventHandler()->ProcessEvent(e);
541  }
542  if ((event.GetKeyCode() == WXK_NUMPAD_ADD) || (event.GetKeyCode() == int('+'))){
543  wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, eCmdZoomIn);
544  GetParent()->GetEventHandler()->ProcessEvent(e);
545  }
546  else if ((event.GetKeyCode() == WXK_NUMPAD_SUBTRACT) || (event.GetKeyCode() == int('-'))){
547  wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, eCmdZoomOut);
548  GetParent()->GetEventHandler()->ProcessEvent(e);
549  }
550  else if ((event.GetKeyCode() == WXK_NUMPAD_MULTIPLY) || (event.GetKeyCode() == int('8'))){
551  wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, eCmdZoomAll);
552  GetParent()->GetEventHandler()->ProcessEvent(e);
553  }
554  }
555 #endif
556 }
557 
558 
560 {
562 
563  handler->SetPane(rec->m_pPane);
564  wxEvtHandler* evt_handler = handler->GetEvtHandler();
565  _ASSERT(evt_handler);
566  bool res = evt_handler->ProcessEvent(event);
567  handler->SetPane(NULL);
568  return res;
569 }
570 
571 
572 /*
573 int CGlWidgetPane::x_Handlers_handle(CGUIEvent& event, int area, bool ignore_curr)
574 {
575  int res = 0;
576 
577  SHandlerRec* p_first = ignore_curr ? NULL : m_pCurrHandlerRec;
578  if(p_first) {
579  IGlEventHandler* handler = p_first->m_pHandler;
580  res = handler->handle(m_Event, *p_first->m_pPane);
581  if(res) {
582  x_SetCurrHandler(p_first);
583  return res;
584  }
585  }
586 
587  if(res == 0) {
588  // event was not handled by current handler - iterate through over handlers
589  NON_CONST_ITERATE(THandlerRecList, it, m_lsHandlerRecs) {
590  IGlEventHandler* handler = it->m_pHandler;
591  if((it->m_Area & area)
592  && (p_first == NULL || handler != p_first->m_pHandler) ) {
593  res = handler->handle(m_Event, *it->m_pPane);
594  if(res) {
595  x_SetCurrHandler(&(*it));
596  return res;
597  }
598  }
599  }
600  }
601  return 0;
602 }
603 */
604 
605 
606 ////////////////////////////////////////////////////////////////////////////////
607 /// class CGlWidgetBase
608 
609 BEGIN_EVENT_TABLE( CGlWidgetBase, wxPanel )
610  EVT_SIZE(CGlWidgetBase::OnSize)
611  EVT_COMMAND_SCROLL(ID_VSCROPLLBAR, CGlWidgetBase::OnScroll)
612  EVT_COMMAND_SCROLL(ID_HSCROPLLBAR, CGlWidgetBase::OnScroll)
613 
618 
623 
627 
628  // by default unconditionally enable all zoom commands
630 
632 
634  wxWindow* parent,
635  wxWindowID id,
636  const wxPoint& pos,
637  const wxSize& size,
638  long style,
639  const wxString& name)
640  : wxPanel(parent, id, pos, size, style, name)
641 {
642 }
643 
644 
646 {
647 }
648 
649 
651 {
653  x_SetPortLimits();
654  GetPort().ZoomAll();
655 }
656 
657 
658 void CGlWidgetBase::SetRegistryPath(const string& reg_path)
659 {
660  m_RegPath = reg_path;
661 }
662 
663 
665 {
666  LOG_POST(Error << "CGlWidgetBase::LoadSettings() - override in derived classes");
667 }
668 
669 
671 {
672  LOG_POST(Error << "CGlWidgetBase::SaveSettings() - override in derived classes");
673 }
674 
675 
677 {
678  return (CGlWidgetPane*) FindWindowById(ID_GLCHILDPANE, this);
679 }
680 
681 
682 void CGlWidgetBase::OnSize(wxSizeEvent& event)
683 {
684  wxSize size = event.GetSize();
685  if (size.GetWidth() == 0 || size.GetHeight() == 0)
686  return;
687 
688  Layout();
689 
690  CGlWidgetPane* child_pane = x_GetPane();
691  if ( ! child_pane)
692  return;
693 
694  int w, h;
695  child_pane->GetClientSize(&w, &h);
696 
697  TVPRect rcVP(0, 0, w - 1, h - 1);
698  GetPort().SetViewport(rcVP);
701  Refresh();
702 }
703 
704 void CGlWidgetBase::OnScroll(wxScrollEvent& event)
705 {
706  // When user scrolls check for dialog overlay fix just like we do for
707  // mouse down (since window has been updated)
708  CGlWidgetPane* p = x_GetPane();
709  if (p != NULL)
710  p->CheckOverlayTimer();
711 
712  if (event.GetOrientation() == wxHORIZONTAL) {
713  x_OnScrollX(event.GetPosition());
715  }
716  else if (event.GetOrientation() == wxVERTICAL) {
717  x_OnScrollY(event.GetPosition());
719  }
720 
721  // Don't want to record individual events when user is dragging
722  // the scrollbar (just record the mouse up/release in that case).
723  // But we do want to save position info for page up/down or clicking
724  // on the scroll track (jumping straight to a new position).
725  if (event.GetEventType() == wxEVT_SCROLL_THUMBRELEASE ||
726  event.GetEventType() == wxEVT_SCROLL_TOP ||
727  event.GetEventType() == wxEVT_SCROLL_BOTTOM ||
728  event.GetEventType() == wxEVT_SCROLL_LINEUP ||
729  event.GetEventType() == wxEVT_SCROLL_LINEDOWN ||
730  event.GetEventType() == wxEVT_SCROLL_PAGEUP ||
731  event.GetEventType() == wxEVT_SCROLL_PAGEDOWN) {
732  x_SaveStates();
733  }
734 }
735 
736 
737 void CGlWidgetBase::OnZoomIn(wxCommandEvent& event)
738 {
740 }
741 
742 
743 void CGlWidgetBase::OnZoomInX(wxCommandEvent& event)
744 {
746 }
747 
748 
749 void CGlWidgetBase::OnZoomInY(wxCommandEvent& event)
750 {
752 }
753 
754 
755 void CGlWidgetBase::OnZoomInMouse(wxCommandEvent& event)
756 {
757  CGlPane& port = GetPort();
758  if(port.IsZoomInAvaiable()) {
759  TModelUnit factor = port.GetZoomFactor();
761  x_UpdateOnZoom();
762  x_SaveStates();
763  }
764 }
765 
766 
767 void CGlWidgetBase::OnZoomOut(wxCommandEvent& event)
768 {
770 }
771 
772 
773 void CGlWidgetBase::OnZoomOutX(wxCommandEvent& event)
774 {
776 }
777 
778 
779 void CGlWidgetBase::OnZoomOutY(wxCommandEvent& event)
780 {
782 }
783 
784 
785 void CGlWidgetBase::OnZoomOutMouse(wxCommandEvent& event)
786 {
787  CGlPane& port = GetPort();
788  if(port.IsZoomOutAvaiable()) {
789  TModelUnit factor = port.GetZoomFactor();
790  port.ZoomPoint(m_PopupPoint, 1.0 / factor,
792  x_UpdateOnZoom();
793  x_SaveStates();
794  }
795 }
796 
797 
798 void CGlWidgetBase::OnZoomAll(wxCommandEvent& event)
799 {
801 }
802 
803 
804 void CGlWidgetBase::OnZoomAllX(wxCommandEvent& event)
805 {
807 }
808 
809 
810 void CGlWidgetBase::OnZoomAllY(wxCommandEvent& event)
811 {
813 }
814 
815 
816 void CGlWidgetBase::OnEnableCmdUpdate(wxUpdateUIEvent& event)
817 {
818  event.Enable(true);
819 }
820 
821 
823 {
824  GetPort().ZoomRect(rc);
825  x_UpdateOnZoom();
826  x_SaveStates();
827 }
828 
829 
831  TModelUnit factor,
832  CGlPane::EZoomOptions options)
833 {
834  GetPort().ZoomPoint(point, factor, (int)options);
835  x_UpdateOnZoom();
836  x_SaveStates();
837 }
838 
839 
841 {
842  GetPort().Scroll(d_x, d_y);
843  x_UpdateOnZoom();
844 }
845 
846 void CGlWidgetBase::x_ZoomIn(int options)
847 {
848  CGlPane& port = GetPort();
849  if(port.IsZoomInAvaiable()) { //### options
850  port.ZoomInCenter(options);
851  x_UpdateOnZoom();
852  x_SaveStates();
853  }
854 }
855 
856 
857 void CGlWidgetBase::x_ZoomOut(int options)
858 {
859  CGlPane& port = GetPort();
860  if(port.IsZoomOutAvaiable()) {
861  port.ZoomOutCenter(options);
862  x_UpdateOnZoom();
863  x_SaveStates();
864  }
865 }
866 
867 
868 void CGlWidgetBase::x_ZoomAll(int options)
869 {
870  CGlPane& port = GetPort();
871  if(port.IsZoomOutAvaiable()) {
872  port.ZoomAll(options);
873  x_UpdateOnZoom();
874  x_SaveStates();
875  }
876 }
877 
878 bool CGlWidgetBase::DoPopupMenu(wxMenu *menu, int x, int y)
879 {
881 
882  // blocking call..
883  bool b = wxPanel::DoPopupMenu(menu,x,y);
884 
886 
887  return b;
888 }
889 
891 {
892  _ASSERT( ! x_GetPane());
893 
894  x_CreatePane();
895 
896  CGlWidgetPane* child_pane = x_GetPane();
897  _ASSERT(child_pane);
898 
899  wxFlexGridSizer* sizer = new wxFlexGridSizer(2, 2, 0, 0);
900  this->SetSizer(sizer);
901 
902  sizer->AddGrowableCol(0);
903  sizer->AddGrowableRow(0);
904 
905  sizer->Add(child_pane, 1, wxEXPAND);
906 
907  wxScrollBar*
908  vsb = new CUnfocusedScrollbar(this, ID_VSCROPLLBAR, wxDefaultPosition,
909  wxDefaultSize, wxSB_VERTICAL);
910  sizer->Add(vsb, 0, wxEXPAND);
911 
912  wxScrollBar*
913  hsb = new CUnfocusedScrollbar(this, ID_HSCROPLLBAR, wxDefaultPosition,
914  wxDefaultSize, wxSB_HORIZONTAL);
915  sizer->Add(hsb, 0, wxEXPAND);
916 
917  vsb->SetMinSize(wxSize(wxDefaultCoord, 4));
918  hsb->SetMinSize(wxSize(4, wxDefaultCoord));
919 
920  sizer->AddSpacer(1);
921 }
922 
923 
925 {
926  CGlWidgetPane* child_pane = x_GetPane();
927  if (child_pane) {
928  child_pane->Refresh();
929  }
930 }
931 
932 
933 ////////////////////////////////////////////////////////////////////////////////
934 /// Update handlers
935 
937 {
938  /// Update data strutures
939  /// update m_Port (x_SetPortLimits)
940  /// update visible rect in m_Port
941  /// x_UpdateScrollbars() if necessary
942  /// x_UpdatePanes() ?
943  /// x_RedrawControls()
944 }
945 
947 {
951 }
952 
954 {
955  x_UpdateOnZoom();
956 }
957 
959 {
960  x_UpdateOnZoom();
961 }
962 
964 {
965  /// notify our parent that we've changed
967  Send(&evt, ePool_Parent);
968  Refresh();
969 }
970 
971 
972 static const double kPageInc = 0.8;
973 static const double kLineDiv = 50;
974 
975 
976 // we map the real model range to integer scrol range [0, kScrollRange]
977 // CNormalizer provides functions for converting between the model and scroll ranges
979 {
980  wxScrollBar* scroll_bar_v = (wxScrollBar*)FindWindow(ID_VSCROPLLBAR);
981  wxScrollBar* scroll_bar_h = (wxScrollBar*)FindWindow(ID_HSCROPLLBAR);
982 
983  CGlPane& port = GetPort();
984  const TModelRect& rc_all = port.GetModelLimitsRect();
985  const TModelRect& rc_vis = port.GetVisibleRect();
986 
987  if (scroll_bar_h) {
988  int range = (int)min(rc_all.Width(), (kLineDiv*rc_all.Width())/rc_vis.Width());
989  // Need a min for cases where limits are small, e.g. 0.0 to 1.0
990  range = std::max((int)kLineDiv,range);
991 
992  CNormalizer norm(rc_all.Left(), rc_all.Right(), range);
993  int position = norm.RealToInt(rc_vis.Left());
994  int thumb_size = norm.SizeToInt(rc_vis.Width());
995  int page_size = norm.SizeToInt(rc_vis.Width() * kPageInc);
996 
997  scroll_bar_h->SetScrollbar(position, thumb_size, range, page_size);
998  }
999  if (scroll_bar_v) {
1000  int range, position, page_size, thumb_size;
1001 
1002  if( rc_all.Height() > 0 ){
1003  range = (int) min( rc_all.Height(), (kLineDiv*rc_all.Height())/rc_vis.Height() );
1004  // Need a min for cases where limits are small, e.g. 0.0 to 1.0
1005  range = std::max((int)kLineDiv,range);
1006 
1007  // Remember, vertical dimension is flipped
1008  // so calculations differ from horisontal case
1009  CNormalizer norm( rc_all.Bottom(), rc_all.Top(), range );
1010 
1011  // use Top, not Bottom because of the flipping
1012  position = range - norm.RealToInt( rc_vis.Top() );
1013 
1014  page_size = norm.SizeToInt( rc_vis.Height() * kPageInc );
1015  thumb_size = norm.SizeToInt( rc_vis.Height() );
1016 
1017  } else {
1018  range = (int) min( -rc_all.Height(), (kLineDiv*rc_all.Height())/rc_vis.Height() );
1019  // Need a min for cases where limits are small, e.g. 0.0 to 1.0
1020  range = std::max((int)kLineDiv,range);
1021 
1022  // Remember, vertical dimension is flipped
1023  // so calculations differ from horisontal case
1024  CNormalizer norm( rc_all.Top(), rc_all.Bottom(), range );
1025 
1026  // use Top, not Bottom because of the flipping
1027  position = norm.RealToInt( rc_vis.Top() );
1028 
1029  page_size = norm.SizeToInt( -rc_vis.Height() * kPageInc );
1030  thumb_size = norm.SizeToInt( -rc_vis.Height() );
1031  }
1032 
1033  scroll_bar_v->SetScrollbar( position, thumb_size, range, page_size );
1034  }
1035 }
1036 
1037 
1039 {
1040  CGlWidgetPane* child_pane = x_GetPane();
1041  CGlPane& port = GetPort();
1042  const TModelRect& rc_all = port.GetModelLimitsRect();
1043  const TModelRect& rc_vis = port.GetVisibleRect();
1044 
1045  int range = (int) min(rc_all.Width(), (kLineDiv*rc_all.Width())/rc_vis.Width());
1046  // Need a min for cases where limits are small, e.g. 0.0 to 1.0
1047  range = std::max((int)kLineDiv,range);
1048 
1049  CNormalizer norm(rc_all.Left(), rc_all.Right(), range);
1050  double d_x = norm.IntToReal(pos) - rc_vis.Left();
1051  port.Scroll(d_x, 0);
1052 
1053  if (child_pane) {
1054  child_pane->Refresh();
1055  }
1056 }
1057 
1058 
1060 {
1061  CGlWidgetPane* child_pane = x_GetPane();
1062  CGlPane& port = GetPort();
1063  const TModelRect& rc_all = port.GetModelLimitsRect();
1064  const TModelRect& rc_vis = port.GetVisibleRect();
1065 
1066  int range;
1067  double d_y;
1068 
1069  if( rc_all.Height() > 0 ){
1070  range = (int) min( rc_all.Height(), (kLineDiv*rc_all.Height())/rc_vis.Height() );
1071  // Need a min for cases where limits are small, e.g. 0.0 to 1.0
1072  range = std::max((int)kLineDiv,range);
1073 
1074  CNormalizer norm( rc_all.Bottom(), rc_all.Top(), range );
1075  d_y = norm.IntToReal( range-pos ) - rc_vis.Top();
1076  } else {
1077  // Remember, vertical dimension is flipped
1078  // so calculations differ from horisontal case
1079  range = (int) min( -rc_all.Height(), (kLineDiv*rc_all.Height())/rc_vis.Height() );
1080  // Need a min for cases where limits are small, e.g. 0.0 to 1.0
1081  range = std::max((int)kLineDiv,range);
1082 
1083  CNormalizer norm( rc_all.Top(), rc_all.Bottom(), range );
1084  d_y = norm.IntToReal( pos ) - rc_vis.Top();
1085  }
1086 
1087  port.Scroll( 0, d_y );
1088 
1089  if( child_pane ){
1090  child_pane->Refresh();
1091  }
1092 }
1093 
1094 
1096 {
1097  // send "Decorate" event to listeners
1098  CPopupMenuEvent evt(this, menu);
1100 
1101  // obtain the modified menu and clean it empty sections
1102  menu = evt.GetMenu();
1103  CleanupSeparators(*menu);
1104 
1105  // connect contributed wxEvtHandlers so that they can handle commands
1106  vector<wxEvtHandler*>& handlers = evt.GetHandlers();
1107  for( size_t i = 0; i < handlers.size(); i++ ) {
1108  PushEventHandler(handlers[i]);
1109  }
1110 
1111  // show the menu
1112  PopupMenu(menu);
1113 
1114  delete menu;
1115 
1116  // disconnect and destroy the handlers
1117  for( size_t i = 0; i < handlers.size(); i++ ) {
1118  wxEvtHandler* h = PopEventHandler();
1119  _ASSERT(h == handlers[i]);
1120  delete h;
1121  }
1122 }
1123 
1124 
1125 // dummy event handler
1127 {
1128  _TRACE("unhandled event: CGlWidgetBase:OnViewEvent()");
1129 }
1130 
1131 
static CAttribMenu & GetInstance()
Return a static instance of CAttribMenu.
Definition: attrib_menu.cpp:50
CEvent - generic event implementation TODO TODO - Attachments.
Definition: event.hpp:86
CGLCanvas.
Definition: glcanvas.hpp:55
void x_SetupGLContext()
Definition: glcanvas.cpp:264
class CGlPane
Definition: glpane.hpp:62
class CGlWidgetBase
void OnSize(wxSizeEvent &event)
void OnZoomInY(wxCommandEvent &event)
virtual void x_UpdateOnZoom()
void OnZoomOutX(wxCommandEvent &event)
virtual void Scroll(TModelUnit d_x, TModelUnit d_y)
void OnAllEvents(CViewEvent::TEventObject evt)
virtual void x_OnScrollY(int pos)
virtual void x_UpdateOnVScroll()
virtual void NotifyVisibleRangeChanged()
TModelPoint m_PopupPoint
virtual void SetRegistryPath(const string &reg_path)
virtual void x_SaveStates()
void OnZoomAllX(wxCommandEvent &event)
virtual void x_ZoomIn(int options)
Zoom functions.
virtual void LoadSettings()
virtual CGlPane & GetPort()=0
implement these 2 functions in derived classes
virtual void ZoomRect(const TModelRect &rc)
void OnEnableCmdUpdate(wxUpdateUIEvent &event)
void OnScroll(wxScrollEvent &event)
void OnZoomAll(wxCommandEvent &event)
void OnZoomOutY(wxCommandEvent &event)
virtual void x_RedrawControls(void)
virtual void x_ZoomOut(int options)
virtual void x_ZoomAll(int options)
string m_RegPath
path to the widget's settings in GUI Registry
void OnZoomInX(wxCommandEvent &event)
virtual void x_UpdateOnHScroll()
void OnZoomInMouse(wxCommandEvent &event)
virtual void x_CreateControls(void)
creates Pane, Scrollbars and other child widgets, called from Create()
virtual void Create()
creates controls and performs basic initialization
void OnZoomIn(wxCommandEvent &event)
void OnZoomOutMouse(wxCommandEvent &event)
virtual void x_SetPortLimits(void)=0
updates model limits of the Master CGlPane
virtual void x_UpdateScrollbars()
virtual void ZoomPoint(const TModelPoint &point, TModelUnit factor, CGlPane::EZoomOptions=CGlPane::fZoomXY)
virtual bool DoPopupMenu(wxMenu *menu, int x, int y)
Override to record when (blocking) popup menu is active.
void OnZoomAllY(wxCommandEvent &event)
virtual void SaveSettings() const
virtual ~CGlWidgetBase()
virtual void x_OnScrollX(int pos)
virtual void x_ShowDecoratedPopupMenu(wxMenu *menu)
virtual void x_CreatePane()=0
factory method creating master pane, called form x_CreateControls()
virtual CGlWidgetPane * x_GetPane()
virtual void x_Update()
Update handlers.
void OnZoomOut(wxCommandEvent &event)
CGlWidgetPane represent a window component residing in CGlWidgetBase client area.
virtual void GHH_ReleaseMouse()
releases captured mouse
void OnMouseUp(wxMouseEvent &event)
THandlerRecList m_lsHandlerRecs
list of records for registered handlers
void OnMouseDown(wxMouseEvent &event)
bool x_DispatchEventToHandler(wxEvent &event, SHandlerRec *rec)
void x_SetCurrHandler(SHandlerRec *rec)
virtual ~CGlWidgetPane()
void OnKillFocus(wxFocusEvent &event)
void OnMouseCaptureLost(wxMouseCaptureLostEvent &event)
virtual bool TC_NeedTooltip(const wxPoint &pt)
Returns "true" if client wants to dispaly a tooltip.
bool m_PseudoSized
For windows (e.g. tree) that do not want to layout/update for the fake size event.
void OnTimer(wxTimerEvent &event)
void OnCmdEvent(wxCommandEvent &event)
void x_HandleAccels(wxKeyEvent &event)
bool x_Handlers_handle(wxEvent &event, int area, bool ignore_curr=true)
void SetPopupMenuDisplayed(bool b)
list< SHandlerRec > THandlerRecList
bool x_UnregisterHandler(IGlEventHandler *handler)
void OnMouseWheel(wxMouseEvent &event)
bool x_RegisterHandler(IGlEventHandler *handler, int area, CGlPane *pane, int index=-1)
void OnMotion(wxMouseEvent &event)
virtual bool x_GrabFocus()
void OnTipRemoved(wxCommandEvent &event)
void OnSetFocus(wxFocusEvent &event)
void OnKeyEvent(wxKeyEvent &event)
wxTimer m_GLOverlapFixTimer
Need associated timer since some popups take a little time to clear.
void OnSize(wxSizeEvent &event)
CGlWidgetPane(wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0)
void CheckOverlayTimer()
void OnLeaveWindow(wxMouseEvent &event)
virtual void GHH_CaptureMouse()
captures mouse events in the hosting window for D&D
virtual int x_GetAreaByVPPos(TVPUnit vp_x, TVPUnit vp_y)
virtual int x_GetAreaByWindowPos(const wxPoint &pos)
virtual wxWindow * TC_GetWindow()
Returns pointer to the widget hosting ITooltipClient.
virtual string TC_GetTooltip(const wxRect &rect)
Returns tooltip string and coordinates for area tootlip associated with.
CStopWatch m_EnterTimer
Windows vista bug screws up opengl after dlgs/popups displayed over window.
virtual void GHH_SetCursor(const wxCursor &cursor)
changes the cursor in the hosting window
SHandlerRec * m_pCurrHandlerRec
pointer to record for last active handler
void OnEnterWindow(wxMouseEvent &event)
this class converts model units to the integers distribited in [0, m_IntRange] and vice versa
double IntToReal(int i)
int RealToInt(double real)
int SizeToInt(double size)
CPopupMenuEvent - an event that is sent when a popup menu needs to be shown.
Definition: popup_event.hpp:54
wxMenu * GetMenu()
Definition: popup_event.hpp:75
THandlers & GetHandlers()
Definition: popup_event.hpp:88
@ eWidgetRangeChanged
notification from child to parent that the visible range has changed
Definition: view_event.hpp:58
IGlEventHandler.
virtual void SetPane(CGlPane *)
void TTHH_Init()
Init calls virtual functions so can't be called from ctor.
GUI command routing and handling framework.
void(*)(CSeq_entry_Handle seh, IWorkbench *wb, const CSerialObject &obj) handler
#define false
Definition: bool.h:36
static const double kLineDiv
static bool trace
static const double kPageInc
#define WIDGET_PANE_ENTER_TIMER
EVT_COMMAND_RANGE(eCmdFirstStickyToolTipCmd, eCmdLastStickyToolTipCmd, wxEVT_COMMAND_BUTTON_CLICKED, CGlWidgetPane::OnCmdEvent) void CGlWidgetPane
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define NULL
Definition: ncbistd.hpp:225
#define _TRACE(message)
Definition: ncbidbg.hpp:122
#define LOG_POST(message)
This macro is deprecated and it's strongly recomended to move in all projects (except tests) to macro...
Definition: ncbidiag.hpp:226
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
TModelUnit GetZoomFactor(void) const
Definition: glpane.hpp:468
GLdouble TModelUnit
Definition: gltypes.hpp:48
void ZoomPoint(TModelUnit x, TModelUnit y, TModelUnit factor, int options=fZoomXY)
Definition: glpane.cpp:311
void ZoomInCenter(int options=fZoomXY)
Definition: glpane.cpp:338
void ZoomOutCenter(int options=fZoomXY)
Definition: glpane.cpp:343
T Height() const
Definition: glrect.hpp:90
void SetViewport(const TVPRect &R)
Definition: glpane.cpp:96
T Top() const
Definition: glrect.hpp:84
T Bottom() const
Definition: glrect.hpp:82
T Width() const
Definition: glrect.hpp:86
T Right() const
Definition: glrect.hpp:83
bool IsZoomInAvaiable(void)
Definition: glpane.cpp:275
void ZoomAll(int options=fZoomXY)
Definition: glpane.cpp:289
void AdjustToLimits()
Definition: glpane.hpp:504
void ZoomRect(const TModelRect &r)
Definition: glpane.cpp:348
TModelRect & GetModelLimitsRect(void)
Definition: glpane.hpp:347
T Left() const
Definition: glrect.hpp:81
void Scroll(TModelUnit dx, TModelUnit dy)
Definition: glpane.cpp:602
EZoomOptions
EZoomOptions flags control behavior of Zoom operations.
Definition: glpane.hpp:99
bool IsZoomOutAvaiable(void)
Definition: glpane.cpp:280
TModelRect & GetVisibleRect(void)
Definition: glpane.hpp:357
@ fZoomX
Definition: glpane.hpp:100
@ fZoomY
Definition: glpane.hpp:101
@ fZoomXY
Definition: glpane.hpp:103
virtual bool Send(CEvent *evt, EDispatch disp_how=eDispatch_Default, int pool_name=ePool_Default)
Sends an event synchronously.
@ eCmdFirstStickyToolTipCmd
Definition: command.hpp:116
@ eCmdLastStickyToolTipCmd
Event fired when an existing tip is removed.
Definition: command.hpp:138
@ eCmdTipRemoved
Event fired when a new tip added.
Definition: command.hpp:137
@ eCmdZoomOutX
Definition: command.hpp:78
@ eCmdZoomAllX
Definition: command.hpp:79
@ eCmdZoomInMouse
Definition: command.hpp:71
@ eCmdZoomOutMouse
Definition: command.hpp:72
@ eCmdZoomOutY
Definition: command.hpp:81
@ eCmdZoomInX
Definition: command.hpp:77
@ eCmdZoomIn
empty command
Definition: command.hpp:68
@ eCmdZoomAllY
Definition: command.hpp:82
@ eCmdZoomOut
Definition: command.hpp:69
@ eCmdSetEqualScale
Definition: command.hpp:83
@ eCmdZoomInY
Definition: command.hpp:80
@ eCmdZoomAll
Definition: command.hpp:70
@ eEvent_Message
message from one class to another
Definition: event.hpp:99
@ eDispatch_Default
dispatch until handled at least by one handler
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
bool IsRunning(void) const
Check state of stopwatch.
Definition: ncbitime.hpp:2836
double Restart(void)
Return time elapsed since first Start() or last Restart() call (in seconds).
Definition: ncbitime.hpp:2817
double Elapsed(void) const
Return time elapsed since first Start() or last Restart() call (in seconds).
Definition: ncbitime.hpp:2776
void Reset(void)
Stop (if running) and reset the timer.
Definition: ncbitime.hpp:2808
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
END_EVENT_TABLE()
int i
CMinPanelContainer::OnRestoreWindow EVT_UPDATE_UI_RANGE(eCmdCloseDockPanel, eCmdWindowRestore, CMinPanelContainer::OnUpdateWindowCommand) CMinPanelContainer
#define wxT(x)
Definition: muParser.cpp:41
range(_Ty, _Ty) -> range< _Ty >
const struct ncbi::grid::netcache::search::fields::SIZE size
T max(T x_, T y_)
T min(T x_, T y_)
Int4 delta(size_t dimension_, const Int4 *score_)
wxEVT_COMMAND_MENU_SELECTED
@ ID_VSCROPLLBAR
@ ID_HSCROPLLBAR
ViewerWindowBase::OnEditMenu ViewerWindowBase::OnJustification EVT_MENU(MID_SHOW_GEOM_VLTNS, ViewerWindowBase::OnShowGeomVltns) EVT_MENU(MID_FIND_PATTERN
IGlEventHandler * m_pHandler
#define _ASSERT
void SetFocus(CRef< objects::CSeq_entry > entry)
bool DlgGLWinOverlayFix(wxWindow *win)
Fix a problem on windows where after a dialog overlays an opengl window the opengl window may be cons...
Definition: wx_utils.cpp:1290
void CleanupSeparators(wxMenu &menu)
Removes extra separators (in the begining or at the end of the menu, ot those that precede other sepa...
Definition: wx_utils.cpp:668
#define const
Definition: zconf.h:232
Modified on Wed Apr 17 13:09:09 2024 by modify_doxy.py rev. 669887