splitter.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:27k
- /*
- * ===========================================================================
- * PRODUCTION $Log: splitter.cpp,v $
- * PRODUCTION Revision 1000.1 2004/06/01 21:09:10 gouriano
- * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.7
- * PRODUCTION
- * ===========================================================================
- */
- /* $Id: splitter.cpp,v 1000.1 2004/06/01 21:09:10 gouriano Exp $
- * ===========================================================================
- *
- * PUBLIC DOMAIN NOTICE
- * National Center for Biotechnology Information
- *
- * This software/database is a "United States Government Work" under the
- * terms of the United States Copyright Act. It was written as part of
- * the author's official duties as a United States Government employee and
- * thus cannot be copyrighted. This software/database is freely available
- * to the public for use. The National Library of Medicine and the U.S.
- * Government have not placed any restriction on its use or reproduction.
- *
- * Although all reasonable efforts have been taken to ensure the accuracy
- * and reliability of the software and data, the NLM and the U.S.
- * Government do not and cannot warrant the performance or results that
- * may be obtained by using this software or data. The NLM and the U.S.
- * Government disclaim all warranties, express or implied, including
- * warranties of performance, merchantability or fitness for any particular
- * purpose.
- *
- * Please cite the author in any work or product based on this material.
- *
- * ===========================================================================
- *
- * Authors: Andrey Yazhuk
- *
- * File Description:
- *
- */
- #include <ncbi_pch.hpp>
- #include <corelib/ncbistd.hpp>
- #include <corelib/ncbistl.hpp>
- #include <algorithm>
- #include <gui/widgets/fl/splitter.hpp>
- #include <FL/fl_draw.H>
- #include <FL/Fl.H>
- BEGIN_NCBI_SCOPE
- CSplitter::CSplitter(int x, int y, int w, int h, const char* label)
- : Fl_Group(x, y, w, h, label),
- m_Mode(eHorizontal),
- m_SepSize(4),
- m_iDragSepX(-1), m_iDragSepY(-1)
- {
- Fl_Group::end();
-
- color(fl_rgb_color(224, 224, 224));
- box(FL_FLAT_BOX);
- m_vCells.resize(1, NULL); // by default it has a single cell
- m_vNormSizeX.resize(1, -1);
- m_vNormSizeY.resize(1, -1);
- m_Event.StandardConfig();
- }
- CSplitter::~CSplitter()
- {
- }
- CSplitter::EMode CSplitter::GetMode() const
- {
- return m_Mode;
- }
- void CSplitter::Create(EMode mode)
- {
- if(m_Mode != mode) {
- x_Clear();
- m_Mode = mode;
- }
- }
- const static int kMaxCells = 64;
- void CSplitter::Create(EMode mode, const TPosVector& sizes)
- {
- x_Clear();
- switch(mode) {
- case eHorizontal: x_Create(mode, TPosVector(), sizes); break;
- case eVertical: x_Create(mode, sizes, TPosVector()); break;
- case eGrid: x_Create(mode, sizes, sizes); break;
- };
- }
- void CSplitter::Create(EMode mode, const int ar_size[])
- {
- TPosVector sizes;
- int i = 0;
- for(; i < kMaxCells; i++ ) {
- if(ar_size[i] >= 0)
- sizes.push_back(ar_size[i]);
- else break;
- }
- _ASSERT(i < kMaxCells);
- Create(mode, sizes);
- }
- void CSplitter::Create(EMode mode, const TPosVector& widths, const TPosVector& heights)
- {
- x_Create(mode, widths, heights);
- }
- void CSplitter::Create(EMode mode, const int ar_w[], const int ar_h[])
- {
- TPosVector widths;
- int i = 0;
- for(; i < kMaxCells; i++ ) {
- if(ar_w[i] >= 0)
- widths.push_back(ar_w[i]);
- else break;
- }
- _ASSERT(i < kMaxCells);
-
- TPosVector heights;
- for( i = 0; i < kMaxCells; i++ ) {
- if(ar_h[i] >= 0)
- heights.push_back(ar_h[i]);
- else break;
- }
- _ASSERT(i < kMaxCells);
- x_Create(mode, widths, heights);
- }
- void CSplitter::Create(int n_horz_panes, int n_vert_panes)
- {
- vector<int> widths;
- vector<int> heights;
-
- n_horz_panes = max(1, n_horz_panes);
- n_vert_panes = max(1, n_vert_panes);
- for( int i = 0; i < n_horz_panes; i++)
- widths.push_back(10);
- for( int i = 0; i < n_vert_panes; i++)
- heights.push_back(10);
- EMode mode = (n_horz_panes == 1) ? eVertical :
- ((n_vert_panes == 1) ? eHorizontal : eGrid);
- x_Create(mode, widths, heights);
- x_DistributeEvenly(true, true);
- }
- void CSplitter::x_Create(EMode mode, const TPosVector& widths, const TPosVector& heights)
- {
- m_Mode = mode;
- int n_w = widths.size();
- int n_h = heights.size();
- if(n_w == 0) n_w++;
- if(n_h == 0) n_h++;
- _ASSERT(n_w < kMaxCells && n_h < kMaxCells); // keep 'em reasonable
- x_Clear();
-
- for( int pos = 0, i = 0; i < n_w - 1; i++) {
- pos += widths[i];
- m_vSplitPosX.push_back(pos);
- }
- m_vNormSizeX.resize(n_w, -1);
-
- for( int pos = 0, i = 0; i < n_h - 1; i++) {
- pos += heights[i];
- m_vSplitPosY.push_back(pos);
- }
- m_vNormSizeY.resize(n_h, -1);
- int n_cells = GetColumnsCount() * GetRowsCount();
- m_vCells.resize(n_cells, NULL);
- }
- int CSplitter::GetColumnsCount() const
- {
- return m_vSplitPosX.size() + 1;
- }
- int CSplitter::GetRowsCount() const
- {
- return m_vSplitPosY.size() + 1;
- }
- bool CSplitter::IsValidCell(int i_x, int i_y) const
- {
- return i_x >= 0 && i_x <= (int) m_vSplitPosX.size()
- && i_y >= 0 && i_y <= (int) m_vSplitPosY.size();
- }
- bool CSplitter::InsertToCell(Fl_Widget* w, int i_x, int i_y)
- {
- if(i_x >= 0 && i_x < GetColumnsCount()
- && i_y >= 0 && i_y < GetRowsCount()) {
-
- int i_cell = x_GetCellIndex(i_x, i_y);
- if(m_vCells[i_cell] == NULL) {// cell is vacant
- int ins_pos = 0; // insertion position
- for( int i = 0; i < i_cell; i++) {
- if(m_vCells[i])
- ins_pos++;
- }
- w->hide();
-
- Fl_Group::insert(*w, ins_pos);
- m_vCells[i_cell] = w;
- x_ResizeToCell(i_x, i_y);
- w->show();
- return true;
- }
- }
- return false;
- }
- Fl_Widget* CSplitter::RemoveFromCell(int i_x, int i_y)
- {
- int i_cell = x_GetCellIndex(i_x, i_y);
- Fl_Widget* w = m_vCells[i_cell];
- if(w) {
- m_vCells[i_cell] = NULL;
- Fl_Group::remove(w);
- }
- redraw();
- return w;
- }
- bool CSplitter::Remove(Fl_Widget* w)
- {
- int i_x, i_y;
- if(Find(w, i_x, i_y)) {
- RemoveFromCell(i_x, i_y);
- return true;
- }
- return false;
- }
- void CSplitter::RemoveAll()
- {
- for( size_t i = 0; i < m_vCells.size(); i++ ) {
- Fl_Widget* w = m_vCells[i];
- if(w) {
- m_vCells[i] = NULL;
- Fl_Group::remove(w);
- }
- }
- redraw();
- }
- bool CSplitter::Find(Fl_Widget* w, int& i_x, int& i_y) const
- {
- i_x = i_y = -1;
- if(w) {
- for( int i = 0; i < (int) m_vCells.size(); i++ ) {
- if(m_vCells[i] == w) {
- i_x = x_GetColumn(i);
- i_y = x_GetRow(i);
- return true;
- }
- }
- }
- return false;
- }
- /// adds a child widget "w" to first vacant cell. If "w" already a child it is
- /// removed and added again to a new position. If there is no cells available
- /// new row/column is created
- void CSplitter::add(Fl_Widget *widget)
- {
- TCells::iterator it = std::find(m_vCells.begin(), m_vCells.end(), widget);
- if(it != m_vCells.end()) { // already a child - remove
- Fl_Group::remove(*widget);
- *it = NULL;
- }
-
- // look for first vacant cell
- it = std::find(m_vCells.begin(), m_vCells.end(), (Fl_Widget*) NULL);
- if(it != m_vCells.end()) { // there is a vacant cell
- int i_cell = it - m_vCells.begin();
- Fl_Group::insert(*widget, i_cell);
- m_vCells[i_cell] = widget;
- int i_x = x_GetColumn(i_cell);
- int i_y = x_GetRow(i_cell);
- x_ResizeToCell(i_x, i_y);
- } else {
- int old_n_cells = m_vCells.size();
- if(m_Mode == eVertical) {
- x_NewSplit(m_vSplitPosX, m_vNormSizeX, w());
- } else {
- x_NewSplit(m_vSplitPosY, m_vNormSizeY, h());
- }
- Fl_Group::add(widget);
- m_vCells.resize(GetRowsCount() * GetColumnsCount(), NULL);
- m_vCells[old_n_cells] = widget; // old_n_cells specifies fisrt vacant position
-
- for( int i = 0; i <= old_n_cells; i++ ) {
- x_ResizeToCell(i);
- }
- }
- }
- void CSplitter::add(Fl_Widget& w)
- {
- CSplitter::add(&w);
- }
- void CSplitter::remove(Fl_Widget &w)
- {
- TCells::iterator it = std::find(m_vCells.begin(), m_vCells.end(), &w);
- if(it != m_vCells.end()) {
- *it = NULL;
- Fl_Group::remove(w);
- }
- }
- void CSplitter::draw()
- {
- fl_push_clip(x(), y(), w(), h());
- if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing:
- draw_box();
- int n_cols = GetColumnsCount();
- int n_rows = GetRowsCount();
- for( int i_x = 0; i_x < n_cols; i_x++ ) {
- int left = x_GetLeft(i_x);
- int right = x_GetRight(i_x);
- for( int i_y = 0; i_y < n_rows; i_y++ ) {
- int top = x_GetTop(i_y);
- int bottom = x_GetBottom(i_y);
-
- // horizontal segment
- draw_box(FL_UP_BOX, left, bottom + 1, right - left + 1, m_SepSize, FL_GRAY);
- // vertical segment
- draw_box(FL_UP_BOX, right + 1, top, m_SepSize, bottom - top + 1, FL_GRAY);
- // intersection
- draw_box(FL_UP_BOX, right + 1, bottom + 1, m_SepSize, m_SepSize, FL_GRAY);
- }
- }
- }
- draw_children();
-
- fl_pop_clip();
- }
- void CSplitter::resize(int new_x, int new_y, int new_w, int new_h)
- {
- bool b_size_changed = new_w != w() || new_h != h();
- bool b_pos_changed = new_x != x() || new_y != y();
-
- if(b_size_changed) {
- x_DoResize(m_vSplitPosX, m_vNormSizeX, w(), new_w); // horizontal
- x_DoResize(m_vSplitPosY, m_vNormSizeY, h(), new_h); // vertical
- }
- if(b_size_changed || b_pos_changed) {
- Fl_Widget::resize(new_x, new_y, new_w, new_h);
-
- for(int i = 0; i < (int) m_vCells.size(); i++ ) {
- if(m_vCells[i])
- x_ResizeToCell(i);
- }
- redraw();
- }
- }
- void CSplitter::init_sizes() { x_Deprecated(); }
- void CSplitter::insert(Fl_Widget &w, int n) { x_Deprecated(); }
- void CSplitter::begin() { x_Deprecated(); }
- void CSplitter::end() { x_Deprecated(); }
- const Fl_Widget** CSplitter::array() const
- {
- x_Deprecated(); return NULL;
- }
- Fl_Widget* CSplitter::child(int n) const
- {
- x_Deprecated(); return NULL;
- }
- int CSplitter::children() const
- {
- x_Deprecated(); return -1;
- }
- int CSplitter::find(const Fl_Widget *w) const
- {
- x_Deprecated(); return -1;
- }
- int CSplitter::find(const Fl_Widget &w) const
- {
- x_Deprecated(); return -1;
- }
- void CSplitter::resizable(Fl_Widget *box) { x_Deprecated(); }
- void CSplitter::resizable(Fl_Widget &box) { x_Deprecated(); }
- Fl_Widget* CSplitter::resizable() const
- {
- x_Deprecated(); return NULL;
- }
- Fl_Group& CSplitter::add_resizable(Fl_Widget &box)
- {
- x_Deprecated(); return *this;
- }
- Fl_Widget* CSplitter::x_GetCell(int i_x, int i_y)
- {
- bool b_valid = (i_x >= 0 && i_x <= (int) m_vSplitPosX.size())
- && (i_y >= 0 && i_y <= (int) m_vSplitPosY.size());
- _ASSERT(b_valid);
- if(b_valid) {
- int index = i_x + i_y * GetColumnsCount();
- return m_vCells[index];
- }
- return NULL;
- }
- int CSplitter::x_GetCellIndex(int i_x, int i_y)
- {
- bool b_valid = (i_x >= 0 && i_x <= (int) m_vSplitPosX.size())
- && (i_y >= 0 && i_y <= (int) m_vSplitPosY.size());
- _ASSERT(b_valid);
- return b_valid ? (i_x + i_y * GetColumnsCount()) : -1;
- }
- int CSplitter::x_GetColumn(int i_cell) const
- {
- _ASSERT(i_cell >= 0 && i_cell < (int) m_vCells.size());
- int n_cols = m_vSplitPosX.size() + 1;
- return i_cell % n_cols;
- }
- int CSplitter::x_GetRow(int i_cell) const
- {
- _ASSERT(i_cell >= 0 && i_cell < (int) m_vCells.size());
- int n_cols = m_vSplitPosX.size() + 1;
- return i_cell / n_cols;
- }
- int CSplitter::x_GetLeft(int i_x) const
- {
- _ASSERT(i_x >= 0 && i_x <= (int) m_vSplitPosX.size());
- int loc_x = (i_x == 0) ? 0 : (m_vSplitPosX[i_x - 1] + m_SepSize);
- return x() + loc_x;
- }
- int CSplitter::x_GetRight(int i_x) const
- {
- _ASSERT(i_x >= 0 && i_x <= (int) m_vSplitPosX.size());
- int loc_next = (i_x == (int) m_vSplitPosX.size()) ? w() : m_vSplitPosX[i_x];
- return x() + loc_next - 1;
- }
- int CSplitter::x_GetWidth(int i_x) const
- {
- _ASSERT(i_x >= 0 && i_x <= (int) m_vSplitPosX.size());
- int top = (i_x == 0) ? 0 : m_vSplitPosX[i_x - 1] + m_SepSize;
- int next = (i_x == (int) m_vSplitPosX.size()) ? w() : m_vSplitPosX[i_x];
- return next - top;
- }
- int CSplitter::x_GetTop(int i_y) const
- {
- _ASSERT(i_y >= 0 && i_y <= (int) m_vSplitPosY.size());
- int loc_y = (i_y == 0) ? 0 : (m_vSplitPosY[i_y - 1] + m_SepSize);
- return y() + loc_y;
- }
- int CSplitter::x_GetBottom(int i_y) const
- {
- _ASSERT(i_y >= 0 && i_y <= (int) m_vSplitPosY.size());
- int loc_next = (i_y == (int) m_vSplitPosY.size()) ? h() : m_vSplitPosY[i_y];
- return y() + loc_next - 1;
- }
- int CSplitter::x_GetHeight(int i_y) const
- {
- _ASSERT(i_y >= 0 && i_y <= (int) m_vSplitPosY.size());
- int top = (i_y == 0) ? 0 : m_vSplitPosY[i_y - 1] + m_SepSize;
- int next = (i_y == (int) m_vSplitPosY.size()) ? h() : m_vSplitPosY[i_y];
- return next - top;
- }
- // removes all child widgets and separators
- void CSplitter::x_Clear()
- {
- clear();
- m_vSplitPosX.clear();
- m_vSplitPosY.clear();
-
- m_vCells.resize(1, NULL);
-
- m_vNormSizeX.clear();
- m_vNormSizeX.push_back(-1);
-
- m_vNormSizeY.clear();
- m_vNormSizeY.push_back(-1);
- }
- void CSplitter::x_ResizeToCell(int i_cell)
- {
- int i_x = x_GetColumn(i_cell);
- int i_y = x_GetRow(i_cell);
- x_ResizeToCell(i_x, i_y);
- }
- void CSplitter::x_ResizeToCell(int i_x, int i_y)
- {
- Fl_Widget* w = x_GetCell(i_x, i_y);
- if(w) {
- int left = x_GetLeft(i_x);
- int width = x_GetWidth(i_x);
- int top = x_GetTop(i_y);
- int height = x_GetHeight(i_y);
-
- w->resize(left, top, width, height);
- }
- }
- int CSplitter::handle(int event)
- {
- m_Event.OnFLTKEvent(event);
- int res = 0;
- switch(event) {
- case FL_KEYDOWN:
- case FL_KEYUP: res = x_HandleKeyEvent(); break;
- case FL_MOVE: res = x_HandleMouseMove(); break;
- case FL_PUSH: res = x_HandleMousePush(); break;
- case FL_DRAG: res = x_HandleMouseDrag(); break;
- case FL_RELEASE: res = x_HandleMouseRelease(); break;
- default: res = Fl_Group::handle(event);
- }
- return res;
- }
- int CSplitter::x_HandleKeyEvent()
- {
- return 0;
- }
- int CSplitter::x_HandleMouseMove()
- {
- int i_sep_x = x_HitTestSeparator(Fl::event_x() - x(), m_vSplitPosX);
- int i_sep_y = x_HitTestSeparator(Fl::event_y() - y(), m_vSplitPosY);
- Fl_Cursor cursor = FL_CURSOR_DEFAULT;
- if(i_sep_x == -1) {
- cursor = (i_sep_y == -1) ? FL_CURSOR_DEFAULT : FL_CURSOR_NS;
- } else {
- cursor = (i_sep_y == -1) ? FL_CURSOR_WE : FL_CURSOR_MOVE ;
- }
- fl_cursor(cursor, FL_BLACK, FL_WHITE);
-
- if(i_sep_x == -1 && i_sep_y == -1) {
- return Fl_Group::handle(FL_MOVE);
- } else return 1;
- }
- int CSplitter::x_HandleMousePush()
- {
- switch(m_Event.GetGUISignal()) {
- case CGUIEvent::ePush: return true;
- case CGUIEvent::eSelectSignal: {
- m_MouseDownX = Fl::event_x();
- m_MouseDownY = Fl::event_y();
- int i_sep_x = x_HitTestSeparator(Fl::event_x() - x(), m_vSplitPosX);
- int i_sep_y = x_HitTestSeparator(Fl::event_y() - y(), m_vSplitPosY);
-
- bool b_hit_x_sep = (i_sep_x != -1);
- bool b_hit_y_sep = (i_sep_y != -1);
- int n_clicks = Fl::event_clicks();
- if(b_hit_x_sep || b_hit_y_sep) {
- if(n_clicks == 0) { // single click
- m_iDragSepX = i_sep_x;
- m_iDragSepY = i_sep_y;
- m_StartPosX = (m_iDragSepX == -1) ? -1 : m_vSplitPosX[m_iDragSepX];
- m_StartPosY = (m_iDragSepY == -1) ? -1 : m_vSplitPosY[m_iDragSepY];
- } else if(n_clicks == 1) { // double click
- x_DistributeEvenly(b_hit_x_sep, b_hit_y_sep);
- return 1;
- }
- return 1;
- }
- return Fl_Group::handle(FL_PUSH);
- }
- default: break;
- }; //switch
- return Fl_Group::handle(FL_PUSH);
- }
- int CSplitter::x_HandleMouseDrag()
- {
- if(x_IsDragging()) {
- x_DoDragSeparator(false);
- return 1;
- }
- return Fl_Group::handle(FL_DRAG);
- }
- int CSplitter::x_HandleMouseRelease()
- {
- bool b_handled = false;
- if(x_IsDragging()) { // if dragging - do not share events with children
- x_DoDragSeparator(true);
- m_iDragSepX = m_iDragSepY = -1;
- b_handled = true;
- } else {
- int i_cell_x, i_cell_y, i_sep_x, i_sep_y;
- x_HitTest(Fl::event_x() - x(), m_vSplitPosX, i_cell_x, i_sep_x);
- x_HitTest(Fl::event_y() - y(), m_vSplitPosY, i_cell_y, i_sep_y);
- if(m_Event.GetGUISignal() == CGUIEvent::ePopupSignal) {
- if(i_cell_x != -1 && i_cell_y != -1) { // hit the cell
- b_handled = Fl_Group::handle(FL_RELEASE) != 0; // let the children handle it
- }
- if(! b_handled) { // not on child or children haven't handled
- fl_cursor(FL_CURSOR_DEFAULT, FL_BLACK, FL_WHITE);
- x_OnShowPopupMenu();
- b_handled = true;
- }
- } else Fl_Group::handle(FL_RELEASE); // default handling
- }
- return b_handled ? 1 : 0;
- }
- void CSplitter::x_DoDragSeparator(bool b_final)
- {
- int start_x = 0, stop_x = -1;
- int start_y = 0, stop_y = -1;
- if(m_iDragSepX != -1) {
- int shift = Fl::event_x() - m_MouseDownX; // global shift
- int new_pos = m_StartPosX + shift;
- x_MoveSeparator(m_iDragSepX, new_pos, m_vSplitPosX, w(), start_x, stop_x);
- if(b_final) {
- m_vNormSizeX[m_iDragSepX] = -1;
- m_vNormSizeX[m_iDragSepX + 1] = -1;
- }
- }
- if(m_iDragSepY != -1) {
- int shift = Fl::event_y() - m_MouseDownY; // global shift
- int new_pos = m_StartPosY + shift;
- x_MoveSeparator(m_iDragSepY, new_pos, m_vSplitPosY, h(), start_y, stop_y);
- if(b_final) {
- m_vNormSizeY[m_iDragSepY] = -1;
- m_vNormSizeY[m_iDragSepY + 1] = -1;
- }
- }
-
- x_UpdateRegion(start_x, stop_x, start_y, stop_y);
- }
- // z is local coordinate in the dimension corresponding to vpos
- int CSplitter::x_HitTestSeparator(int z, TPosVector& vpos)
- {
- int n = vpos.size();
- for( int i = 0; i < n; i++ ) {
- int pos = vpos[i];
- if(z >= pos && z < pos + m_SepSize)
- return i;
- }
- return -1;
- }
- // assuming that "z" is within splitter bounds
- void CSplitter::x_HitTest(int z, TPosVector& vpos, int& i_cell, int& i_sep)
- {
- i_sep = i_cell = -1;
- int n = vpos.size();
- for( int i = 0; i < n; i++ ) {
- int pos = vpos[i];
- if(z < pos) { // belongs to cell
- i_cell = i;
- return;
- } else if(z < pos + m_SepSize) { // belongs to separator
- i_sep = i;
- return;
- }
- }
- i_cell = n;
- return; // belongs to last cell
- }
- void CSplitter::x_OnShowPopupMenu()
- {
- }
- void CSplitter::x_DistributeEvenly(bool b_x, bool b_y)
- {
- if(b_x) {
- x_DoDistributeEvenly(m_vSplitPosX, w());
- std::fill(m_vNormSizeX.begin(), m_vNormSizeX.end(), -1);
- }
- if(b_y) {
- x_DoDistributeEvenly(m_vSplitPosY, h());
- std::fill(m_vNormSizeY.begin(), m_vNormSizeY.end(), -1);
- }
- if(b_x || b_y) {
- for( int i = 0; i < (int) m_vCells.size(); i++ ) {
- int i_x = x_GetColumn(i);
- int i_y = x_GetRow(i);
- x_ResizeToCell(i_x, i_y);
- }
- redraw();
- }
- }
- void CSplitter::x_DoDistributeEvenly(TPosVector& vSplitPos, int size)
- {
- int n = vSplitPos.size() + 1;
- int space = max(0, size - m_SepSize * (n - 1));
- int w = space / n; // space per row/column
- int rest = space - w * n; // space that cannot be divided evenly
-
- int pos = w + (rest ? 1 : 0);
- for( int i = 0; i < n - 1; i++ ) {
- vSplitPos[i] = pos;
- pos += w + m_SepSize;
- if(i < rest) // for first "rest" children add 1 pixel
- pos++;
- }
- }
- void CSplitter::x_DoResize(TPosVector& v_split_pos, TSizeVector& v_norm_sizes, int size, int new_size)
- {
- _ASSERT(v_split_pos.size() + 1 == v_norm_sizes.size());
-
- int n_split = v_split_pos.size();
- int min_size = n_split * m_SepSize;
- if(new_size < size) { // splitter is shrinking
- int limit = max(new_size, min_size);
-
- for( int i = n_split; i >= 0; i--) {
- int next_start = (i == n_split) ? size : v_split_pos[i];
- if(next_start >= limit) { // shrink it
- int start = (i == 0) ? 0 : (v_split_pos[i - 1] + m_SepSize);
-
- if(visible() && v_norm_sizes[i] < 0) {
- // splitter is visible and cell is being resized for the fisrt time
- v_norm_sizes[i] = next_start - start; // save original size
- }
- if(i < n_split) {
- v_split_pos[i] = limit; // move separator
- }
- limit -= m_SepSize;
- }
- else break;
- }
- } else if(new_size > size) { // splitter is growing
- int grow_space = min(new_size - size, size - min_size);
- int shift = 0; // cumulative shift for split positions
- for( int i = 0; i < n_split; i++) {
- if(grow_space > 0 && v_norm_sizes[i] > 0) {
- // cell needs to grow and there is space left
- int start = (i == 0) ? 0 : (v_split_pos[i - 1] + m_SepSize);
- int next_start = + (i == n_split) ? size : v_split_pos[i];
- int sz = next_start - start; // current size
- int new_sz = min(v_norm_sizes[i], sz + grow_space);
-
- if(new_sz >= v_norm_sizes[i]) {
- v_norm_sizes[i] = -1; // does not want to grow anymore
- }
- int d_sz = new_sz - sz; // size increase
- shift += d_sz;
- grow_space -= d_sz;
- }
- if(shift) {
- v_split_pos[i] += shift;
- }
- }
- }
- }
- void CSplitter::x_MoveSeparator(int i_sep, int new_pos,
- TPosVector& vSplitPos, int size,
- int& start, int& stop)
- {
- _ASSERT(i_sep >= 0 && i_sep < (int) vSplitPos.size());
- start = 0;
- stop = -1; // set empty range
- int pos = vSplitPos[i_sep];
- int d = new_pos - pos;
-
- if(d != 0) {
- int n_sep = vSplitPos.size();
- if(d > 0) { // movind down
- int bottom_lim = size - (n_sep - i_sep) * m_SepSize;
- new_pos = min(new_pos, bottom_lim);
- if(new_pos > pos) { // there is space to move to
- int p = new_pos;
- int i = i_sep;
- // move current separator and , if necessary, separator below it
- for(; i < n_sep; i++) {
- if(p > vSplitPos[i]) {
- vSplitPos[i] = p;
- p += m_SepSize;
- } else break;
- }
- // resize children
- start = i_sep;
- stop = min(i, n_sep);
- }
- } else if(d < 0) { //moving up
- int top_lim = i_sep * m_SepSize;
- new_pos = max(new_pos, top_lim);
- if(new_pos < pos) { // there is space to move to
- int p = new_pos;
- int i = i_sep;
-
- // move current separator and , if necessary, separator below it
- for(; i >= 0; i--) {
- if(p < vSplitPos[i]) {
- vSplitPos[i] = p;
- p -= m_SepSize;
- } else break;
- }
- // resize children
- start = max(0, i + 1);
- stop = i_sep + 1;
- }
- }
- }
- }
- void CSplitter::x_UpdateRegion(int start_x, int stop_x, int start_y, int stop_y)
- {
- bool b_redraw = false;
- for(int i_x = 0; i_x <= (int) m_vSplitPosX.size(); i_x++ ) {
- for( int i_y = 0; i_y <= (int) m_vSplitPosY.size(); i_y++ ) {
- // if cell belongs to one of the affected ranges - resize it
- if( (i_x >= start_x && i_x <= stop_x) ||
- (i_y >= start_y && i_y <= stop_y) ) {
- b_redraw = true;
- x_ResizeToCell(i_x, i_y);
- }
- }
- }
- if(b_redraw) {
- redraw();
- }
- }
- void CSplitter::x_NewSplit(TPosVector& v_split_pos, TSizeVector& v_norm_size, int size)
- {
- int n_split = v_split_pos.size();
- int sum_size = h() - n_split * m_SepSize;
- int av_size = sum_size / (n_split + 1); // average cell size
- // splitting...
- v_split_pos.push_back(size);
- v_norm_size.push_back(-1);
- n_split++;
- // calculate new sizes
- double K = (double)(sum_size - m_SepSize) / (sum_size + av_size);
- TPosVector sizes(n_split);
- for( int i = 0; i < n_split; i++ ) {
- int start = (i == 0) ? 0 : v_split_pos[i - 1] + m_SepSize;
- int size = v_split_pos[i] - start;
- sizes[i] = (int)( K * size);
- }
-
- // moving split points
- for( int pos = 0, i = 0; i < n_split; i++ ) {
- pos += sizes[i];
- v_split_pos[i] = pos;
- pos += m_SepSize;
- }
- }
- END_NCBI_SCOPE
- /*
- * ===========================================================================
- * $Log: splitter.cpp,v $
- * Revision 1000.1 2004/06/01 21:09:10 gouriano
- * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.7
- *
- * Revision 1.7 2004/05/21 22:27:53 gorelenk
- * Added PCH ncbi_pch.hpp
- *
- * Revision 1.6 2004/05/13 17:22:54 yazhuk
- * Clean-up
- *
- * Revision 1.5 2004/05/10 16:25:40 yazhuk
- * Addressed GCC warnings
- *
- * Revision 1.4 2004/02/04 20:02:44 yazhuk
- * Added Remove(), RemoveAll(), Find() and new overload for Create()
- *
- * Revision 1.3 2004/01/28 16:40:28 yazhuk
- * Major refactoring, bug fixes, added new functions
- *
- * Revision 1.2 2004/01/23 00:00:29 ucko
- * Properly capitalize FL directory for headers.
- *
- * Revision 1.1 2004/01/22 16:26:24 yazhuk
- * Initial revision
- *
- * ===========================================================================
- */