notebook.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,435 行 · 第 1/3 页
CPP
1,435 行
int flags = 0;
if ( n == m_sel )
{
flags |= wxCONTROL_SELECTED;
if ( IsFocused() )
flags |= wxCONTROL_FOCUSED;
}
GetRenderer()->DrawTab
(
dc,
rect,
GetTabOrientation(),
m_titles[n],
bmp,
flags,
m_accels[n]
);
}
void wxNotebook::DoDraw(wxControlRenderer *renderer)
{
//wxRect rectUpdate = GetUpdateClientRect(); -- unused
wxDC& dc = renderer->GetDC();
dc.SetFont(GetFont());
dc.SetTextForeground(GetForegroundColour());
// redraw the border - it's simpler to always do it instead of checking
// whether this needs to be done
GetRenderer()->DrawBorder(dc, wxBORDER_RAISED, GetPagePart());
// avoid overwriting the spin button
if ( HasSpinBtn() )
{
wxRect rectTabs = GetAllTabsRect();
wxSize sizeSpinBtn = m_spinbtn->GetSize();
if ( IsVertical() )
{
rectTabs.height -= sizeSpinBtn.y;
// Allow for erasing the line under selected tab
rectTabs.width += 2;
}
else
{
rectTabs.width -= sizeSpinBtn.x;
// Allow for erasing the line under selected tab
rectTabs.height += 2;
}
dc.SetClippingRegion(rectTabs);
}
wxRect rect = GetTabsPart();
bool isVertical = IsVertical();
wxRect rectSel;
for ( size_t n = m_firstVisible; n < m_lastVisible; n++ )
{
GetTabSize(n, &rect.width, &rect.height);
if ( n == m_sel )
{
// don't redraw it now as this tab has to be drawn over the other
// ones as it takes more place and spills over to them
rectSel = rect;
}
else // not selected tab
{
// unfortunately we can't do this because the selected tab hangs
// over its neighbours and so we might need to refresh more tabs -
// of course, we could still avoid rereshing some of them with more
// complicated checks, but it doesn't seem too bad to refresh all
// of them, I still don't see flicker, so leaving as is for now
//if ( rectUpdate.Intersects(rect) )
{
DoDrawTab(dc, rect, n);
}
//else: doesn't need to be refreshed
}
// move the rect to the next tab
if ( isVertical )
rect.y += rect.height;
else
rect.x += rect.width;
}
// now redraw the selected tab
if ( rectSel.width )
{
DoDrawTab(dc, rectSel, m_sel);
}
dc.DestroyClippingRegion();
}
// ----------------------------------------------------------------------------
// wxNotebook geometry
// ----------------------------------------------------------------------------
int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
{
if ( flags )
*flags = wxNB_HITTEST_NOWHERE;
// first check that it is in this window at all
if ( !GetClientRect().Inside(pt) )
{
return -1;
}
wxRect rectTabs = GetAllTabsRect();
switch ( GetTabOrientation() )
{
default:
wxFAIL_MSG(_T("unknown tab orientation"));
// fall through
case wxTOP:
if ( pt.y > rectTabs.GetBottom() )
return -1;
break;
case wxBOTTOM:
if ( pt.y < rectTabs.y )
return -1;
break;
case wxLEFT:
if ( pt.x > rectTabs.GetRight() )
return -1;
break;
case wxRIGHT:
if ( pt.x < rectTabs.x )
return -1;
break;
}
for ( size_t n = m_firstVisible; n < m_lastVisible; n++ )
{
GetTabSize(n, &rectTabs.width, &rectTabs.height);
if ( rectTabs.Inside(pt) )
{
if ( flags )
{
// TODO: be more precise
*flags = wxNB_HITTEST_ONITEM;
}
return n;
}
// move the rectTabs to the next tab
if ( IsVertical() )
rectTabs.y += rectTabs.height;
else
rectTabs.x += rectTabs.width;
}
return -1;
}
bool wxNotebook::IsVertical() const
{
wxDirection dir = GetTabOrientation();
return dir == wxLEFT || dir == wxRIGHT;
}
wxDirection wxNotebook::GetTabOrientation() const
{
long style = GetWindowStyle();
if ( style & wxNB_BOTTOM )
return wxBOTTOM;
else if ( style & wxNB_RIGHT )
return wxRIGHT;
else if ( style & wxNB_LEFT )
return wxLEFT;
// wxNB_TOP == 0 so we don't have to test for it
return wxTOP;
}
wxRect wxNotebook::GetTabRect(int page) const
{
wxRect rect;
wxCHECK_MSG( IS_VALID_PAGE(page), rect, _T("invalid notebook page") );
// calc the size of this tab and of the preceding ones
wxCoord widthThis, widthBefore;
if ( FixedSizeTabs() )
{
widthThis = m_widthMax;
widthBefore = page*m_widthMax;
}
else
{
widthBefore = 0;
for ( int n = 0; n < page; n++ )
{
widthBefore += m_widths[n];
}
widthThis = m_widths[page];
}
rect = GetTabsPart();
if ( IsVertical() )
{
rect.y += widthBefore - m_offset;
rect.height = widthThis;
}
else // horz
{
rect.x += widthBefore - m_offset;
rect.width = widthThis;
}
return rect;
}
wxRect wxNotebook::GetAllTabsRect() const
{
wxRect rect;
if ( GetPageCount() )
{
const wxSize indent = GetRenderer()->GetTabIndent();
wxSize size = GetClientSize();
if ( IsVertical() )
{
rect.width = m_heightTab + indent.x;
rect.x = GetTabOrientation() == wxLEFT ? 0 : size.x - rect.width;
rect.y = 0;
rect.height = size.y;
}
else // horz
{
rect.x = 0;
rect.width = size.x;
rect.height = m_heightTab + indent.y;
rect.y = GetTabOrientation() == wxTOP ? 0 : size.y - rect.height;
}
}
//else: no pages
return rect;
}
wxRect wxNotebook::GetTabsPart() const
{
wxRect rect = GetAllTabsRect();
wxDirection dir = GetTabOrientation();
const wxSize indent = GetRenderer()->GetTabIndent();
if ( IsVertical() )
{
rect.y += indent.x;
if ( dir == wxLEFT )
{
rect.x += indent.y;
rect.width -= indent.y;
}
else // wxRIGHT
{
rect.width -= indent.y;
}
}
else // horz
{
rect.x += indent.x;
if ( dir == wxTOP )
{
rect.y += indent.y;
rect.height -= indent.y;
}
else // wxBOTTOM
{
rect.height -= indent.y;
}
}
return rect;
}
void wxNotebook::GetTabSize(int page, wxCoord *w, wxCoord *h) const
{
wxCHECK_RET( w && h, _T("NULL pointer in GetTabSize") );
if ( IsVertical() )
{
// width and height have inverted meaning
wxCoord *tmp = w;
w = h;
h = tmp;
}
// height is always fixed
*h = m_heightTab;
// width may also be fixed and be the same for all tabs
*w = GetTabWidth(page);
}
void wxNotebook::SetTabSize(const wxSize& sz)
{
wxCHECK_RET( FixedSizeTabs(), _T("SetTabSize() ignored") );
if ( IsVertical() )
{
m_heightTab = sz.x;
m_widthMax = sz.y;
}
else // horz
{
m_widthMax = sz.x;
m_heightTab = sz.y;
}
}
wxSize wxNotebook::CalcTabSize(int page) const
{
// NB: don't use m_widthMax, m_heightTab or m_widths here because this
// method is called to calculate them
wxSize size;
wxCHECK_MSG( IS_VALID_PAGE(page), size, _T("invalid notebook page") );
GetTextExtent(m_titles[page], &size.x, &size.y);
if ( HasImage(page) )
{
wxSize sizeImage;
m_imageList->GetSize(m_images[page], sizeImage.x, sizeImage.y);
size.x += sizeImage.x + 5; // FIXME: hard coded margin
if ( sizeImage.y > size.y )
size.y = sizeImage.y;
}
size.x += 2*m_sizePad.x;
size.y += 2*m_sizePad.y;
return size;
}
void wxNotebook::ResizeTab(int page)
{
wxSize sizeTab = CalcTabSize(page);
// we only need full relayout if the page size changes
bool needsRelayout = false;
if ( IsVertical() )
{
// swap coordinates
wxCoord tmp = sizeTab.x;
sizeTab.x = sizeTab.y;
sizeTab.y = tmp;
}
if ( sizeTab.y > m_heightTab )
{
needsRelayout = true;
m_heightTab = sizeTab.y;
}
m_widths[page] = sizeTab.x;
if ( sizeTab.x > m_widthMax )
m_widthMax = sizeTab.x;
// the total of the tabs has changed too
UpdateSpinBtn();
if ( needsRelayout )
Relayout();
else
RefreshAllTabs();
}
void wxNotebook::SetPadding(const wxSize& padding)
{
if ( padding != m_sizePad )
{
m_sizePad = padding;
Relayout();
}
}
void wxNotebook::Relayout()
{
if ( GetPageCount() )
{
RefreshAllTabs();
UpdateSpinBtn();
if ( m_sel != INVALID_PAGE )
{
// resize the currently shown page
wxRect rectPage = GetPageRect();
m_pages[m_sel]->SetSize(rectPage);
// also scroll it into view if needed (note that m_lastVisible
// was updated by the call to UpdateSpinBtn() above, this is why it
// is needed here)
if ( HasSpinBtn() )
{
if ( m_sel < m_firstVisible )
{
// selection is to the left of visible part of tabs
ScrollTo(m_sel);
}
else if ( m_sel > m_lastFullyVisible )
{
// selection is to the right of visible part of tabs
ScrollLastTo(m_sel);
}
}
}
}
else // we have no pages
{
// just refresh everything
Refresh();
}
}
wxRect wxNotebook::GetPagePart() const
{
wxRect rectPage = GetClientRect();
if ( GetPageCount() )
{
wxRect rectTabs = GetAllTabsRect();
wxDirection dir = GetTabOrientation();
if ( IsVertical() )
{
rectPage.width -= rectTabs.width;
if ( dir == wxLEFT )
rectPage.x += rectTabs.width;
}
else // horz
{
rectPage.height -= rectTabs.height;
if ( dir == wxTOP )
rectPage.y += rectTabs.height;
}
}
//else: no pages at all
return rectPage;
}
wxRect wxNotebook::GetPageRect() const
{
wxRect rect = GetPagePart();
// leave space for the border
wxRect rectBorder = GetRenderer()->GetBorderDimensions(wxBORDER_RAISED);
// FIXME: hardcoded +2!
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?