linear_sel_handler.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:17k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: linear_sel_handler.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 21:10:38  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.11
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: linear_sel_handler.cpp,v 1000.2 2004/06/01 21:10:38 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Andrey Yazhuk
  35.  *
  36.  * File Description:
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbistd.hpp>
  41. #include <gui/widgets/gl/linear_sel_handler.hpp>
  42. #include <FL/Fl.H>
  43. #include <math.h>
  44. BEGIN_NCBI_SCOPE
  45. static int kDragThreshold = 4; // make this configurable
  46. ISelHandlerHost::~ISelHandlerHost()
  47. {
  48. }
  49. ////////////////////////////////////////////////////////////////////////////////
  50. /// class CLinearSelHandler
  51. CLinearSelHandler::CLinearSelHandler(EOrientation orient)
  52. :   m_Orientation(orient),
  53.     m_ExtState(eNoExt),
  54.     m_OpType(eNoOp),
  55.     m_bResizeCursor(false),
  56.     m_pHost(NULL),
  57.     m_SelColor(0.5f, 0.5f, 0.5f, 0.25f),
  58.     m_PassiveSelColor(0.6f, 0.6f, 0.6f, 0.25f),
  59.     m_SymbolColor(0.0f, 0.0f, 1.0f, 1.0f),
  60.     m_Font(CGlBitmapFont::eHelvetica24)
  61. {
  62. }
  63. CLinearSelHandler::~CLinearSelHandler()
  64. {
  65. }
  66. void    CLinearSelHandler::SetHost(ISelHandlerHost* pHost)
  67. {
  68.     m_pHost = pHost;
  69. }
  70. int CLinearSelHandler::handle(CGUIEvent& event, CGlPane& pane)
  71. {
  72.     m_pPane = &pane;
  73.     int res = 0;
  74.     switch(event.GetFLTKEvent())   {
  75.     case FL_PUSH: res =  x_OnMousePush(event, pane); break;
  76.     case FL_DRAG: res =  x_OnMouseDrag(event, pane); break;
  77.     case FL_RELEASE: res = x_OnMouseRelease(event, pane); break;
  78.     case FL_MOVE: res = x_OnMouseMove(event, pane); break;
  79.     case FL_KEYDOWN: res = x_OnKeyDown(event); break;
  80.     case FL_KEYUP: res = x_OnKeyUp(event); break;
  81.     }
  82.     m_pPane = 0;
  83.     return res;
  84. }
  85. TSeqRange  CLinearSelHandler::GetSelectionLimits()    const
  86. {
  87.     return m_Selection.GetLimits();
  88. }
  89. const   CLinearSelHandler::TRangeColl&   CLinearSelHandler::GetSelection() const
  90. {
  91.     return m_Selection;
  92. }
  93. void    CLinearSelHandler::SetSelection(const TRangeColl& C, bool b_redraw)
  94. {
  95.     m_Selection = C;
  96.     if(b_redraw)
  97.         m_pHost->SHH_Redraw();
  98. }
  99. void    CLinearSelHandler::ResetSelection(bool b_redraw)
  100. {
  101.     m_Selection.clear();
  102.     if(b_redraw)
  103.         m_pHost->SHH_Redraw();
  104. }
  105. void    CLinearSelHandler::SetColor(EColorType type, const CGlColor& color)
  106. {
  107.     switch(type)    {
  108.     case eSelection: m_SelColor = color; break;
  109.     case ePasssiveSelection: m_PassiveSelColor = color; break;
  110.     case eSymbol: m_SymbolColor = color; break;
  111.     default: _ASSERT(false);
  112.     }
  113. }
  114. ////////////////////////////////////////////////////////////////////////////////
  115. // event handlers
  116. int CLinearSelHandler::x_OnMousePush(CGUIEvent& event, CGlPane& pane)
  117. {    
  118.     CGUIEvent::EGUIState state = event.GetGUIState();
  119.     if((state == CGUIEvent::eSelectState || state == CGUIEvent::eSelectAltState)
  120.         &&  event.GetGUISignal() == CGUIEvent::eSelectSignal)   {
  121.     
  122.         if(Fl::event_clicks() == 0) {
  123.             x_OnStartSel(event);
  124.             x_OnSelectCursor();
  125.         } else {                // doubleclick
  126.             x_OnResetAll();            
  127.         }                
  128.         return 1;
  129.     }
  130.     return 0;
  131. }
  132. int CLinearSelHandler::x_OnMouseDrag(CGUIEvent& event, CGlPane& pane)
  133. {
  134.     CGUIEvent::EGUIState state = event.GetGUIState();
  135.     if(m_OpType != eNoOp  &&
  136.       (state == CGUIEvent::eSelectState || state == CGUIEvent::eSelectAltState)) {
  137.         x_OnChangeSelRange();
  138.     }
  139.     return 1; // always handle drags
  140. }
  141. int CLinearSelHandler::x_OnMouseRelease(CGUIEvent& event, CGlPane& pane)
  142. {
  143.     CGUIEvent::EGUIState state = event.GetGUIState();
  144.     if(event.GetGUISignal() == CGUIEvent::eRelease  &&
  145.       (state == CGUIEvent::eSelectState || state == CGUIEvent::eSelectAltState)) {
  146.    
  147.         m_OpType = x_GetOpTypeByEvent(event);
  148.         x_OnChangeSelRange();
  149.         x_OnEndSelRange();
  150.         x_OnSelectCursor();
  151.         return 1;
  152.     }
  153.     return 0;
  154. }
  155. int CLinearSelHandler::x_OnMouseMove(CGUIEvent& event, CGlPane& pane)
  156. {
  157.     CGUIEvent::EGUIState state = event.GetGUIState();
  158.     x_OnSelectCursor();
  159.     if(state == CGUIEvent::eSelectState || state == CGUIEvent::eSelectAltState) {
  160.            return 1;
  161.     } else return 0;
  162. }
  163. int CLinearSelHandler::x_OnKeyDown(CGUIEvent& event)
  164. {
  165.     x_OnOpChange(event);
  166.     return 0;
  167. }
  168. int CLinearSelHandler::x_OnKeyUp(CGUIEvent& event)
  169. {
  170.     x_OnOpChange(event);
  171.     return 0;
  172. }
  173. ////////////////////////////////////////////////////////////////////////////////
  174. /// Signal handlers
  175. void    CLinearSelHandler::x_OnStartSel(CGUIEvent& event)
  176. {    
  177.     TSeqRange HitR;
  178.     bool b_hit_start = false;
  179.     x_HitTest(HitR, b_hit_start);
  180.     
  181.     if(HitR.NotEmpty()) {   // hit a border of the selected range
  182.         m_OpType = eChange;
  183.         m_ExtState = b_hit_start ? eExtRangeStart : eExtRangeEnd;
  184.         m_CurrRange = HitR;
  185.         x_RemoveFromSelection(HitR);
  186.     } else {        
  187.         m_ExtState = eExtRangeEnd;    
  188.         m_OpType = x_GetOpTypeByEvent(event);
  189.         TModelUnit m_Z = x_MouseToSeqPos();
  190.         TSeqPos pos = (TSeqPos) floor(m_Z);
  191.         m_CurrRange.SetFrom(pos);
  192.         m_CurrRange.SetToOpen(pos);            
  193.     }
  194.     m_pHost->SHH_Redraw();
  195. }
  196. void CLinearSelHandler::x_OnChangeSelRange()
  197. {
  198.     TModelUnit m_Z = x_MouseToSeqPos();
  199.     TSeqPos pos = (TSeqPos) floor(m_Z);
  200.     pos = x_ClipPosByRange(pos);
  201.     TSeqRange old_r = m_CurrRange;
  202.     if(m_ExtState == eNoExt  &&  pos != m_CurrRange.GetFrom())   {
  203.         if(pos > m_CurrRange.GetFrom()) {
  204.             m_CurrRange.SetToOpen(pos);
  205.             m_ExtState = eExtRangeEnd;
  206.         } else  {
  207.             m_CurrRange.SetToOpen(m_CurrRange.GetFrom());
  208.             m_CurrRange.SetFrom(pos);
  209.             m_ExtState = eExtRangeStart;
  210.         }
  211.     } else if(m_ExtState == eExtRangeEnd &&  pos != m_CurrRange.GetToOpen()) {
  212.         if(pos > m_CurrRange.GetFrom())  { 
  213.             m_CurrRange.SetToOpen(pos);
  214.         } else { //flip
  215.             m_CurrRange.SetToOpen(m_CurrRange.GetFrom());
  216.             m_CurrRange.SetFrom(pos);
  217.             m_ExtState = eExtRangeStart;
  218.         }
  219.     } else if(m_ExtState == eExtRangeStart  &&  pos != m_CurrRange.GetFrom())    {
  220.         if(pos <= m_CurrRange.GetToOpen())  { 
  221.             m_CurrRange.SetFrom(pos);
  222.         } else {
  223.             m_CurrRange.SetFrom(m_CurrRange.GetToOpen());
  224.             m_CurrRange.SetToOpen(pos);
  225.             m_ExtState = eExtRangeEnd;
  226.         }
  227.     }; 
  228.    
  229.     if(m_CurrRange != old_r)
  230.         m_pHost->SHH_Redraw();
  231. }
  232. void    CLinearSelHandler::x_OnEndSelRange()
  233. {
  234.     if(! m_CurrRange.Empty())   {
  235.         switch(m_OpType)   {
  236.         case eAdd: 
  237.         case eChange:   x_AddToSelection(m_CurrRange); break;
  238.         case eRemove:   x_RemoveFromSelection(m_CurrRange); break;
  239.         case eNoOp: break;
  240.         }
  241.     }
  242.     m_CurrRange.SetLength(0);
  243.     
  244.     m_ExtState = eNoExt;
  245.     m_OpType = eNoOp;
  246.     
  247.     m_pHost->SHH_Redraw();    
  248. }
  249. void    CLinearSelHandler::x_OnResetAll()
  250. {
  251.     bool b_update = ! m_Selection.empty();
  252.     m_Selection.clear();
  253.     m_ExtState = eNoExt;
  254.     m_OpType = eNoOp;
  255.     if(b_update)
  256.         m_pHost->SHH_Redraw();
  257. }
  258. void    CLinearSelHandler::x_OnOpChange(CGUIEvent& event)
  259. {
  260.    if(m_ExtState != eNoExt)   {
  261.         EOpType NewType = x_GetOpTypeByEvent(event);
  262.         
  263.         if(NewType != m_OpType) {
  264.             m_OpType = NewType;
  265.             x_OnSelectCursor();
  266.             m_pHost->SHH_Redraw();
  267.         }
  268.     } 
  269. }
  270. void    CLinearSelHandler::x_OnSelectCursor()
  271. {
  272.     switch(m_OpType)    {
  273.     case eNoOp:   {
  274.         TSeqRange HitR;
  275.         bool b_hit_start = false;
  276.         x_HitTest(HitR, b_hit_start);
  277.     
  278.         m_bResizeCursor = HitR.NotEmpty();
  279.     }; break;
  280.     case eAdd: 
  281.     case eRemove:
  282.     case eChange:   m_bResizeCursor = true; break;
  283.     }   
  284.     x_SetCursor();
  285. }
  286. void    CLinearSelHandler::x_SetCursor()
  287. {
  288.     Fl_Cursor Cur = FL_CURSOR_DEFAULT;
  289.     if(m_bResizeCursor) {
  290.         Cur = (m_Orientation == eHorz) ? FL_CURSOR_WE : FL_CURSOR_NS; 
  291.     } 
  292.     fl_cursor(Cur, FL_BLACK, FL_WHITE);
  293. }
  294. ////////////////////////////////////////////////////////////////////////////////
  295. /// helper functions
  296. // translate modificators to operation type
  297. CLinearSelHandler::EOpType CLinearSelHandler::x_GetOpTypeByEvent(CGUIEvent& event)    const
  298. {
  299.     switch(event.GetGUIState())    {
  300.     case CGUIEvent::eSelectState: return eAdd;
  301.     case CGUIEvent::eSelectAltState:    return eRemove;
  302.     default:    return eNoOp;
  303.     }
  304. }
  305. TModelUnit CLinearSelHandler::x_MouseToSeqPos()
  306. {
  307.     _ASSERT(m_pPane);
  308.     int z = (m_Orientation == eHorz) ? Fl::event_x() : Fl::event_y();
  309.     return m_pHost->SHH_GetModelByWindow(z, m_Orientation) + 0.5;
  310. }
  311. void    CLinearSelHandler::x_HitTest(TSeqRange& range, bool& b_hit_start)
  312. {
  313.     _ASSERT(m_pPane);
  314.     int z = (m_Orientation == eHorz) ? Fl::event_x() : Fl::event_y();
  315.     
  316.     int min_D = -1;
  317.     bool b_min_start = false;
  318.     const TSeqRange* p_min_range = 0;
  319.     const TRangeColl& C = m_Selection;
  320.     ITERATE(TRangeColl, it, C)  {
  321.         const TSeqRange& R = *it;
  322.         int from_Z = m_pHost->SHH_GetWindowByModel(R.GetFrom(), m_Orientation);
  323.         int to_Z = m_pHost->SHH_GetWindowByModel(R.GetToOpen(), m_Orientation);
  324.         int D = abs(z - from_Z);
  325.         if(min_D < 0 || min_D > D)    {
  326.             min_D = D;
  327.             b_min_start = true;
  328.             p_min_range = &R;
  329.         }
  330.         D = abs(z - to_Z);
  331.         if(min_D > D)    {
  332.             min_D = D;
  333.             b_min_start = false;
  334.             p_min_range = &R;
  335.         }        
  336.     }
  337.     if(min_D > -1  && min_D <= kDragThreshold) {
  338.         b_hit_start = b_min_start;
  339.         _ASSERT(p_min_range);
  340.         range  = *p_min_range;
  341.     } else range.SetLength(0);
  342. }
  343. TSeqPos CLinearSelHandler::x_ClipPosByRange(TSeqPos pos)
  344. {
  345.     bool b_horz = (m_Orientation == eHorz);
  346.     TModelRect rc_lim = m_pPane->GetModelLimitsRect();
  347.     pos = max(pos, (TSeqPos) (b_horz ? rc_lim.Left() : rc_lim.Bottom()));
  348.     pos = min(pos, (TSeqPos) (b_horz ? rc_lim.Right() : rc_lim.Top()));    
  349.     return pos;
  350. }
  351. void    CLinearSelHandler::x_AddToSelection(const TSeqRange& range)
  352. {
  353.     m_Selection.CombineWith(range);
  354. }
  355. void    CLinearSelHandler::x_RemoveFromSelection(const TSeqRange& range)
  356. {
  357.     m_Selection.Subtract(range);
  358. }
  359. void    CLinearSelHandler::Render(CGlPane& pane, ERenderingOption option)
  360. {
  361.     TModelRect rc_vis = pane.GetVisibleRect();
  362.     
  363.     if(! rc_vis.IsEmpty()) {    
  364.         pane.OpenOrtho();
  365.         
  366.         TModelUnit offset_x = pane.GetOffsetX();
  367.         TModelUnit offset_y = pane.GetOffsetY();
  368.         bool b_horz = (m_Orientation == eHorz);
  369.         // draw exisiting selection
  370.         glColorC( (option == eActiveState) ? m_SelColor : m_PassiveSelColor);
  371.         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  372.         
  373.         const TRangeColl& C = m_Selection;
  374.         ITERATE(TRangeColl, it, C)  { // for every segment
  375.             const TSeqRange& r = *it;
  376.             switch(m_Orientation)   {
  377.             case eHorz: glRectd(r.GetFrom() - offset_x, rc_vis.Bottom() - offset_y, 
  378.                                 r.GetToOpen() - offset_x, rc_vis.Top() - offset_y); break;
  379.             case eVert: glRectd(rc_vis.Left() - offset_x, r.GetFrom() - offset_y, 
  380.                                 rc_vis.Right() - offset_x, r.GetToOpen() - offset_y); break;
  381.             }
  382.         }
  383.         
  384.         if(m_OpType != eNoOp)   { // draw current range
  385.             TModelRect rc_curr(rc_vis);
  386.             if(b_horz)  {
  387.                 rc_curr.SetLeft( max(rc_vis.Left(), (TModelUnit) m_CurrRange.GetFrom()) );
  388.                 rc_curr.SetRight( min(rc_vis.Right(), (TModelUnit) m_CurrRange.GetToOpen()) );
  389.             } else {
  390.                 rc_curr.SetBottom( max(rc_vis.Bottom(), (TModelUnit) m_CurrRange.GetFrom()) );
  391.                 rc_curr.SetTop( min(rc_vis.Top(), (TModelUnit) m_CurrRange.GetToOpen()) );
  392.             }
  393.             glRectd(rc_curr.Left() - offset_x, rc_curr.Top() - offset_y, 
  394.                     rc_curr.Right() - offset_x, rc_curr.Bottom() - offset_y);
  395.         
  396.             if(option == eActiveState)  {
  397.                 glColorC(m_SymbolColor); 
  398.                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  399.                 glRectd(rc_curr.Left() - offset_x, rc_curr.Bottom() - offset_y, 
  400.                         rc_curr.Right() - offset_x, rc_curr.Top() - offset_y);
  401.                 
  402.                 // drwaing Operation symbol
  403.                 const char* s = 0;
  404.                 switch(m_OpType)    {
  405.                 case eAdd: s = "+"; break;
  406.                 case eRemove: s = "-"; break;
  407.                 case eChange: s = "<->"; break;
  408.                 case eNoOp: break;
  409.                 }
  410.                         
  411.                 float w = m_Font.TextWidth(s) * pane.GetScaleX();
  412.                 float kY = pane.GetScaleY() < 0 ? -1.0f : 1.0f;
  413.                 float h = kY * m_Font.TextHeight() * pane.GetScaleY(); // make it positive
  414.             
  415.                 // if there is enougth space - draw operation symbol
  416.                 if(w < rc_curr.Width()  &&  h < fabs(rc_curr.Height()))   { 
  417.                     float x = (rc_curr.Left() + rc_curr.Right() - w) / 2 - offset_x;
  418.                     float y = (rc_curr.Bottom() + rc_curr.Top() - h) / 2 - offset_y;
  419.                     m_Font.TextOut(x, y, s);
  420.                 }
  421.             }
  422.         }
  423.         pane.Close();
  424.     }
  425. }
  426. END_NCBI_SCOPE
  427. /*
  428.  * ===========================================================================
  429.  * $Log: linear_sel_handler.cpp,v $
  430.  * Revision 1000.2  2004/06/01 21:10:38  gouriano
  431.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.11
  432.  *
  433.  * Revision 1.11  2004/05/21 22:27:54  gorelenk
  434.  * Added PCH ncbi_pch.hpp
  435.  *
  436.  * Revision 1.10  2004/04/06 16:07:58  yazhuk
  437.  * Clean-up
  438.  *
  439.  * Revision 1.9  2004/03/23 14:07:37  dicuccio
  440.  * Fixed compiler warnings
  441.  *
  442.  * Revision 1.8  2004/03/11 17:52:33  dicuccio
  443.  * Use TSeqRange instead of TRange
  444.  *
  445.  * Revision 1.7  2004/02/12 21:00:47  yazhuk
  446.  * Support of CGlPane "offset" mode
  447.  *
  448.  * Revision 1.6  2004/02/09 14:36:54  lebedev
  449.  * Restore glPolygonMode to default state after rendering
  450.  *
  451.  * Revision 1.5  2004/02/09 13:49:14  lebedev
  452.  * Added  methods for customizing selection colors
  453.  *
  454.  * Revision 1.4  2004/01/08 19:46:01  yazhuk
  455.  * Clean-up
  456.  *
  457.  * Revision 1.3  2003/12/05 17:51:04  yazhuk
  458.  * Fixed cursor selection for vertical orientation.
  459.  *
  460.  * Revision 1.2  2003/12/01 20:52:36  ucko
  461.  * Use fabs, not abs, for floating-point numbers.
  462.  *
  463.  * Revision 1.1  2003/12/01 16:33:19  yazhuk
  464.  * Former alnmulti_sel_handler.cpp moved to gui/widgets/gl
  465.  *
  466.  * Revision 1.12  2003/10/29 23:28:34  yazhuk
  467.  * Changed includes
  468.  *
  469.  * Revision 1.11  2003/10/20 15:51:58  yazhuk
  470.  * Changed keyboard events handling policy.
  471.  *
  472.  * Revision 1.10  2003/10/15 21:25:03  yazhuk
  473.  * Fixed "selection last position" bug. Eliminated excessive updates.
  474.  *
  475.  * Revision 1.9  2003/10/10 19:07:36  yazhuk
  476.  * Replaced glColor3fv with glColorC
  477.  *
  478.  * Revision 1.8  2003/10/08 14:17:25  dicuccio
  479.  * use glColor3fv instead of glColorC
  480.  *
  481.  * Revision 1.7  2003/09/29 17:00:09  dicuccio
  482.  * fl.H -> Fl.H
  483.  *
  484.  * Revision 1.6  2003/09/29 15:53:42  dicuccio
  485.  * Reordered #include statements
  486.  *
  487.  * Revision 1.5  2003/09/23 21:11:21  yazhuk
  488.  * Removed x_ModifiersOk() and x_ClipPosByRange() definitions
  489.  *
  490.  * Revision 1.4  2003/09/14 14:03:44  ucko
  491.  * #include <math.h> (needed with GCC)
  492.  *
  493.  * Revision 1.3  2003/09/10 20:44:21  yazhuk
  494.  * Improved drawing of the current range
  495.  *
  496.  * Revision 1.2  2003/09/08 20:49:42  yazhuk
  497.  * Added functions for manipulating with Selection
  498.  *
  499.  * Revision 1.1  2003/09/08 16:31:49  yazhuk
  500.  * Initial revision
  501.  *
  502.  * ===========================================================================
  503.  */