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

Go to the SVN repository for this file.

1 /* $Id: minimap_handler.cpp 42737 2019-04-08 18:13:09Z katargir $
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: Vladimir Tereshkov, Andrey Yazhuk
27  *
28  * File Description:
29  *
30  */
31 #include <ncbi_pch.hpp>
32 
33 
34 #include <gui/opengl/glhelpers.hpp>
36 #include <gui/opengl/irender.hpp>
38 
39 #include <math.h>
40 
41 #include <wx/utils.h>
42 
44 
45 ////////////////////////////////////////////////////////////////////////////////
46 /// class CMinimapHandler
47 
48 BEGIN_EVENT_TABLE(CMinimapHandler, wxEvtHandler)
49  EVT_LEFT_DOWN(CMinimapHandler::OnLeftDown)
50  EVT_LEFT_UP(CMinimapHandler::OnLeftUp)
51  EVT_MOTION(CMinimapHandler::OnMotion)
52  EVT_MOUSEWHEEL(CMinimapHandler::OnMouseWheel)
53  EVT_MOUSE_CAPTURE_LOST(CMinimapHandler::OnMouseCaptureLost)
54  EVT_KEY_DOWN(CMinimapHandler::OnKeyDown)
55  EVT_KEY_UP(CMinimapHandler::OnKeyUp)
57 
58 
60 : m_pTexture(NULL),
61  m_XCoordLimit(1.0f),
62  m_YCoordLimit(1.0f),
63  m_Host(NULL),
64  m_State(eIdle),
65  m_PixPerNorm(50),
66  m_MouseStart(0, 0),
67  m_CurrPos(0, 0),
68  m_InnerRectX(0), m_InnerRectY(0),
69  m_InnerRectW(0), m_InnerRectH(0),
70  m_ScaleColor(0.0f, 0.6f, 0.0f, 0.3f),
71  m_TickColor(0.0f, 0.6f, 0.0f, 1.0f),
72  m_RectColor(0.7f, 0.8f, 0.7f, 0.85f)
73 {
74 }
75 
76 
78 {
79 }
80 
81 
83 {
84  m_Pane = pane;
85 }
86 
87 
89 {
90  return this;
91 }
92 
93 
95 {
96  m_Host = host;
97 }
98 
99 
101 {
102  return dynamic_cast<IGenericHandlerHost*>(m_Host);
103 }
104 
105 
106 static int kGaugeMaxDim = 160;
107 static float kMinInnerRectDim = 5.0f;
108 
110 {
111  CGlAttrGuard AttrGuard(GL_ENABLE_BIT | GL_POLYGON_BIT | GL_HINT_BIT);
112 
113  switch(m_State) {
114  case eReadyMinimap:
115  case eMinimap: {
116  if ( ! m_pTexture) {
118  if (m_pTexture) {
120  }
121  }
122  x_RenderMinimap(pane);
123  break;
124  }
125  default:
126  break;
127  }
128 }
129 
130 
132 {
133  IRender& gl = GetGl();
134 
135  gl.Enable(GL_BLEND);
136  gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
137 
138 
139  const TModelRect & visRect = pane.GetVisibleRect();
140  const TModelRect & modRect = pane.GetModelLimitsRect();
141 
142  int vw = pane.GetViewport().Width();
143  int vh = pane.GetViewport().Height();
144 
145  int ext_w;
146  int ext_h;
147 
148  if (vw > vh) {
149  ext_w = kGaugeMaxDim;
150  ext_h = kGaugeMaxDim*(((double)vh)/(double)vw);
151  }
152  else {
153  ext_h = kGaugeMaxDim;
154  ext_w = kGaugeMaxDim*(((double)vw)/(double)vh);
155  }
156 
157  m_scalex = (int)((double)ext_w) / (double)modRect.Width();
158  m_scaley = (int)((double)ext_h) / (double)modRect.Height();
159 
160  // Set inner rect cursor size (but don't let it get too small):
161  float w_h = ((float)vw)/((float)vh);
162  m_InnerRectW = std::max((int) (visRect.Width() * m_scalex),
163  (int) (kMinInnerRectDim * w_h) );
164  m_InnerRectH = std::max((int) (visRect.Height() * m_scaley),
165  (int) (kMinInnerRectDim * 1.0f/w_h) );
166 
167  m_InnerRectX = (int) ((visRect.Left() - modRect.Left()) * m_scalex);
168  m_InnerRectY = (int) ((-visRect.Top() + modRect.Top()) * m_scaley);
169 
170  pane.OpenPixels();
171 
172  int base_x = m_MarkerPos.x;
173  int base_y = m_MarkerPos.y;
174  int dim_y = m_Host->MMHH_GetVPPosByY(0);
175 
176  // external rect
177  int yb = dim_y - (base_y + ext_h/2);
178  int yt = dim_y - (base_y - ext_h/2);
179  int xl = base_x - ext_w / 2;
180  int xr = base_x + ext_w / 2;
181  m_Minimap.Init(xl, dim_y-yt, xr, dim_y-yb);
182 
183  // internal rect
184  int yb_i = std::max(yt-m_InnerRectY-m_InnerRectH, yb);
185  yb_i = std::min(yb_i, yt-m_InnerRectH);
186  int yt_i = yb_i + m_InnerRectH;
187 
188  int xl_i = std::max(xl + m_InnerRectX, xl);
189  xl_i = std::min(xl_i, xr-m_InnerRectW);
190  int xr_i = xl_i + m_InnerRectW;
191  m_MiniCursor.Init(xl_i, dim_y-yt_i, xr_i, dim_y-yb_i);
192 
193  // external/internal rects
194  gl.Enable(GL_TEXTURE_2D);
195  // texture should always be there (but check):
196  if (m_pTexture)
198 
199  gl.ColorC(m_RectColor);
200  gl.Begin(GL_QUADS);
201  gl.TexCoord2f(0, 0);
202  gl.Vertex2d(xl, yb);
203  gl.TexCoord2f(m_XCoordLimit, 0);
204  gl.Vertex2d(xr, yb);
206  gl.Vertex2d(xr, yt);
207  gl.TexCoord2f(0, m_YCoordLimit);
208  gl.Vertex2d(xl, yt);
209  gl.End();
210  gl.Disable(GL_TEXTURE_2D);
211 
212  gl.ColorC(m_ScaleColor);
213  gl.Begin(GL_QUADS);
214  gl.Vertex2d(xl_i, yb_i);
215  gl.Vertex2d(xr_i, yb_i);
216  gl.Vertex2d(xr_i, yt_i);
217  gl.Vertex2d(xl_i, yt_i);
218  gl.End();
219 
220  gl.LineWidth(1.0);
221  gl.ColorC(m_TickColor);
222  gl.Begin(GL_LINE_LOOP);
223  gl.Vertex2d(xl_i, yb_i);
224  gl.Vertex2d(xr_i, yb_i);
225  gl.Vertex2d(xr_i, yt_i);
226  gl.Vertex2d(xl_i, yt_i);
227  gl.End();
228 
229  gl.Begin(GL_LINE_LOOP);
230  gl.Vertex2d(xl, yb);
231  gl.Vertex2d(xr, yb);
232  gl.Vertex2d(xr, yt);
233  gl.Vertex2d(xl, yt);
234  gl.End();
235 
236  pane.Close();
237 
239 }
240 
241 
242 ////////////////////////////////////////////////////////////////////////////////
243 /// event handlers
245 {
246  return wxGetKeyState(wxKeyCode('M'));
247 }
248 
249 
250 void CMinimapHandler::OnLeftDown(wxMouseEvent& event)
251 {
252  EState ready_st = eIdle, active_st = eIdle;
253  if(sIsMiniMapMode()) {
254  ready_st = eReadyMinimap;
255  active_st = eMinimap;
256  }
257 
258  if(ready_st != eIdle) {
259  wxPoint ms_pos = event.GetPosition();
260  x_SwitchToReadyState(ready_st, ms_pos);
261  x_SwithToActiveState(active_st, ms_pos);
262  x_OnSelectCursor(ms_pos);
263  } else {
264  event.Skip();
265  }
266 }
267 
268 
269 void CMinimapHandler::OnMotion(wxMouseEvent& event)
270 {
271  m_LastMouse = event.GetPosition();
272 
273  if(event.Dragging()) {
274  switch(m_State) {
275  case eMinimap: {
276  wxPoint ms_pos = event.GetPosition();
277 
278  // More intuitive to just have one mode of operation?
279  //if (m_Substate == eNormal){
280  // x_OnChangePan(ms_pos);
281  // }
282  //if (m_Substate == eCursor){
283  int x = ms_pos.x - m_MiniCursor.Left() - m_MiniCursor.Width() / 2;
284  int y = ms_pos.y - m_MiniCursor.Bottom() - m_MiniCursor.Height() / 2;
285  x_OnChangeZoomRectPan(x, -y);
286  //}
287  x_OnSelectCursor(ms_pos);
288  break;
289  }
290  default:
291  break;
292  }
293  } else {
294  if(m_State != eIdle ) {
295  wxPoint ms_pos = event.GetPosition();
296  x_OnSelectCursor(ms_pos);
297  } else {
298  event.Skip();
299  }
300  }
301 }
302 
303 
304 void CMinimapHandler::x_OnChangePan(const wxPoint& ms_pos)
305 {
306  m_CurrPos = ms_pos;
307 
308  int y1 = m_Host->MMHH_GetVPPosByY(m_MouseStart.y);
309  int y2 = m_Host->MMHH_GetVPPosByY(m_CurrPos.y);
310 
312  TModelUnit m_y1 = m_Pane->UnProjectY(y1);
314  TModelUnit m_y2 = m_Pane->UnProjectY(y2);
315 
316  m_Host->MMHH_Scroll(m_x1 - m_x2, m_y1 - m_y2);
318 
320 }
321 
322 
323 void CMinimapHandler::OnLeftUp(wxMouseEvent& event)
324 {
325  switch(m_State) {
326  case eMinimap:
327  case eReadyMinimap: {
328  wxPoint ms_pos = event.GetPosition();
329  if (m_Substate == eJumpTo) {
330  int x = ms_pos.x - m_MiniCursor.Left() - m_MiniCursor.Width() / 2;
331  int y = ms_pos.y - m_MiniCursor.Bottom() - m_MiniCursor.Height() / 2;
332  x_OnChangeZoomRectPan(x, -y);
333  }
335  x_OnSelectCursor(ms_pos);
336  return;
337  }
338  default:
339  break;
340  }
341  event.Skip();
342 }
343 
344 
345 void CMinimapHandler::OnMouseWheel(wxMouseEvent& event)
346 {
347  if(sIsMiniMapMode()) {
348  wxPoint ms_pos = event.GetPosition();
349  switch(m_State) {
350  case eIdle:
352  // continue
353  case eReadyMinimap: {
354  m_WheelTotalShift = 0;
356  } // continue
357  case eMinimap: {
358  m_WheelTotalShift += event.GetWheelRotation();
359  //x_OnChangeScale(m_WheelTotalShift);
360  // updating shift after clipping with Min and Max norm values
362  break;
363  }
364  default:
365  _ASSERT(false);
366  break;
367  }
368  x_OnSelectCursor(ms_pos);
369  } else {
370  event.Skip();
371  }
372 }
373 
374 
375 void CMinimapHandler::OnKeyDown(wxKeyEvent& event)
376 {
377  if(m_State == eIdle) {
378  EState ready_st = sIsMiniMapMode() ? eReadyMinimap : eIdle;
379  if(ready_st != eIdle) {
380 
381  // On mac, event object in OnKeyDown does not have correct mouse position.
382  x_SwitchToReadyState(ready_st, event.GetPosition());
383  x_OnSelectCursor(event.GetPosition());
384  }
385  }
386  if(m_State == eIdle) {
387  event.Skip();
388  }
389 }
390 
391 
392 void CMinimapHandler::OnKeyUp(wxKeyEvent& event)
393 {
394  if(! sIsMiniMapMode()) {
395  switch(m_State) {
396  case eReadyMinimap:
397  case eMinimap: {
399  m_State = eIdle;
400  m_pTexture = NULL;
401  x_OnSelectCursor(event.GetPosition());
402  return;
403  }
404  default:
405  break;
406  }
407  }
408  event.Skip();
409 }
410 
411 
412 ////////////////////////////////////////////////////////////////////////////////
413 /// Signal handlers
414 
415 void CMinimapHandler::x_SwitchToReadyState(EState new_state, const wxPoint& ms_pos)
416 {
417  _ASSERT(m_Host);
418  if(m_State != new_state) {
419  m_State = new_state;
420 
421  // ms_pos doesn't work on mac for keydown events (large negative value).
423 
424  if(m_State == eReadyMinimap) {
427 
430  }
432  }
433 }
434 
435 
437 {
438  _ASSERT(m_Host);
439 
440  m_State = state;
441  m_MouseStart = ms_pos;
442 
445 }
446 
447 
449 {
450  m_Host->MMHH_Scroll(x / m_scalex, y / m_scaley);
452 }
453 
454 
456 {
457  _ASSERT(new_state != eMinimap);
458 
459  m_State = new_state;
461 
462  m_Host->MMHH_EndOp();
465 }
466 
467 
468 void CMinimapHandler::x_OnSelectCursor(const wxPoint& ms_pos)
469 {
470  switch(m_State) {
471  case eIdle:
472  m_CursorId = wxCURSOR_ARROW;
473  break;
474  case eReadyMinimap:
475  case eMinimap: {
476  m_Substate = x_GetSubstate(ms_pos);
477  switch (m_Substate){
478  case eJumpTo:
479  m_CursorId = wxCURSOR_HAND;
480  break;
481  default:
482  m_CursorId = wxCURSOR_SIZING;
483  break;
484  }
485  break;
486  }
487  default:
488  break;
489  }
490 }
491 
492 
494 {
495  return log(scale);
496 }
497 
498 
500 {
501  return exp(norm);
502 }
503 
504 
506 {
507  int x = ms_pos.x;
508  int y = ms_pos.y;
509 
510  if ((y > m_MiniCursor.Bottom() && y < m_MiniCursor.Top()) &&
511  (x > m_MiniCursor.Left() && x < m_MiniCursor.Right())) {
512  return eCursor;
513  }
514  else if ((y > m_Minimap.Bottom() && y < m_Minimap.Top()) &&
515  (x > m_Minimap.Left() && x < m_Minimap.Right())) {
516  return eJumpTo;
517  }
518  return eNormal;
519 }
520 
521 
522 void CMinimapHandler::OnMouseCaptureLost(wxMouseCaptureLostEvent& evt)
523 {
524  // should we do anything here?
525 }
526 
527 
CGlAttrGuard - guard class for restoring OpenGL attributes.
Definition: glutils.hpp:130
class CGlPane
Definition: glpane.hpp:62
CMinimapHandler provides support for mouse-driven zoom and pan operations.
IMinimapHandlerHost * m_Host
void OnKeyUp(wxKeyEvent &event)
void x_OnChangeZoomRectPan(int x, int y)
void x_SwithToActiveState(EState state, const wxPoint &ms_pos)
void x_OnChangePan(const wxPoint &ms_pos)
TModelPoint m_ptStart
void x_OnSelectCursor(const wxPoint &ms_pos)
void SetHost(IMinimapHandlerHost *pHost)
TModelUnit x_NormToScale(TModelUnit norm) const
CRgbaColor m_RectColor
CRgbaColor m_ScaleColor
void OnLeftUp(wxMouseEvent &event)
void OnLeftDown(wxMouseEvent &event)
IGlEventHandler implementation.
void OnKeyDown(wxKeyEvent &event)
void OnMouseWheel(wxMouseEvent &event)
void OnMouseCaptureLost(wxMouseCaptureLostEvent &evt)
TSubstate x_GetSubstate(const wxPoint &ms_pos)
virtual void SetPane(CGlPane *pane)
void OnMotion(wxMouseEvent &event)
void x_RenderMinimap(CGlPane &pane)
virtual ~CMinimapHandler()
I3DTexture * m_pTexture
void x_OnEndMinimap(EState new_state)
void Render(CGlPane &Pane)
TModelUnit m_StartNorm
IGenericHandlerHost * GetGenericHost()
CRgbaColor m_TickColor
TModelUnit x_ScaleToNorm(TModelUnit scale) const
virtual wxEvtHandler * GetEvtHandler()
void x_SwitchToReadyState(EState new_state, const wxPoint &ms_pos)
signal handlers - functions doing the real job
IGenericHandlerHost.
virtual void GHH_ReleaseMouse()=0
releases captured mouse
virtual void GHH_Redraw()=0
redraws the Host and the handler
virtual void GHH_CaptureMouse()=0
captures mouse events in the hosting window for D&D
Interface IMinimapHandlerHost represents a context in which CMinimapHandler functions.
virtual I3DTexture * MMHH_GetTexture(float &, float &)
gets a texture and its coordinate limits for the minmap
@ eCurrent
minimal scale
virtual TModelUnit MMHH_GetScale(EMMScaleType type)=0
virtual TVPUnit MMHH_GetVPPosByY(int y) const =0
converts window coord to Viewport coord
virtual void MMHH_Scroll(TModelUnit d_x, TModelUnit d_y)=0
virtual void MMHH_EndOp()=0
#define NULL
Definition: ncbistd.hpp:225
GLdouble TModelUnit
Definition: gltypes.hpp:48
virtual void TexCoord2f(GLfloat s, GLfloat t)=0
Colors (also defined in IGlState since they can be set either before or inside of Begin()/End().
T Height() const
Definition: glrect.hpp:90
virtual void Enable(GLenum glstate)=0
void Init()
Definition: glrect.hpp:62
virtual void Begin(GLenum mode)=0
Start rendering.
T Top() const
Definition: glrect.hpp:84
virtual void BlendFunc(GLenum sfactor, GLenum dfactor)=0
Options to be used when GL_BLEND is enabled.
T Bottom() const
Definition: glrect.hpp:82
TModelPoint UnProject(TVPUnit m_x, TVPUnit m_y) const
Definition: glpane.cpp:738
T Width() const
Definition: glrect.hpp:86
bool OpenPixels()
Definition: glpane.hpp:432
IRender & GetGl()
convenience function for getting current render manager
void Vertex2d(GLdouble x, GLdouble y)
Definition: irender.hpp:185
T Right() const
Definition: glrect.hpp:83
TVPRect & GetViewport(void)
Definition: glpane.hpp:332
TModelUnit UnProjectX(TVPUnit m_x) const
Definition: glpane.cpp:706
TModelRect & GetModelLimitsRect(void)
Definition: glpane.hpp:347
T Left() const
Definition: glrect.hpp:81
virtual void End()=0
Finish rendering (create buffer and send to renderer)
static bool CheckGlError()
Check if there are any OpenGL errors.
Definition: glutils.cpp:166
void Close(void)
Definition: glpane.cpp:178
TModelUnit UnProjectY(TVPUnit m_y) const
Definition: glpane.cpp:722
virtual void MakeCurrent()=0
TModelRect & GetVisibleRect(void)
Definition: glpane.hpp:357
virtual void Disable(GLenum glstate)=0
glDisable()
virtual void LineWidth(GLfloat w)=0
Set line width for drawing: glLineWidth()
virtual void ColorC(const CRgbaColor &c)=0
Set current color (glColor{3,4}{f,d}{v,})
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
END_EVENT_TABLE()
static int kGaugeMaxDim
bool sIsMiniMapMode()
event handlers
static float kMinInnerRectDim
T max(T x_, T y_)
T min(T x_, T y_)
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
@ eIdle
#define _ASSERT
Modified on Sat Dec 02 09:24:16 2023 by modify_doxy.py rev. 669887