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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: splitter.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 21:09:10  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.7
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: splitter.cpp,v 1000.1 2004/06/01 21:09:10 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 <corelib/ncbistl.hpp>
  42. #include <algorithm>
  43. #include <gui/widgets/fl/splitter.hpp>
  44. #include <FL/fl_draw.H>
  45. #include <FL/Fl.H>
  46. BEGIN_NCBI_SCOPE
  47. CSplitter::CSplitter(int x, int y, int w, int h, const char* label)
  48.     : Fl_Group(x, y, w, h, label),
  49.     m_Mode(eHorizontal),
  50.     m_SepSize(4),
  51.     m_iDragSepX(-1), m_iDragSepY(-1)
  52. {
  53.     Fl_Group::end();
  54.     
  55.     color(fl_rgb_color(224, 224, 224));
  56.     box(FL_FLAT_BOX);
  57.     m_vCells.resize(1, NULL); // by default it has a single cell
  58.     m_vNormSizeX.resize(1, -1);
  59.     m_vNormSizeY.resize(1, -1);
  60.     m_Event.StandardConfig();
  61. }
  62. CSplitter::~CSplitter()
  63. {
  64. }
  65. CSplitter::EMode   CSplitter::GetMode()    const
  66. {
  67.     return m_Mode;
  68. }
  69. void    CSplitter::Create(EMode mode)
  70. {
  71.     if(m_Mode != mode)  {
  72.         x_Clear();
  73.         m_Mode = mode;
  74.     }
  75. }
  76. const static int    kMaxCells = 64;
  77. void    CSplitter::Create(EMode mode, const TPosVector& sizes)
  78. {
  79.     x_Clear();
  80.     switch(mode)  {
  81.     case    eHorizontal:  x_Create(mode, TPosVector(), sizes);    break;
  82.     case    eVertical:    x_Create(mode, sizes, TPosVector());    break;
  83.     case    eGrid:    x_Create(mode, sizes, sizes);    break;
  84.     };
  85. }
  86. void    CSplitter::Create(EMode mode, const int ar_size[])
  87. {
  88.     TPosVector sizes;
  89.     int  i = 0;
  90.     for(; i < kMaxCells; i++ )   {
  91.         if(ar_size[i] >= 0)
  92.             sizes.push_back(ar_size[i]);
  93.         else break;
  94.     }
  95.     _ASSERT(i < kMaxCells);
  96.     Create(mode, sizes);
  97. }
  98. void    CSplitter::Create(EMode mode, const TPosVector& widths, const TPosVector& heights)
  99. {
  100.     x_Create(mode, widths, heights);
  101. }
  102. void    CSplitter::Create(EMode mode, const int ar_w[], const int ar_h[])
  103. {
  104.     TPosVector widths;
  105.     int  i = 0;
  106.     for(; i < kMaxCells; i++ )   {
  107.         if(ar_w[i] >= 0)
  108.             widths.push_back(ar_w[i]);
  109.         else break;
  110.     }
  111.     _ASSERT(i < kMaxCells);
  112.     
  113.     TPosVector heights;
  114.     for( i = 0; i < kMaxCells; i++ )   {
  115.         if(ar_h[i] >= 0)
  116.             heights.push_back(ar_h[i]);
  117.         else break;
  118.     }
  119.     _ASSERT(i < kMaxCells);
  120.     x_Create(mode, widths, heights);
  121. }
  122. void    CSplitter::Create(int n_horz_panes, int n_vert_panes)
  123. {
  124.     vector<int> widths;
  125.     vector<int> heights;
  126.     
  127.     n_horz_panes = max(1, n_horz_panes);
  128.     n_vert_panes = max(1, n_vert_panes);
  129.     for( int i = 0; i < n_horz_panes; i++)
  130.         widths.push_back(10);
  131.     for( int i = 0; i < n_vert_panes; i++)
  132.         heights.push_back(10);
  133.     EMode mode = (n_horz_panes == 1) ? eVertical :
  134.                     ((n_vert_panes == 1) ? eHorizontal : eGrid);
  135.     x_Create(mode, widths, heights);
  136.     x_DistributeEvenly(true, true);
  137. }
  138. void    CSplitter::x_Create(EMode mode, const TPosVector& widths, const TPosVector& heights)
  139. {
  140.     m_Mode = mode;    
  141.     int n_w = widths.size(); 
  142.     int n_h = heights.size();
  143.     if(n_w == 0)    n_w++;
  144.     if(n_h == 0)    n_h++;
  145.     _ASSERT(n_w < kMaxCells  &&  n_h < kMaxCells); // keep 'em reasonable
  146.     x_Clear();    
  147.     
  148.     for( int pos = 0, i = 0; i < n_w - 1; i++)  {
  149.         pos += widths[i];
  150.         m_vSplitPosX.push_back(pos);
  151.     }
  152.     m_vNormSizeX.resize(n_w, -1);
  153.     
  154.     for( int pos = 0, i = 0; i < n_h - 1; i++)  {        
  155.         pos += heights[i];
  156.         m_vSplitPosY.push_back(pos);
  157.     }
  158.     m_vNormSizeY.resize(n_h, -1);
  159.     int n_cells = GetColumnsCount() * GetRowsCount();
  160.     m_vCells.resize(n_cells, NULL);
  161. }
  162. int     CSplitter::GetColumnsCount() const
  163. {
  164.     return m_vSplitPosX.size() + 1;
  165. }
  166. int     CSplitter::GetRowsCount() const
  167. {
  168.     return m_vSplitPosY.size() + 1;
  169. }
  170. bool    CSplitter::IsValidCell(int i_x, int i_y) const
  171. {
  172.     return i_x >= 0  &&  i_x <= (int) m_vSplitPosX.size()
  173.             &&  i_y >= 0  &&  i_y <= (int) m_vSplitPosY.size();
  174. }
  175. bool    CSplitter::InsertToCell(Fl_Widget* w, int i_x, int i_y)
  176. {
  177.     if(i_x >= 0  &&  i_x < GetColumnsCount()
  178.         && i_y >= 0  &&  i_y < GetRowsCount())   {
  179.         
  180.         int i_cell = x_GetCellIndex(i_x, i_y);
  181.         if(m_vCells[i_cell] == NULL) {// cell is  vacant
  182.             int ins_pos = 0; // insertion position
  183.             for( int i = 0;  i < i_cell; i++)   {
  184.                 if(m_vCells[i])
  185.                     ins_pos++;
  186.             }
  187.             w->hide();
  188.             
  189.             Fl_Group::insert(*w, ins_pos);
  190.             m_vCells[i_cell] = w;
  191.             x_ResizeToCell(i_x, i_y);
  192.             w->show();
  193.             return true;
  194.         }
  195.     }
  196.     return false;
  197. }    
  198. Fl_Widget*    CSplitter::RemoveFromCell(int i_x, int i_y)
  199. {
  200.     int i_cell = x_GetCellIndex(i_x, i_y);
  201.     Fl_Widget* w = m_vCells[i_cell];
  202.     if(w) {        
  203.         m_vCells[i_cell] = NULL;
  204.         Fl_Group::remove(w);        
  205.     }
  206.     redraw();
  207.     return w; 
  208. }
  209. bool    CSplitter::Remove(Fl_Widget* w)
  210. {
  211.     int i_x, i_y;
  212.     if(Find(w, i_x, i_y))    {
  213.         RemoveFromCell(i_x, i_y);
  214.         return true;
  215.     }
  216.     return false;
  217. }
  218. void    CSplitter::RemoveAll()
  219. {
  220.     for( size_t i = 0; i < m_vCells.size(); i++ )   {
  221.         Fl_Widget* w = m_vCells[i];
  222.         if(w) {        
  223.             m_vCells[i] = NULL;
  224.             Fl_Group::remove(w);        
  225.         }
  226.     }
  227.     redraw();
  228. }
  229. bool    CSplitter::Find(Fl_Widget* w, int& i_x, int& i_y)   const
  230. {
  231.     i_x = i_y = -1;
  232.     if(w)   {
  233.         for( int i = 0; i < (int) m_vCells.size();  i++ )   {
  234.             if(m_vCells[i] == w)    {
  235.                 i_x = x_GetColumn(i);
  236.                 i_y = x_GetRow(i);
  237.                 return true;
  238.             }
  239.         }
  240.     }
  241.     return false;
  242. }
  243. /// adds a child widget "w" to first vacant cell. If "w" already a child it is
  244. /// removed and added again to a new position. If there is no cells available
  245. /// new row/column is created
  246. void    CSplitter::add(Fl_Widget *widget)
  247. {
  248.     TCells::iterator it = std::find(m_vCells.begin(), m_vCells.end(), widget);
  249.     if(it != m_vCells.end())      { // already a child - remove
  250.         Fl_Group::remove(*widget);
  251.         *it = NULL;
  252.     }
  253.     
  254.     // look for first vacant cell 
  255.     it = std::find(m_vCells.begin(), m_vCells.end(), (Fl_Widget*) NULL);
  256.     if(it !=  m_vCells.end())   { // there is a vacant cell
  257.         int i_cell = it - m_vCells.begin();
  258.         Fl_Group::insert(*widget, i_cell);
  259.         m_vCells[i_cell] = widget;
  260.         int i_x = x_GetColumn(i_cell);
  261.         int i_y = x_GetRow(i_cell);
  262.         x_ResizeToCell(i_x, i_y);
  263.     } else  {
  264.         int old_n_cells = m_vCells.size();
  265.         if(m_Mode == eVertical) {
  266.             x_NewSplit(m_vSplitPosX, m_vNormSizeX, w());
  267.         }   else {
  268.             x_NewSplit(m_vSplitPosY, m_vNormSizeY, h());
  269.         }
  270.         Fl_Group::add(widget);
  271.         m_vCells.resize(GetRowsCount() * GetColumnsCount(), NULL);
  272.         m_vCells[old_n_cells] = widget; // old_n_cells specifies fisrt vacant position        
  273.         
  274.         for( int i = 0; i <= old_n_cells; i++   )   {
  275.             x_ResizeToCell(i);
  276.         }
  277.     }
  278. }
  279. void    CSplitter::add(Fl_Widget&  w)
  280. {
  281.     CSplitter::add(&w);
  282. }
  283. void    CSplitter::remove(Fl_Widget &w)
  284. {
  285.     TCells::iterator it = std::find(m_vCells.begin(), m_vCells.end(), &w);
  286.     if(it != m_vCells.end())    {
  287.         *it = NULL;
  288.         Fl_Group::remove(w);
  289.     }
  290. }
  291. void    CSplitter::draw()
  292. {
  293.     fl_push_clip(x(), y(), w(), h());
  294.     if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing:  
  295.         draw_box();
  296.         int n_cols = GetColumnsCount();
  297.         int n_rows = GetRowsCount();       
  298.         for( int i_x = 0;  i_x < n_cols;  i_x++ )    {
  299.             int left = x_GetLeft(i_x);    
  300.             int right = x_GetRight(i_x);    
  301.             for( int i_y = 0;  i_y < n_rows;  i_y++ )   {
  302.                 int top = x_GetTop(i_y);
  303.                 int bottom = x_GetBottom(i_y);
  304.                 
  305.                 // horizontal segment
  306.                 draw_box(FL_UP_BOX, left, bottom + 1, right - left + 1, m_SepSize, FL_GRAY);
  307.                 // vertical segment
  308.                 draw_box(FL_UP_BOX, right + 1, top, m_SepSize, bottom - top + 1, FL_GRAY);
  309.                 // intersection
  310.                 draw_box(FL_UP_BOX, right + 1, bottom + 1, m_SepSize, m_SepSize, FL_GRAY);
  311.             }        
  312.         }
  313.     }
  314.     draw_children();
  315.     
  316.     fl_pop_clip();
  317. }
  318. void    CSplitter::resize(int new_x, int new_y, int new_w, int new_h)
  319. {
  320.     bool b_size_changed = new_w != w()  || new_h != h();
  321.     bool b_pos_changed = new_x != x()  || new_y != y();
  322.     
  323.     if(b_size_changed)  {
  324.         x_DoResize(m_vSplitPosX, m_vNormSizeX, w(), new_w); // horizontal
  325.         x_DoResize(m_vSplitPosY, m_vNormSizeY, h(), new_h); // vertical
  326.     }
  327.     if(b_size_changed  ||  b_pos_changed)   {
  328.         Fl_Widget::resize(new_x, new_y, new_w, new_h);
  329.     
  330.         for(int i = 0; i < (int) m_vCells.size(); i++ )    {
  331.             if(m_vCells[i])
  332.                 x_ResizeToCell(i);
  333.         }    
  334.         redraw();
  335.     }
  336. }
  337. void    CSplitter::init_sizes() {   x_Deprecated();   }
  338. void    CSplitter::insert(Fl_Widget &w, int n)  {   x_Deprecated();   }
  339. void    CSplitter::begin()  {   x_Deprecated();   }
  340. void    CSplitter::end()    {   x_Deprecated();   }
  341. const Fl_Widget** CSplitter::array() const  
  342. {   
  343.     x_Deprecated();  return NULL;
  344. }
  345. Fl_Widget*        CSplitter::child(int n) const
  346. {
  347.     x_Deprecated();  return NULL;
  348. }
  349. int     CSplitter::children() const 
  350. {
  351.     x_Deprecated();  return -1;  
  352. }
  353. int     CSplitter::find(const Fl_Widget *w) const
  354. {
  355.     x_Deprecated();  return -1;  
  356. }
  357. int     CSplitter::find(const Fl_Widget &w) const
  358. {
  359.     x_Deprecated();  return -1;  
  360. }
  361. void    CSplitter::resizable(Fl_Widget *box)   {   x_Deprecated();   }
  362. void    CSplitter::resizable(Fl_Widget &box)   {   x_Deprecated();   }
  363. Fl_Widget*  CSplitter::resizable() const
  364. {
  365.     x_Deprecated();  return NULL;
  366. }
  367. Fl_Group&   CSplitter::add_resizable(Fl_Widget &box)
  368. {
  369.     x_Deprecated();  return *this;
  370. }
  371. Fl_Widget*   CSplitter::x_GetCell(int i_x, int i_y)
  372. {
  373.     bool b_valid = (i_x >= 0  &&  i_x <= (int) m_vSplitPosX.size())
  374.                     && (i_y >= 0  &&  i_y <= (int) m_vSplitPosY.size());
  375.     _ASSERT(b_valid);
  376.     if(b_valid) {
  377.         int index = i_x + i_y * GetColumnsCount();
  378.         return m_vCells[index];
  379.     }
  380.     return NULL;
  381. }
  382. int     CSplitter::x_GetCellIndex(int i_x, int i_y)
  383. {
  384.     bool b_valid = (i_x >= 0  &&  i_x <= (int) m_vSplitPosX.size())
  385.                     && (i_y >= 0  &&  i_y <= (int) m_vSplitPosY.size());
  386.     _ASSERT(b_valid);
  387.     return b_valid ? (i_x + i_y * GetColumnsCount()) : -1;
  388. }
  389. int     CSplitter::x_GetColumn(int i_cell) const
  390. {
  391.     _ASSERT(i_cell >= 0  &&  i_cell < (int) m_vCells.size());
  392.     int n_cols = m_vSplitPosX.size() + 1;
  393.     return i_cell % n_cols;
  394. }
  395. int     CSplitter::x_GetRow(int i_cell) const
  396. {
  397.     _ASSERT(i_cell >= 0  &&  i_cell < (int) m_vCells.size());
  398.     int n_cols = m_vSplitPosX.size() + 1;
  399.     return i_cell / n_cols;
  400. }
  401. int     CSplitter::x_GetLeft(int i_x)     const
  402. {
  403.     _ASSERT(i_x >= 0  &&  i_x <= (int) m_vSplitPosX.size());
  404.     int loc_x = (i_x == 0) ? 0 : (m_vSplitPosX[i_x - 1] + m_SepSize);
  405.     return x() + loc_x;
  406. }
  407. int     CSplitter::x_GetRight(int i_x)  const
  408. {
  409.     _ASSERT(i_x >= 0  &&  i_x <= (int) m_vSplitPosX.size());
  410.     int loc_next =  (i_x == (int) m_vSplitPosX.size()) ? w() : m_vSplitPosX[i_x];
  411.     return x() + loc_next - 1;
  412. }
  413. int     CSplitter::x_GetWidth(int i_x)  const
  414. {
  415.     _ASSERT(i_x >= 0  &&  i_x <= (int) m_vSplitPosX.size());
  416.     int top = (i_x == 0) ? 0 : m_vSplitPosX[i_x - 1] + m_SepSize;
  417.     int next =  (i_x == (int) m_vSplitPosX.size()) ? w() : m_vSplitPosX[i_x];
  418.     return next - top;
  419. }
  420. int     CSplitter::x_GetTop(int i_y)     const
  421. {
  422.     _ASSERT(i_y >= 0  &&  i_y <= (int) m_vSplitPosY.size());
  423.     int loc_y = (i_y == 0) ? 0 : (m_vSplitPosY[i_y - 1] + m_SepSize);
  424.     return y() + loc_y;
  425. }
  426. int     CSplitter::x_GetBottom(int i_y)  const
  427. {
  428.     _ASSERT(i_y >= 0  &&  i_y <= (int) m_vSplitPosY.size());
  429.     int loc_next =  (i_y == (int) m_vSplitPosY.size()) ? h() : m_vSplitPosY[i_y];
  430.     return y() + loc_next - 1;
  431. }
  432. int     CSplitter::x_GetHeight(int i_y)  const
  433. {
  434.     _ASSERT(i_y >= 0  &&  i_y <= (int) m_vSplitPosY.size());
  435.     int top = (i_y == 0) ? 0 : m_vSplitPosY[i_y - 1] + m_SepSize;
  436.     int next =  (i_y == (int) m_vSplitPosY.size()) ? h() : m_vSplitPosY[i_y];
  437.     return next - top;
  438. }
  439. // removes all child widgets and separators
  440. void    CSplitter::x_Clear()
  441. {
  442.     clear();
  443.     m_vSplitPosX.clear();
  444.     m_vSplitPosY.clear();
  445.     
  446.     m_vCells.resize(1, NULL);
  447.     
  448.     m_vNormSizeX.clear();
  449.     m_vNormSizeX.push_back(-1);
  450.     
  451.     m_vNormSizeY.clear();
  452.     m_vNormSizeY.push_back(-1);
  453. }
  454. void    CSplitter::x_ResizeToCell(int i_cell)
  455. {
  456.     int i_x = x_GetColumn(i_cell);
  457.     int i_y = x_GetRow(i_cell);
  458.     x_ResizeToCell(i_x, i_y);
  459. }
  460. void    CSplitter::x_ResizeToCell(int i_x, int i_y)
  461. {
  462.     Fl_Widget* w = x_GetCell(i_x, i_y);
  463.     if(w)   {
  464.         int left = x_GetLeft(i_x);
  465.         int width = x_GetWidth(i_x);
  466.         int top = x_GetTop(i_y);
  467.         int height = x_GetHeight(i_y);
  468.         
  469.         w->resize(left, top, width, height);
  470.     }    
  471. }
  472. int  CSplitter::handle(int event)
  473. {
  474.     m_Event.OnFLTKEvent(event);
  475.     int res = 0;
  476.     switch(event)   {
  477.     case FL_KEYDOWN:
  478.     case FL_KEYUP:  res = x_HandleKeyEvent(); break;
  479.     case FL_MOVE:   res = x_HandleMouseMove(); break;
  480.     case FL_PUSH:   res = x_HandleMousePush(); break;
  481.     case FL_DRAG: res = x_HandleMouseDrag(); break;
  482.     case FL_RELEASE: res = x_HandleMouseRelease(); break;
  483.     default: res = Fl_Group::handle(event);
  484.     }     
  485.     return res;
  486. }
  487. int    CSplitter::x_HandleKeyEvent()
  488. {
  489.     return 0;
  490. }
  491. int    CSplitter::x_HandleMouseMove()
  492. {
  493.     int i_sep_x = x_HitTestSeparator(Fl::event_x() - x(), m_vSplitPosX);
  494.     int i_sep_y = x_HitTestSeparator(Fl::event_y() - y(), m_vSplitPosY);
  495.     Fl_Cursor cursor = FL_CURSOR_DEFAULT;
  496.     if(i_sep_x == -1)  {
  497.         cursor = (i_sep_y == -1) ? FL_CURSOR_DEFAULT : FL_CURSOR_NS;
  498.     } else  {
  499.         cursor = (i_sep_y == -1) ? FL_CURSOR_WE : FL_CURSOR_MOVE ;
  500.     }
  501.     fl_cursor(cursor, FL_BLACK, FL_WHITE); 
  502.     
  503.     if(i_sep_x == -1  && i_sep_y == -1) {
  504.         return Fl_Group::handle(FL_MOVE);
  505.     } else return 1;
  506. }
  507. int    CSplitter::x_HandleMousePush()
  508. {
  509.     switch(m_Event.GetGUISignal()) {
  510.     case    CGUIEvent::ePush:   return true;
  511.     case    CGUIEvent::eSelectSignal:   {
  512.         m_MouseDownX = Fl::event_x();
  513.         m_MouseDownY = Fl::event_y();
  514.         int i_sep_x = x_HitTestSeparator(Fl::event_x() - x(), m_vSplitPosX);
  515.         int i_sep_y = x_HitTestSeparator(Fl::event_y() - y(), m_vSplitPosY);
  516.         
  517.         bool b_hit_x_sep = (i_sep_x != -1);
  518.         bool b_hit_y_sep = (i_sep_y != -1);
  519.         int n_clicks = Fl::event_clicks();
  520.         if(b_hit_x_sep  ||  b_hit_y_sep)    {
  521.             if(n_clicks == 0) { // single click
  522.                 m_iDragSepX = i_sep_x;
  523.                 m_iDragSepY = i_sep_y;
  524.                 m_StartPosX = (m_iDragSepX == -1) ? -1 : m_vSplitPosX[m_iDragSepX];
  525.                 m_StartPosY = (m_iDragSepY == -1) ? -1 : m_vSplitPosY[m_iDragSepY];
  526.             } else if(n_clicks == 1)    { // double click
  527.                 x_DistributeEvenly(b_hit_x_sep, b_hit_y_sep);
  528.                 return 1;
  529.             }
  530.             return 1;
  531.         }
  532.         return Fl_Group::handle(FL_PUSH);
  533.     }
  534.     default: break;
  535.     }; //switch
  536.     return Fl_Group::handle(FL_PUSH);
  537. }
  538. int    CSplitter::x_HandleMouseDrag()
  539. {
  540.     if(x_IsDragging()) {
  541.         x_DoDragSeparator(false);      
  542.         return 1;
  543.     }
  544.     return Fl_Group::handle(FL_DRAG);
  545. }
  546. int    CSplitter::x_HandleMouseRelease()
  547. {
  548.     bool b_handled = false;
  549.     if(x_IsDragging()) { // if dragging - do not share events with children
  550.         x_DoDragSeparator(true);
  551.         m_iDragSepX = m_iDragSepY = -1;
  552.         b_handled = true;
  553.     } else  {
  554.         int i_cell_x, i_cell_y, i_sep_x, i_sep_y;
  555.         x_HitTest(Fl::event_x() - x(), m_vSplitPosX, i_cell_x, i_sep_x);
  556.         x_HitTest(Fl::event_y() - y(), m_vSplitPosY, i_cell_y, i_sep_y);
  557.         if(m_Event.GetGUISignal() ==  CGUIEvent::ePopupSignal)   {
  558.             if(i_cell_x != -1  && i_cell_y != -1) { // hit the cell
  559.                 b_handled = Fl_Group::handle(FL_RELEASE) != 0; // let the children handle it
  560.             }
  561.             if(! b_handled) { // not on child or children haven't handled  
  562.                 fl_cursor(FL_CURSOR_DEFAULT, FL_BLACK, FL_WHITE); 
  563.                 x_OnShowPopupMenu();    
  564.                 b_handled = true;
  565.             }
  566.         } else Fl_Group::handle(FL_RELEASE); // default handling
  567.     }
  568.     return b_handled ? 1 : 0; 
  569. }
  570. void    CSplitter::x_DoDragSeparator(bool b_final)
  571. {
  572.     int start_x = 0, stop_x = -1;
  573.     int start_y = 0, stop_y = -1;
  574.     if(m_iDragSepX != -1)   {
  575.         int shift = Fl::event_x() - m_MouseDownX; // global shift
  576.         int new_pos = m_StartPosX + shift;
  577.         x_MoveSeparator(m_iDragSepX, new_pos, m_vSplitPosX, w(), start_x, stop_x);
  578.         if(b_final) {
  579.             m_vNormSizeX[m_iDragSepX] = -1;
  580.             m_vNormSizeX[m_iDragSepX + 1] = -1;
  581.         }
  582.     }
  583.     if(m_iDragSepY != -1)   {
  584.         int shift = Fl::event_y() - m_MouseDownY; // global shift
  585.         int new_pos = m_StartPosY + shift;
  586.         x_MoveSeparator(m_iDragSepY, new_pos, m_vSplitPosY, h(), start_y, stop_y);
  587.         if(b_final) {
  588.             m_vNormSizeY[m_iDragSepY] = -1;
  589.             m_vNormSizeY[m_iDragSepY + 1] = -1;
  590.         }
  591.     }
  592.     
  593.     x_UpdateRegion(start_x, stop_x, start_y, stop_y);      
  594. }
  595. // z is local coordinate in the dimension corresponding to vpos
  596. int     CSplitter::x_HitTestSeparator(int z, TPosVector& vpos)
  597. {
  598.     int n = vpos.size();
  599.     for( int i = 0; i < n; i++  )   {
  600.         int pos = vpos[i];
  601.         if(z >= pos  &&  z < pos + m_SepSize)
  602.             return i;
  603.     }
  604.     return -1;
  605. }
  606. // assuming that "z" is within splitter bounds
  607. void    CSplitter::x_HitTest(int z, TPosVector& vpos, int& i_cell, int& i_sep)
  608. {
  609.     i_sep = i_cell = -1;
  610.     int n = vpos.size();
  611.     for( int i = 0; i < n; i++  )   {
  612.         int pos = vpos[i];
  613.         if(z < pos) { // belongs to cell
  614.             i_cell = i;
  615.             return;
  616.         } else if(z < pos + m_SepSize)  { // belongs to separator
  617.             i_sep = i;
  618.             return;
  619.         }
  620.     }
  621.     i_cell = n;
  622.     return; // belongs to last cell
  623. }
  624. void    CSplitter::x_OnShowPopupMenu()
  625. {
  626. }
  627. void    CSplitter::x_DistributeEvenly(bool b_x, bool b_y)
  628. {
  629.     if(b_x) {
  630.         x_DoDistributeEvenly(m_vSplitPosX, w());
  631.         std::fill(m_vNormSizeX.begin(), m_vNormSizeX.end(), -1);
  632.     }
  633.     if(b_y) {
  634.         x_DoDistributeEvenly(m_vSplitPosY, h());
  635.         std::fill(m_vNormSizeY.begin(), m_vNormSizeY.end(), -1);
  636.     }
  637.     if(b_x  ||  b_y)    {
  638.         for( int i = 0; i < (int) m_vCells.size(); i++ )  {
  639.             int i_x = x_GetColumn(i);
  640.             int i_y = x_GetRow(i);
  641.             x_ResizeToCell(i_x, i_y);
  642.         }
  643.         redraw();
  644.     }
  645. }
  646. void    CSplitter::x_DoDistributeEvenly(TPosVector& vSplitPos, int size)
  647. {
  648.     int n = vSplitPos.size() + 1;
  649.     int space = max(0, size - m_SepSize * (n - 1));
  650.     int w = space / n; // space per row/column
  651.     int rest = space - w * n; // space that cannot be divided evenly
  652.     
  653.     int pos = w + (rest ? 1 : 0);
  654.     for( int i = 0; i < n - 1; i++ )   {
  655.         vSplitPos[i] = pos;
  656.         pos += w + m_SepSize;
  657.         if(i < rest) // for first "rest" children add 1 pixel
  658.             pos++;
  659.     }
  660. }
  661. void    CSplitter::x_DoResize(TPosVector& v_split_pos, TSizeVector& v_norm_sizes, int size, int new_size)
  662. {        
  663.     _ASSERT(v_split_pos.size() + 1 == v_norm_sizes.size());
  664.     
  665.     int n_split = v_split_pos.size();
  666.     int min_size = n_split * m_SepSize;
  667.     if(new_size < size) { // splitter is shrinking        
  668.         int limit = max(new_size, min_size); 
  669.     
  670.         for( int i = n_split; i >= 0; i--)   {         
  671.             int next_start = (i == n_split) ? size : v_split_pos[i];
  672.             if(next_start >= limit) { // shrink it
  673.                 int start = (i == 0) ? 0 : (v_split_pos[i - 1] + m_SepSize);        
  674.             
  675.                 if(visible()  &&  v_norm_sizes[i] < 0) { 
  676.                     // splitter is visible and cell is being resized for the fisrt time
  677.                     v_norm_sizes[i] = next_start - start; // save original size
  678.                 }
  679.                 if(i < n_split) {
  680.                     v_split_pos[i] = limit; // move separator
  681.                 }
  682.                 limit -= m_SepSize;            
  683.             }
  684.             else break;
  685.         } 
  686.     } else if(new_size > size)  { // splitter is growing
  687.         int grow_space = min(new_size - size, size - min_size); 
  688.         int shift = 0; // cumulative shift for split positions
  689.         for( int i = 0; i < n_split; i++)   {
  690.             if(grow_space > 0  &&  v_norm_sizes[i] > 0) {
  691.                 // cell needs to grow and there is space left
  692.                 int start = (i == 0) ? 0 : (v_split_pos[i - 1] + m_SepSize);        
  693.                 int next_start = + (i == n_split) ? size : v_split_pos[i];
  694.                 int sz = next_start - start; // current size
  695.                 int new_sz = min(v_norm_sizes[i], sz + grow_space);
  696.                 
  697.                 if(new_sz >= v_norm_sizes[i])   {
  698.                     v_norm_sizes[i] = -1; // does not want to grow anymore
  699.                 }
  700.                 int d_sz = new_sz - sz; // size increase
  701.                 shift += d_sz;
  702.                 grow_space -= d_sz;               
  703.             }
  704.             if(shift)   {
  705.                 v_split_pos[i] += shift;
  706.             }
  707.         }
  708.     }
  709. }
  710. void    CSplitter::x_MoveSeparator(int i_sep, int new_pos, 
  711.                                    TPosVector& vSplitPos, int size, 
  712.                                    int& start, int& stop)
  713. {
  714.     _ASSERT(i_sep >= 0  && i_sep < (int) vSplitPos.size());
  715.     start = 0;
  716.     stop = -1; // set empty range
  717.     int pos = vSplitPos[i_sep];
  718.     int d = new_pos - pos;
  719.         
  720.     if(d != 0)  {
  721.         int n_sep = vSplitPos.size();
  722.         if(d > 0)    { // movind down        
  723.             int bottom_lim = size - (n_sep - i_sep) * m_SepSize;
  724.             new_pos = min(new_pos, bottom_lim);
  725.             if(new_pos > pos)   { // there is space to move to    
  726.                 int  p = new_pos;
  727.                 int i = i_sep;
  728.                 // move current separator and , if necessary, separator below it
  729.                 for(; i < n_sep; i++)  { 
  730.                     if(p > vSplitPos[i])  {
  731.                         vSplitPos[i] = p;
  732.                         p += m_SepSize;
  733.                     } else break;                
  734.                 }
  735.                 // resize children
  736.                 start = i_sep;
  737.                 stop = min(i, n_sep);
  738.             }
  739.         } else if(d < 0)    { //moving up
  740.             int top_lim = i_sep * m_SepSize;
  741.             new_pos = max(new_pos, top_lim);
  742.             if(new_pos < pos)   { // there is space to move to
  743.                 int p = new_pos;
  744.                 int i = i_sep;
  745.                 
  746.                 // move current separator and , if necessary, separator below it
  747.                 for(; i >= 0; i--)  { 
  748.                     if(p < vSplitPos[i])  {
  749.                         vSplitPos[i] = p;
  750.                         p -= m_SepSize;
  751.                     } else break;                
  752.                 }
  753.                 // resize children
  754.                 start = max(0, i + 1);
  755.                 stop = i_sep + 1;
  756.             }
  757.         }
  758.     }
  759. }
  760. void    CSplitter::x_UpdateRegion(int start_x, int stop_x, int start_y, int stop_y)
  761. {
  762.     bool b_redraw = false;
  763.     for(int i_x = 0; i_x <= (int) m_vSplitPosX.size(); i_x++ ) {
  764.         for( int i_y = 0; i_y <= (int) m_vSplitPosY.size(); i_y++  )   {
  765.             // if cell belongs to one of the affected ranges - resize it
  766.             if( (i_x >= start_x  &&  i_x <= stop_x)  ||
  767.                 (i_y >= start_y  &&  i_y <= stop_y) )   { 
  768.                 b_redraw = true;
  769.                 x_ResizeToCell(i_x, i_y);
  770.             }
  771.         }
  772.     }
  773.     if(b_redraw)    {
  774.         redraw();
  775.     }
  776. }
  777. void    CSplitter::x_NewSplit(TPosVector& v_split_pos, TSizeVector& v_norm_size, int size)
  778. {        
  779.     int n_split = v_split_pos.size();
  780.     int sum_size = h() - n_split * m_SepSize;
  781.     int av_size = sum_size / (n_split + 1); // average cell size
  782.     // splitting...
  783.     v_split_pos.push_back(size);
  784.     v_norm_size.push_back(-1);
  785.     n_split++;
  786.     // calculate new sizes
  787.     double K = (double)(sum_size - m_SepSize) / (sum_size + av_size);        
  788.     TPosVector sizes(n_split);
  789.     for( int i = 0; i < n_split; i++ )  {
  790.         int start = (i == 0) ? 0 : v_split_pos[i - 1] + m_SepSize;
  791.         int size = v_split_pos[i] - start;
  792.         sizes[i] = (int)( K * size);        
  793.     }
  794.     
  795.     // moving split points
  796.     for( int pos = 0, i = 0; i < n_split; i++ )  {
  797.         pos += sizes[i];
  798.         v_split_pos[i] = pos;
  799.         pos += m_SepSize;
  800.     }
  801. }
  802. END_NCBI_SCOPE
  803. /*
  804.  * ===========================================================================
  805.  * $Log: splitter.cpp,v $
  806.  * Revision 1000.1  2004/06/01 21:09:10  gouriano
  807.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.7
  808.  *
  809.  * Revision 1.7  2004/05/21 22:27:53  gorelenk
  810.  * Added PCH ncbi_pch.hpp
  811.  *
  812.  * Revision 1.6  2004/05/13 17:22:54  yazhuk
  813.  * Clean-up
  814.  *
  815.  * Revision 1.5  2004/05/10 16:25:40  yazhuk
  816.  * Addressed GCC warnings
  817.  *
  818.  * Revision 1.4  2004/02/04 20:02:44  yazhuk
  819.  * Added Remove(), RemoveAll(), Find() and new overload for Create()
  820.  *
  821.  * Revision 1.3  2004/01/28 16:40:28  yazhuk
  822.  * Major refactoring, bug fixes, added new functions
  823.  *
  824.  * Revision 1.2  2004/01/23 00:00:29  ucko
  825.  * Properly capitalize FL directory for headers.
  826.  *
  827.  * Revision 1.1  2004/01/22 16:26:24  yazhuk
  828.  * Initial revision
  829.  *
  830.  * ===========================================================================
  831.  */