tab_control.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:21k
- /*
- * ===========================================================================
- * PRODUCTION $Log: tab_control.cpp,v $
- * PRODUCTION Revision 1000.1 2004/06/01 21:09:17 gouriano
- * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.8
- * PRODUCTION
- * ===========================================================================
- */
- /* $Id: tab_control.cpp,v 1000.1 2004/06/01 21:09:17 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 <gui/widgets/fl/tab_control.hpp>
- #include <gui/widgets/fl/menu.hpp>
- #include <FL/fl_draw.H>
- BEGIN_NCBI_SCOPE
- ///////////////////////////////////////////////////////////////////////////////
- /// CTabControl
- CTabControl::CTabControl()
- : Fl_Group(0, 0, 0, 0),
- m_Selected(-1),
- m_TabAreaH(0)
- {
- x_Init();
- end();
- }
- CTabControl::CTabControl(int x, int y, int w, int h, const char* label)
- : Fl_Group(x, y, w, h, label),
- m_Selected(-1),
- m_TabAreaH(0)
- {
- x_Init();
- end();
- }
- CTabControl::~CTabControl()
- {
- }
- static const int kScrollBarSize = 15;
- void CTabControl::x_Init()
- {
- end();
- m_ResizePolicies = fShrink;//|fExpand ;
- box(FL_NO_BOX);
- m_Event.StandardConfig();
- m_BorderColor = fl_rgb_color(127, 127, 127);
- m_ActiveBorderColor = fl_rgb_color(96, 96, 96);
-
- m_BackColor = fl_rgb_color(224, 224, 224);
- m_ActiveBackColor = fl_rgb_color(240, 240, 240);
-
- m_TextColor = fl_rgb_color(64, 64, 64);
- m_ActiveTextColor = fl_rgb_color(0, 0, 0);
- m_Tooltip.SetMode(CTooltip::eStayOnMove);
- m_Tooltip.EnableActiveMode(this);
- }
- void CTabControl::SetResizePolicies(int policies)
- {
- if(m_ResizePolicies != policies) {
- m_ResizePolicies = policies;
- x_Layout();
- redraw();
- }
- }
- bool CTabControl::AddTab(Fl_Widget* pane, const char* label)
- {
- if(pane) {
- int count = x_GetTabsCount();
- return x_InsertTab(pane, count, label, "");
- }
- return false;
- }
- bool CTabControl::InsertTab(Fl_Widget* pane, int index, const char* label)
- {
- int count = x_GetTabsCount();
- if(pane && index >=0 && index <= count) {
- return x_InsertTab(pane, index, label, "");
- }
- return false;
- }
- bool CTabControl::RemoveTab(Fl_Widget* pane)
- {
- int index = x_GetTabIndex(pane);
- if(index >= 0) {
- return x_RemoveTab(index);
- }
- return false;
- }
- bool CTabControl::RemoveTab(int index)
- {
- return x_RemoveTab(index);
- }
- void CTabControl::RemoveAllTabs()
- {
- x_RemoveAllTabs();
- }
- int CTabControl::GetTabsCount() const
- {
- return x_GetTabsCount();
- }
-
- Fl_Widget* CTabControl::GetTab(int index)
- {
- return x_GetPane(index);
- }
- string CTabControl::GetTabLabel(int index) const
- {
- if(x_IsIndexValid(index)) {
- return m_vDescrs[index]->m_Label;
- } else return "";
- }
- string CTabControl::GetTabTooltip(int index) const
- {
- if(x_IsIndexValid(index)) {
- return m_vDescrs[index]->m_Tooltip;
- } else return "";
- }
- void CTabControl::SetTabLabel(int index, const char* label)
- {
- if(x_IsIndexValid(index)) {
- m_vDescrs[index]->m_Label = label ? label : "";
- x_Layout();
- }
- }
- void CTabControl::SetTabTooltip(int index, const char* tooltip)
- {
- if(x_IsIndexValid(index)) {
- m_vDescrs[index]->m_Tooltip = tooltip ? tooltip : "";
- x_Layout();
- }
- }
- int CTabControl::GetSelectedTab() const
- {
- return m_Selected;
- }
- void CTabControl::SelectTab(int index)
- {
- x_SelectTab(index);
- }
- Fl_Widget* CTabControl::x_GetPane(int index)
- {
- if(x_IsIndexValid(index)) {
- return m_vDescrs[index]->m_pPane;
- }
- _ASSERT(false);
- return false;
- }
- CTabControl::STabDescr* CTabControl::x_GetTab(int index)
- {
- if(x_IsIndexValid(index)) {
- return m_vDescrs[index];
- }
- _ASSERT(false);
- return NULL;
- }
- int CTabControl::x_GetTabIndex(Fl_Widget* pane) const
- {
- for( int i = 0; i < x_GetTabsCount(); i++ ) {
- if(m_vDescrs[i]->m_pPane == pane)
- return i;
- }
- return -1;
- }
- bool CTabControl::x_InsertTab(Fl_Widget* pane, int index, const char* label,
- const char* tooltip)
- {
- bool b_valid = index >= 0 && index <= x_GetTabsCount();
- _ASSERT(b_valid);
- if(b_valid) {
- STabDescr* p_descr = new STabDescr;
- p_descr->m_pPane = pane;
- p_descr->m_Label = label ? label : "";
- p_descr->m_Tooltip = tooltip ? tooltip : "";
- pane->hide();
- Fl_Group::add(pane);
- m_vDescrs.insert(m_vDescrs.begin() + index, p_descr);
-
- x_LayoutTabs();
- x_SelectTab(index);
- return true;
- } else return false;
- }
- bool CTabControl::x_RemoveTab(int index)
- {
- _ASSERT(x_IsIndexValid(index));
- if(x_IsIndexValid(index)) {
- STabDescr* p_descr = m_vDescrs[index];
-
- p_descr->m_pPane->hide();
- Fl_Group::remove(p_descr->m_pPane);
- delete p_descr;
- m_vDescrs.erase(m_vDescrs.begin() + index);
- x_LayoutTabs();
- // adjust selected
- if(index < m_Selected) {
- m_Selected--;
- }
- bool b_reselect = (index == m_Selected);
- if(index == x_GetTabsCount())
- index--;
- if(b_reselect) {
- m_Selected = -1;
- x_SelectTab(index);
- }
- redraw();
- return true;
- } else return false;
- }
- void CTabControl::x_RemoveAllTabs()
- {
- while(! m_vDescrs.empty()) {
- STabDescr* p_descr = m_vDescrs.back();
-
- Fl_Group::remove(p_descr->m_pPane);
- m_vDescrs.pop_back();
- }
- }
- void CTabControl::x_SelectTab(int index)
- {
- _ASSERT(index >= -1 && index < (int) x_GetTabsCount());
- if(index != m_Selected) {
- Fl_Widget* curr_w = x_GetSelectedPane();
- if(curr_w) {
- curr_w->hide();
- }
- m_Selected = index;
-
- curr_w = x_GetSelectedPane();
-
- if(curr_w) {
- int cl_x, cl_y, cl_w, cl_h;
- x_GetClientRect(cl_x, cl_y, cl_w, cl_h);
- curr_w->resize(cl_x, cl_y, cl_w, cl_h);
- curr_w->show();
- }
- redraw();
- }
- }
- CTabControl::STabDescr* CTabControl::x_GetSelectedTab()
- {
- if(x_IsIndexValid(m_Selected)) {
- return m_vDescrs[m_Selected];
- } else return NULL;
- }
- Fl_Widget* CTabControl::x_GetSelectedPane()
- {
- if(x_IsIndexValid(m_Selected)) {
- return m_vDescrs[m_Selected]->m_pPane;
- } else return NULL;
- }
- const static int kClientOffset = 2; // client inset
- const static int kTabRowH = 24; // height of a single row of tabs
- const static int kTabOffsetX = 8;
- const static int kTabOffsetY = 6;
- const static int kTabSpaceY = 4; // vertical spacing between client and tab rectangle
- const static int kTabSpaceX = 2; // space between client frame and tab rectangles
- void CTabControl::draw()
- {
- fl_push_clip(x(), y(), w(), h());
- if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing:
-
- int has_tabs = x_GetTabsCount() > 0;
- int x2 = x() + w() - 1;
- int y2 = y() + h() - 1;
- if(has_tabs) { // outer frame - backround color
- fl_color(m_BackColor);
- fl_xyline(x(), y(), x2);
- fl_xyline(x(), y(), x(), y2);
- fl_xyline(x2, y(), x2, y2);
- } else { // fill entire area
- fl_rectf(x(), y(), w(), h(), m_BackColor);
- }
- int tab_top = y() + h() - x_GetTabAreaH();
- int tab_bottom = y() + h();
- int row_h = x_GetTabRowH();
- // fill Tab area
- int area_h = x_GetTabAreaH() + kClientOffset;
- int area_w = w() - 2 * kClientOffset;
-
- int highlight_h = kTabSpaceY;
-
- int off = kClientOffset - 1;
- if(m_Selected != -1) {
- STabDescr* p_descr = m_vDescrs[m_Selected];
- highlight_h = p_descr->m_y - (h() - x_GetTabAreaH() - kClientOffset);
- y2 = y() + p_descr->m_y;
- } else y2 -= off;
-
- int y3 = tab_top - kClientOffset;
- fl_rectf(x() + kClientOffset, y3, area_w, highlight_h, m_ActiveBackColor);
- fl_rectf(x(), y3 + highlight_h, w(), area_h - highlight_h, m_BackColor);
-
- // draw inner frame with border color
- fl_color(m_ActiveBorderColor);
- fl_xyline(x() + off, y() + off, x2 - off);
- fl_xyline(x() + off, y() + off , x() + off, y2);
- fl_xyline(x2 - off, y() + off, x2 - off, y2);
- if(! has_tabs) {
- fl_xyline(x() + off, y2, x2 - off, y2);
- }
- // draw tabs
- fl_font(FL_HELVETICA, 12);
- for( int i = 0; i < x_GetTabsCount(); i++ ) {
- x_DrawTab(i);
- }
- }
- Fl_Group::draw();
- fl_pop_clip();
- }
- /// draws Tab corresponding to a given index
- void CTabControl::x_DrawTab(int index)
- {
- STabDescr* p_descr = m_vDescrs[index];
-
- bool bActive = (index == m_Selected);
- int off_x = bActive ? 2 : 0;
- int x1 = x() + p_descr->m_x - off_x;
- int y1 = y() + p_descr->m_y;
- int width = p_descr->m_w - 1 + 2 * off_x;
- int height = p_descr->m_h - 2;
- int x2 = x1 + width - 1;
- int y2 = y1 + height - 1;
-
- // draw Tab countour
- fl_color(bActive ? m_ActiveBorderColor : m_BorderColor);
-
- fl_xyline(x1, y1, x1, y2 - 2); // left vert
- fl_line(x1, y2 - 2, x1 + 2, y2);
- fl_xyline(x1 + 2, y2, x2 - 2, y2); // horz line
- fl_line(x2 - 2, y2, x2, y2 - 2);
- fl_xyline(x2, y1, x2, y2 - 2); // right vert
-
- // fill tab's background
- if(bActive) {
- fl_color(m_ActiveBackColor);
- fl_rectf(x1 + 1, y1, width - 2, height - 2);
- } else {
- fl_color(m_BackColor);
- fl_rectf(x1 + 1, y1 +1, width - 2, height - 3);
- }
-
- // tab's edge
- fl_color(m_BackColor);
- fl_xyline(x1 + 1, y2 - 2, x2 - 1);
- fl_xyline(x1 + 2, y2 - 1, x2 - 2);
-
- if(index == m_Selected) {
- // horizontal line closing client rect
- fl_color(m_ActiveBorderColor);
- int off = kClientOffset - 1;
- fl_xyline(x() + off, y1, x1 - off);
- fl_xyline(x2 + off, y1, x() + w() - 1 - off);
- }
- //draw label
- int text_x = x1 + off_x + kTabOffsetX;
- int text_y = y2 - kTabOffsetY;
- int text_w = width - 2 * kTabOffsetX;
- fl_push_clip(text_x, y1, text_w, height);
-
- fl_color(bActive ? m_ActiveTextColor : m_TextColor);
- fl_draw_text(p_descr->m_Label, text_x, text_y, text_w);
- fl_pop_clip();
- }
- void CTabControl::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 || b_pos_changed) {
- Fl_Widget::resize(new_x, new_y, new_w, new_h);
- if(b_size_changed) {
- x_Layout();
- redraw();
- }
- }
- }
- void CTabControl::x_Layout()
- {
- x_LayoutTabs();
- // resize selected (visible) pane
- Fl_Widget* pane = x_GetSelectedPane();
- if(pane) {
- int cl_x, cl_y, cl_w, cl_h;
- x_GetClientRect(cl_x, cl_y, cl_w, cl_h);
- pane->resize(cl_x, cl_y, cl_w, cl_h);
- }
- }
- void CTabControl::x_LayoutTabs()
- {
- bool b_multi = (m_ResizePolicies & fMultiRow) != 0;
- bool b_expand = (m_ResizePolicies & fExpand) != 0;
- bool b_shrink = (m_ResizePolicies & fShrink) != 0;
-
- m_vRows.clear();
- // mesuare all tabs
- vector<int> widths;
- int total_w = 0;
- int n_tabs = x_GetTabsCount();
- for ( int i = 0; i < n_tabs; i++ ) {
- int width = x_MeasureTabWidth(i);
- total_w += width;
- widths.push_back(width);
- }
-
- int w_av = w() - 2 * (kTabSpaceX + kClientOffset);
- int row_h = x_GetTabRowH();
- int pos_x = kClientOffset + kTabSpaceX;
-
- //assembling tabs in rows
- if(b_multi) { // create multi-row layout
- for ( int i = 0; i < n_tabs; i++ ) {
- int width = widths[i];
- if(i == 0 || pos_x + width > w_av) { // start next row
- m_vRows.push_back(TRowIndexes());
- pos_x = kClientOffset + 1;
- }
- pos_x += width;
- m_vRows.back().push_back(i);
- }
- } else {
- if(b_shrink && total_w > w_av) { // distributing space deficit
- double K = ((double) w_av) / total_w; // reduction koeff.
- int pos = 0;
- for ( int i = 0; i < n_tabs; i++ ) {
- int prev_pos = pos;
- pos += widths[i];
- widths[i] = (int)(K * pos) - (int)(K * prev_pos);
- }
- }
- m_vRows.push_back(TRowIndexes());
- for ( int i = 0; i < n_tabs; i++ ) {
- m_vRows.back().push_back(i);
- }
- }
-
- //now we know how many rows we need
- m_TabAreaH = kTabSpaceY + row_h * m_vRows.size();
-
- // assign positions to rows
- int pos_y = h() - m_TabAreaH + kTabSpaceY;
-
- for( size_t row = 0; row < m_vRows.size(); row++ ) { // for each row
- TRowIndexes& indexes = m_vRows[row];
- pos_x = kClientOffset + kTabSpaceX;
- int n_cols = indexes.size();
- int row_w, delta, rest; // used in fExpand mode
- if(b_expand) {
- row_w = 0;
- for( int col = 0; col < n_cols; col++ ) {
- row_w += widths[indexes[col]];
- }
- int extra = w_av - row_w; // available extra space in a row
- if(extra > 0) {
- delta = extra / n_cols;
- rest = extra - delta * n_cols; // space that cannot be divided between all tabs
- } else delta = rest = 0;
- }
- for( int col = 0; col < n_cols; col++ ) { // for each tab in a row
- int i_tab = indexes[col];
- STabDescr* p_descr = m_vDescrs[i_tab];
- int tab_w = min(widths[i_tab], w_av); // not wider than control
- if(b_expand) {
- tab_w += delta + ((col < rest) ? 1 : 0);
- }
- p_descr->m_x = pos_x;
- p_descr->m_w = tab_w;
- pos_x += tab_w;
-
- p_descr->m_y = pos_y;
- p_descr->m_h = row_h;
- }
- pos_y += row_h;
- }
- }
- int CTabControl::x_GetTabAreaH() const
- {
- return m_TabAreaH;
- }
- int CTabControl::x_GetTabRowH() const
- {
- return kTabRowH;
- }
- int CTabControl::x_MeasureTabWidth(int index)
- {
- STabDescr* p_descr = m_vDescrs[index];
- fl_font(FL_HELVETICA, 12);
- const char* p_text = p_descr->m_Label.c_str();
- int text_w = fl_width(p_text);
- int width = text_w + 2 * kTabOffsetX + 1;
- return width;
- }
- int CTabControl::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);
- }; break;
- }
- m_Tooltip.Handle(event);
- return res;
- }
- bool CTabControl::x_IsIndexValid(int index) const
- {
- return index >= 0 && index < x_GetTabsCount();
- }
- void CTabControl::x_GetClientRect(int& cl_x, int& cl_y, int& cl_w, int& cl_h)
- {
- cl_x = x() + kClientOffset;
- cl_y = y() + kClientOffset;
- cl_w = w() - 2 * kClientOffset;
- cl_h = h() - x_GetTabAreaH() - 2 * kClientOffset;
- }
- bool inline PointInRect(int px, int py, int x, int y, int w, int h)
- {
- return px >= x && px < x + w && py >= y && py < y + h;
- }
- CTabControl::EHitResult CTabControl::x_HitTest(int pos_x, int pos_y, int& i_tab)
- {
- i_tab = -1;
- if(PointInRect(pos_x, pos_y, x(), y(), w(), h())) {
-
- int cl_x, cl_y, cl_w, cl_h;
- x_GetClientRect(cl_x, cl_y, cl_w, cl_h);
- if(PointInRect(pos_x, pos_y, cl_x, cl_y, cl_w, cl_h)) {
- return eClient;
- } else {
- for( int i = 0; i < x_GetTabsCount(); i++ ) {
- STabDescr* p_descr = m_vDescrs[i];
- int loc_x = pos_x - x();
- int loc_y = pos_y - y();
- if(PointInRect(loc_x, loc_y, p_descr->m_x, p_descr->m_y,
- p_descr->m_w, p_descr->m_h)) {
- i_tab = i;
- return eTab;
- }
- }
- }
- return eEmptySpace;
- }
- return eNothing;
- }
- int CTabControl::x_HandleKeyEvent()
- {
- return 0;
- }
- int CTabControl::x_HandleMouseMove()
- {
- return Fl_Group::handle(FL_MOVE);
- }
- int CTabControl::x_HandleMousePush()
- {
- int i_tab;
- EHitResult hit_res = x_HitTest(Fl::event_x(), Fl::event_y(), i_tab);
-
- switch(hit_res) {
- case eClient: return Fl_Group::handle(FL_PUSH); break;
- case eTab:
- case eEmptySpace: {
- int res = 0;
- switch(m_Event.GetGUISignal()) {
- // any mouse click event switches tabs
- case CGUIEvent::ePush: //return true;
- case CGUIEvent::eSelectSignal:
- case CGUIEvent::ePopupSignal: {
- if(i_tab != -1) {
- x_SelectTab(i_tab);
- res = 1;
- }
- }
- }; // switch(m_Event.GetGUISignal())
- if(m_Event.GetGUISignal() == CGUIEvent::ePopupSignal) {
- fl_cursor(FL_CURSOR_DEFAULT, FL_BLACK, FL_WHITE);
- x_OnShowPopupMenu();
- }
- return res;
- }; break;
- }; // switch(hit_res) {
- return 0;
- }
- int CTabControl::x_HandleMouseDrag()
- {
- return Fl_Group::handle(FL_DRAG);
- }
- int CTabControl::x_HandleMouseRelease()
- {
- int i_tab;
- EHitResult hit_res = x_HitTest(Fl::event_x(), Fl::event_y(), i_tab);
-
- bool b_handled = false;
- CGUIEvent::EGUISignal signal = m_Event.GetGUISignal(); // remember
-
- if(hit_res == eClient) {
- if(Fl_Group::handle(FL_RELEASE))
- return true;
- } else if(hit_res == eTab) {
- _ASSERT(i_tab != -1);
- x_SelectTab(i_tab);
- }
- if((signal == CGUIEvent::ePopupSignal) &&
- (hit_res == eTab || hit_res == eEmptySpace)) {
- fl_cursor(FL_CURSOR_DEFAULT, FL_BLACK, FL_WHITE);
- x_OnShowPopupMenu();
- return 1;
- }
- return 0;
- }
- void CTabControl::x_OnShowPopupMenu()
- {
- }
- bool CTabControl::TC_NeedTooltip(int x, int y)
- {
- EHitResult hit_res = x_HitTest(Fl::event_x(), Fl::event_y(), m_iHitTab);
- return hit_res == eTab;
- }
- string CTabControl::TC_GetTooltip(int& x, int& y, int& w, int& h)
- {
- if(m_iHitTab != -1) {
- _ASSERT(x_IsIndexValid(m_iHitTab));
- STabDescr* p_descr = m_vDescrs[m_iHitTab];
- x = p_descr->m_x;
- y = p_descr->m_y;
- w = p_descr->m_w;
- h = p_descr->m_h;
- return p_descr->m_Label;
- }
- return "";
- }
- END_NCBI_SCOPE
- /*
- * ===========================================================================
- * $Log: tab_control.cpp,v $
- * Revision 1000.1 2004/06/01 21:09:17 gouriano
- * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.8
- *
- * Revision 1.8 2004/05/21 22:27:53 gorelenk
- * Added PCH ncbi_pch.hpp
- *
- * Revision 1.7 2004/05/20 12:44:06 dicuccio
- * Added explicit call to end() - closes tab group correctly
- *
- * Revision 1.6 2004/05/13 17:20:32 yazhuk
- * Moved fl_draw_text() functions to utils.hpp; added end() to x_Init()
- *
- * Revision 1.5 2004/05/07 14:21:23 yazhuk
- * Fixed RemoveTab()
- *
- * Revision 1.4 2004/03/08 15:53:13 yazhuk
- * Fixed popup menu handling; clean-up
- *
- * Revision 1.3 2004/03/02 22:27:20 yazhuk
- * Popup menu fix for Mac
- *
- * Revision 1.2 2004/02/04 20:26:36 ucko
- * Fix capitalization of fl_draw.H.
- *
- * Revision 1.1 2004/02/04 20:01:20 yazhuk
- * Initial revision
- *
- * ===========================================================================
- */