splitter.cpp

来自「ncbi源码」· C++ 代码 · 共 950 行 · 第 1/2 页

CPP
950
字号
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 separatorsvoid    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 vposint     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 boundsvoid    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 * * =========================================================================== */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?