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

Go to the SVN repository for this file.

1 /* $Id: seqmark_handler.cpp 46231 2021-02-10 20:39:54Z evgeniev $
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: Vlad Lebedev
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
34 
37 #include <gui/opengl/glhelpers.hpp>
38 #include <gui/opengl/irender.hpp>
39 
40 #include <math.h>
41 
42 
44 
45 
46 const int kMarkerSize = 6;
47 ////////////////////////////////////////////////////////////////////////////////
48 /// class CSeqMarkHandler
49 BEGIN_EVENT_TABLE(CSeqMarkHandler, wxEvtHandler)
50  EVT_LEFT_DOWN(CSeqMarkHandler::OnLeftDown)
51  EVT_LEFT_DCLICK(CSeqMarkHandler::OnLeftDoubleClick)
52  EVT_LEFT_UP(CSeqMarkHandler::OnLeftUp)
53  EVT_MOTION(CSeqMarkHandler::OnMotion)
54  EVT_MOUSE_CAPTURE_LOST(CSeqMarkHandler::OnMouseCaptureLost)
56 
57 
59  : m_Host(NULL)
60  , m_MarkerType(ePoint)
61  , m_MarkDrag(false)
62  , m_ShowCoord(true)
63  , m_DragPos(-1.0)
64  , m_ExtendedPos(-1.0)
65  , m_PosOff(0.0)
66  , m_Font_Helv10(CGlTextureFont::eFontFace_Helvetica, 10)
67  , m_LabelFont(CGlTextureFont::eFontFace_Helvetica, 10)
68  , m_Color(1.0f, 0.0f, 0.0f, 0.3f)
69  , m_HitMe(false)
70  , m_Flipped(false)
71 {
72 }
73 
74 
76 {
77 }
78 
79 
81 {
82  m_Pane = pane;
83 }
84 
85 
87 {
88  return this;
89 }
90 
91 
93 {
94  m_Host = host;
95 }
96 
97 
99 {
100  return dynamic_cast<IGenericHandlerHost*>(m_Host);
101 }
102 
104 {
105  m_MarkerType = t;
106 }
107 
108 void CSeqMarkHandler::SetFlipped(bool flipped)
109 {
110  m_Flipped = flipped;
111 }
112 
114 {
115  // When it's a range marker, maintain m_DragPos as the smaller value
116  // (unless m_ExtendedPos is uninitialized).
117  if (m_MarkerType == eRange &&
118  m_ExtendedPos >= 0.0f &&
119  pos > m_ExtendedPos) {
121  m_ExtendedPos = pos;
122  }
123  else {
124  m_DragPos = (int)pos;
125  }
126 }
127 
129 {
130  if (m_MarkerType == ePoint)
131  return m_DragPos;
132 
133  if (!m_Flipped)
134  return m_DragPos;
135  else
136  return m_ExtendedPos;
137 }
138 
140 {
141  // When it's a range marker, maintain m_DragPos as the smaller value
142  if (m_MarkerType == eRange &&
143  m_DragPos > pos) {
145  m_DragPos = pos;
146  }
147  else {
148  m_ExtendedPos = (int)pos;
149  }
150 }
151 
153 {
154  m_DragPos = range.GetFrom();
155  m_ExtendedPos = range.GetTo();
156 
157  if (m_ExtendedPos < m_DragPos)
159 }
160 
162 {
163  // Only applies to range markers
164  if (!m_Flipped)
165  return m_ExtendedPos;
166  else
167  return m_DragPos;
168 }
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 // event handlers
172 
173 void CSeqMarkHandler::OnLeftDown(wxMouseEvent& event)
174 {
175  _ASSERT(m_Pane);
176 
178  m_PosOff = 0.0;
180  wxPoint pos = event.GetPosition();
181  TModelUnit x_pos = m_Host->SMHH_GetModelByWindow(pos.x, eHorz);
182  TModelUnit y_pos = m_Host->SMHH_GetModelByWindow(pos.y, eVert);
183 
184  TModelPoint click_point = TModelPoint(x_pos, y_pos);
186 
187  if (rc.PtInRect(click_point) ) {
188  m_MarkDrag = true;
189  TSeqPos pos = m_Host->SMHH_GetSeqMark();
190  if (pos != (TSeqPos)(-1)) {
191  SetPos((TModelUnit)pos);
192  }
193  m_PosOff = GetPosLeft() - x_pos;
196  return;
197  }
198  }
199  event.Skip();
200 }
201 
202 
203 void CSeqMarkHandler::OnLeftDoubleClick(wxMouseEvent& event)
204 {
206 
208  wxPoint pos = event.GetPosition();
209  TModelUnit x_pos = m_Host->SMHH_GetModelByWindow(pos.x, eHorz);
210  TModelUnit y_pos = m_Host->SMHH_GetModelByWindow(pos.y, eVert);
211 
212  TModelPoint click_point = TModelPoint(x_pos, y_pos);
214 
215  if (rc.PtInRect(click_point) ) {
216  m_MarkDrag = false;
217  SetPos(0);
218  m_Host->SMHH_SetSeqMark(0); // reset to 0
221  return;
222  }
223  }
224  event.Skip();
225 }
226 
228 {
229  TModelRect rc = pane.GetVisibleRect();
230  TModelUnit half_x = pane.UnProjectWidth(kMarkerSize);
231  TModelUnit half_y = pane.UnProjectHeight(kMarkerSize);
232  TModelUnit pos = GetPosLeft();
233  TSeqPos marker_pos = m_Host->SMHH_GetSeqMark();
234  if (marker_pos != (TSeqPos)(-1)) {
235  pos = (TModelUnit)marker_pos;
236  }
237 
238  if (m_Flipped)
239  pos += 1.0;
240 
241  IRender& gl = GetGl();
242  TModelUnit l_w = gl.TextWidth(&m_LabelFont, m_Label.c_str()) + kMarkerSize;
243  TModelRect res;
244  l_w = pane.UnProjectWidth(l_w);
245  res = TModelRect(pos - half_x, rc.Top() - half_y * 2,
246  pos + half_x + l_w, rc.Top());
247 
248  return res;
249 }
250 
251 
252 void CSeqMarkHandler::OnMotion(wxMouseEvent& event)
253 {
254  m_HitMe = false;
255  if(event.Dragging()) {
256  if (m_MarkDrag) {
257  wxPoint ms_pos = event.GetPosition();
258  TModelUnit prev_pos = GetPosLeft();
259  TModelUnit new_pos = 0.0;
260 
261  // Don't let mouse drag marker outside of viewport
262  // (but in a range marker, it could be partly outside)
263  GLint vp[4];
264  glGetIntegerv(GL_VIEWPORT, vp);
265  if (ms_pos.x < vp[0])
266  ms_pos.x = vp[0];
267  else if (ms_pos.x > vp[0] + vp[2])
268  ms_pos.x = vp[0] + vp[2];
269 
270  new_pos = m_PosOff + m_Host->SMHH_GetModelByWindow(ms_pos.x, eHorz);
271 
272  // Move both endpoints of range markers
273  if (m_MarkerType == eRange) {
274  TModelUnit delta = new_pos - prev_pos;
275 
276  if (!m_Flipped) {
277  m_DragPos = new_pos;
278  m_ExtendedPos += delta;
279  }
280  else {
281  m_ExtendedPos = new_pos;
282  m_DragPos += delta;
283  }
284 
285  }
286  else {
287  m_DragPos = new_pos;
288  }
290  }
291  // always handle drags
292  } else {
293  wxPoint pos = event.GetPosition();
294  TModelUnit x_pos = m_Host->SMHH_GetModelByWindow(pos.x, eHorz);
295  TModelUnit y_pos = m_Host->SMHH_GetModelByWindow(pos.y, eVert);
296 
297  TModelPoint click_point = TModelPoint(x_pos, y_pos);
299 
300  if ( rc.PtInRect(click_point) ) {
301  m_HitMe = true;
302  }
303 
304  event.Skip();
305  }
306 }
307 
308 
309 void CSeqMarkHandler::OnLeftUp(wxMouseEvent& event)
310 {
311  if (m_MarkDrag) {
312  x_OnEndAction();
313  }
314 }
315 
316 void CSeqMarkHandler::OnMouseCaptureLost(wxMouseCaptureLostEvent& evt)
317 {
318  if (m_MarkDrag) {
319  x_OnEndAction();
320  }
321 }
322 
324 {
325  m_MarkDrag = false;
326  if (m_MarkerType == eRange)
327  m_ExtendedPos = floor(m_ExtendedPos < 0 ? 0 : m_ExtendedPos + 0.5);
328 
333 }
334 
335 ////////////////////////////////////////////////////////////////////////////////
336 /// helper functions
337 
339 {
340  // round position to nearest integer coordinate
341  return (TSeqPos) floor(m_DragPos < 0 ? 0 : m_DragPos+0.5);
342 }
343 
344 
346 {
347  IRender& gl = GetGl();
348 
349  gl.Begin(GL_TRIANGLE_STRIP);
350 
351  double incr = M_PI / 10;
352 
353  gl.Vertex2d(x_c, y_c - half);
354  gl.Vertex2d(x_c, y_c + half);
355 
356  double a = M_PI / 2 + incr;
357  for (int i = 0; i < 4; ++i) {
358  float sina = half*sin(a), cosa = half*cos(a);
359  gl.Vertex2d(x_c + cosa, y_c - sina);
360  gl.Vertex2d(x_c + cosa, y_c + sina);
361  a += incr;
362  }
363 
364  gl.Vertex2d(x_c - half, y_c);
365 
366  gl.End();
367 }
368 
370 {
371  IRender& gl = GetGl();
372  TModelUnit w = gl.TextWidth(&m_LabelFont, m_Label.c_str()) + kMarkerSize;
373  TModelUnit h = gl.TextHeight(&m_LabelFont) + 1.0;
374 
375  gl.Rectd(x, y-half, x+w, y+half);
376 
377  if (!m_Label.empty()) {
378  y = y - (h / 2) + 1;
379  x += 2.0;
380 
381  gl.Color4f(1.0f, 1.0f, 1.0f, 1.0f);
382  gl.BeginText(&m_LabelFont);
383  gl.WriteText(x, y, m_Label.c_str());
384  gl.EndText();
385  }
386 }
387 
388 
390 {
391  double height{ 0.0 };
392  Render(pane, option, height);
393 }
394 
395 
397 {
398  CGlAttrGuard AttrGuard(GL_ENABLE_BIT | GL_POLYGON_BIT | GL_HINT_BIT);
399  CGlPaneGuard GUARD(pane, CGlPane::ePixels);
400 
401  const TVPRect& rcV = pane.GetViewport();
402  IRender& gl = GetGl();
403 
404  TModelUnit pos = GetPosLeft();
405  TModelUnit end_pos = GetPosRight();
406  if (m_MarkerType == ePoint)
407  end_pos = pos;
408 
409  /// I think this is not used (at lest not with seqgraphic_pane)
410  if ( !m_DragPos ) {
411  TSeqPos marker_pos = m_Host->SMHH_GetSeqMark();
412  if (marker_pos != (TSeqPos)(-1)) {
413  pos = (TModelUnit)marker_pos + 0.5;
414  }
415  }
416 
417  TModelPoint p;
418  string text_out = x_GetText(TSeqPos(pos + 1.0));
419 
420  TModelUnit width = gl.TextWidth(&m_Font_Helv10, text_out.c_str()) + kMarkerSize;
421  TModelUnit off = option == ePassiveState ? 0 : kMarkerSize * 1.6;
422 
423  m_Color.SetAlpha(0.3f);
424  gl.ColorC(m_Color);
425  gl.PolygonMode(GL_FRONT_AND_BACK, GL_FILL);
426  gl.Enable(GL_BLEND);
427  gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
428 
429  // draw the markers so that they include the base-pair characters
430  // so we draw the first marker at the position and the end is
431  // set to the last position + 1
432  TModelUnit cur_pos;
433  TModelUnit cur_end_pos;
434  TModelUnit text_pos;
435 
436  if (m_Flipped) {
437  cur_pos = pane.ProjectX(pos + 1.0);
438  cur_end_pos = pane.ProjectX(end_pos);
439  }
440  else {
441  cur_pos = pane.ProjectX(pos);
442  cur_end_pos = pane.ProjectX(end_pos + 1.0);
443  }
444  text_pos = cur_pos;
445 
446  double top = rcV.Top() - off;
447  double bottom = (height > 0.0) ? rcV.Top() - off - height : rcV.Bottom();
448  if (bottom < rcV.Bottom()) {
449  height -= rcV.Bottom() - bottom;
450  bottom = rcV.Bottom();
451  }
452  else {
453  height = 0.0;
454  }
455 
456  m_Color.SetAlpha(0.2f);
457  gl.ColorC(m_Color);
458  gl.Rectd(cur_pos, top, cur_end_pos, bottom - 1);
459 
460  m_Color.SetAlpha(0.4f);
461  gl.ColorC(m_Color);
462 
463  gl.Begin(GL_LINES); // make lines at edges a little darker
464  gl.Vertex2d(cur_pos, bottom);
465  gl.Vertex2d(cur_pos, top);
466  gl.Vertex2d(cur_end_pos, bottom);
467  gl.Vertex2d(cur_end_pos, top);
468  gl.End();
469 
470  if (option == ePassiveState && m_ShowCoord) { // show current position
471  // Want to keep text glyph on left-hand side of marker always
472  text_pos -= width / 2.0;
473  if (text_pos < 1.0)
474  text_pos = 1.0;
475 
476  m_Color.SetAlpha(1.0f);
477  gl.ColorC(m_Color);
479  gl.WriteText(text_pos, rcV.Bottom() + 2, text_out.c_str());
480  gl.EndText();
481  }
482  p = TModelPoint(cur_pos, rcV.Top() - kMarkerSize - 1);
483 
484 
485  // Active State (pane)
486  if(option == eActiveState) { // Draw mark texture
487  m_Color.SetAlpha(1.0f);
488  gl.ColorC(m_Color);
489  x_DrawMarker(p.X(), p.Y(), kMarkerSize);
490 
491  m_Color.SetAlpha(0.6f);
492  gl.ColorC(m_Color);
493  x_DrawLabel(p.X(), p.Y(), kMarkerSize);
494  } // option == eActiveState
495 }
496 
498 {
499  return NStr::SizetToString( (unsigned long) pos, NStr::fWithCommas);
500 }
501 
502 
503 
static EGUIState wxGetSelectState(const wxMouseEvent &event)
Definition: gui_event.cpp:42
CGlAttrGuard - guard class for restoring OpenGL attributes.
Definition: glutils.hpp:130
class CGlPane
Definition: glpane.hpp:62
Class CSeqMarkHandler represents in GUI a single "hairpin" on a sequence bar.
void x_DrawMarker(TModelUnit x_c, TModelUnit y_c, int half) const
void OnMouseCaptureLost(wxMouseCaptureLostEvent &evt)
EMarkerType m_MarkerType
void OnLeftDown(wxMouseEvent &event)
TModelUnit m_PosOff
offset between mouse position and marker position
TModelRect x_GetMarkRect(CGlPane &pane) const
CGlTextureFont m_Font_Helv10
virtual void SetPane(CGlPane *pane)
void SetMarkerType(EMarkerType t)
void Render(CGlPane &Pane, ERenderingOption option)
string m_Label
label shown beside the marker (optional).
IGenericHandlerHost * GetGenericHost()
const string & GetId() const
bool m_MarkDrag
For draging the mark.
TModelUnit m_ExtendedPos
Second position, for range markers.
CGlTextureFont m_LabelFont
TSeqPos x_SeqDragPos() const
helper functions
void OnMotion(wxMouseEvent &event)
virtual ~CSeqMarkHandler()
void SetRange(TSeqRange range)
bool m_Flipped
True if strands are flipped.
TSeqPos GetPos() const
virtual wxEvtHandler * GetEvtHandler()
TModelUnit GetPosLeft() const
Return positions based on whether sequence is flipped.
void x_DrawLabel(TModelUnit x, TModelUnit y, int half) const
ISeqMarkHandlerHost * m_Host
virtual string x_GetText(TSeqPos pos)
void SetPos(TModelUnit pos)
bool m_ShowCoord
show coordinate
TModelUnit GetPosRight() const
void SetHost(ISeqMarkHandlerHost *pHost)
TModelUnit m_DragPos
marker position
void SetFlipped(bool flipped)
void OnLeftUp(wxMouseEvent &event)
void SetExtendedPos(TModelUnit pos)
void OnLeftDoubleClick(wxMouseEvent &event)
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
class ISeqMarkHandlerHost
virtual void SMHH_OnReset(const string &marker_id)=0
The derived class may need to do something differently when a marker gets reset, such as remove the m...
virtual TSeqPos SMHH_GetSeqMark() const =0
If the host needs to dictate/store the marker position, then it needs to return a non (TSeqPos)-1 val...
virtual void SMHH_SetSeqMark(TSeqPos mark)=0
The derived class may choose do something differently when marker position is changed.
virtual TModelUnit SMHH_GetModelByWindow(int z, EOrientation orient)=0
#define true
Definition: bool.h:35
#define false
Definition: bool.h:36
#define option
unsigned int TSeqPos
Type for sequence locations and lengths.
Definition: ncbimisc.hpp:875
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
Definition: ncbimisc.hpp:1508
#define NULL
Definition: ncbistd.hpp:225
GLdouble TModelUnit
Definition: gltypes.hpp:48
T X() const
Definition: glpoint.hpp:59
virtual void Enable(GLenum glstate)=0
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
TModelUnit UnProjectWidth(TVPUnit vp_w) const
Definition: glpane.cpp:755
TVPUnit ProjectX(TModelUnit m_x) const
Definition: glpane.cpp:661
IRender & GetGl()
convenience function for getting current render manager
void Vertex2d(GLdouble x, GLdouble y)
Definition: irender.hpp:185
TVPRect & GetViewport(void)
Definition: glpane.hpp:332
virtual TModelUnit TextHeight(const CGlTextureFont *font) const =0
virtual void BeginText(const CGlTextureFont *font, const CRgbaColor &color)=0
Text is drawn is pixel coordinates.
virtual TModelUnit TextWidth(const CGlTextureFont *font, const char *text) const =0
virtual void EndText()=0
Pops matrices and attributes after writing text.
T Y() const
Definition: glpoint.hpp:60
bool PtInRect(T x, T y) const
Definition: glrect.hpp:154
virtual void End()=0
Finish rendering (create buffer and send to renderer)
virtual void PolygonMode(GLenum face, GLenum mode)=0
Set the polygon rasterization mode.
TModelUnit UnProjectHeight(TVPUnit vp_h) const
Definition: glpane.cpp:768
void Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
Definition: irender.hpp:97
virtual void WriteText(TModelUnit x, TModelUnit y, const char *text, TModelUnit rotate_degrees=0.0)=0
Write text at specified model coords.
TModelRect & GetVisibleRect(void)
Definition: glpane.hpp:357
CGlRect< TModelUnit > TModelRect
Definition: gltypes.hpp:54
CGlPoint< TModelUnit > TModelPoint
Definition: gltypes.hpp:51
virtual void ColorC(const CRgbaColor &c)=0
Set current color (glColor{3,4}{f,d}{v,})
void Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
Definition: irender.hpp:193
@ ePixels
Definition: glpane.hpp:67
@ eHorz
Definition: gltypes.hpp:59
@ eVert
Definition: gltypes.hpp:60
void SetAlpha(float r)
Definition: rgba_color.cpp:287
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static string SizetToString(size_t value, TNumToStringFlags flags=0, int base=10)
Convert size_t to string.
Definition: ncbistr.cpp:2751
@ fWithCommas
Use commas as thousands separator.
Definition: ncbistr.hpp:254
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
END_EVENT_TABLE()
int i
range(_Ty, _Ty) -> range< _Ty >
unsigned int a
Definition: ncbi_localip.c:102
EIPRangeType t
Definition: ncbi_localip.c:101
Int4 delta(size_t dimension_, const Int4 *score_)
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
const int kMarkerSize
#define _ASSERT
Modified on Wed May 29 18:44:07 2024 by modify_doxy.py rev. 669887