notebook.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,389 行 · 第 1/3 页
CPP
1,389 行
rc.left = rc.top = 0;
GetSize((int *)&rc.right, (int *)&rc.bottom);
// save the total size, we'll use it below
int widthNbook = rc.right - rc.left,
heightNbook = rc.bottom - rc.top;
// there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
// returns completely false values for multiline tab controls after the tabs
// are added but before getting the first WM_SIZE (off by ~50 pixels, see
//
// http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
//
// and the only work around I could find was this ugly hack... without it
// simply toggling the "multiline" checkbox in the notebook sample resulted
// in a noticeable page displacement
if ( HasFlag(wxNB_MULTILINE) )
{
// avoid an infinite recursion: we get another notification too!
static bool s_isInOnSize = false;
if ( !s_isInOnSize )
{
s_isInOnSize = true;
SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
MAKELPARAM(rc.right, rc.bottom));
s_isInOnSize = false;
}
}
#if wxUSE_UXTHEME
// background bitmap size has changed, update the brush using it too
UpdateBgBrush();
#endif // wxUSE_UXTHEME
TabCtrl_AdjustRect(GetHwnd(), false, &rc);
int width = rc.right - rc.left,
height = rc.bottom - rc.top;
size_t nCount = m_pages.Count();
for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
wxNotebookPage *pPage = m_pages[nPage];
pPage->SetSize(rc.left, rc.top, width, height);
}
// unless we had already repainted everything, we now need to refresh
if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
{
// invalidate areas not covered by pages
RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
RefreshRect(wxRect(0, rc.top, rc.left, height), false);
RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
false);
RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.right, height),
false);
}
#if USE_NOTEBOOK_ANTIFLICKER
// subclass the spin control used by the notebook to scroll pages to
// prevent it from flickering on resize
if ( !m_hasSubclassedUpdown )
{
// iterate over all child windows to find spin button
for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
child;
child = ::GetWindow(child, GW_HWNDNEXT) )
{
wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);
// see if it exists, if no wxWindow found then assume it's the spin
// btn
if ( !childWindow )
{
// subclass the spin button to override WM_ERASEBKGND
if ( !gs_wndprocNotebookSpinBtn )
gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);
wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
m_hasSubclassedUpdown = true;
break;
}
}
}
#endif // USE_NOTEBOOK_ANTIFLICKER
event.Skip();
}
void wxNotebook::OnSelChange(wxNotebookEvent& event)
{
// is it our tab control?
if ( event.GetEventObject() == this )
{
int sel = event.GetOldSelection();
if ( sel != -1 )
m_pages[sel]->Show(false);
sel = event.GetSelection();
if ( sel != -1 )
{
wxNotebookPage *pPage = m_pages[sel];
pPage->Show(true);
// As per bug report:
// http://sourceforge.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
// we should not set the page focus (and thereby the focus for
// a child window) since it erroneously selects radio button controls and also
// breaks keyboard handling for a notebook's scroll buttons. So
// we always focus the notebook and not the page.
SetFocus();
}
else // no pages in the notebook, give the focus to itself
{
SetFocus();
}
m_nSelection = sel;
}
// we want to give others a chance to process this message as well
event.Skip();
}
bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
{
const MSG * const msg = (MSG *)wxmsg;
// intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
// TAB will be passed to the currently selected page, CTRL+TAB and
// CTRL+SHIFT+TAB will be processed by the notebook itself. do not
// intercept SHIFT+TAB. This goes to the parent of the notebook which will
// process it.
if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
msg->hwnd == GetHwnd() &&
(wxIsCtrlDown() || !wxIsShiftDown()) )
{
return MSWProcessMessage(wxmsg);
}
return false;
}
void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
{
if ( event.IsWindowChange() ) {
// change pages
AdvanceSelection(event.GetDirection());
}
else {
// we get this event in 3 cases
//
// a) one of our pages might have generated it because the user TABbed
// out from it in which case we should propagate the event upwards and
// our parent will take care of setting the focus to prev/next sibling
//
// or
//
// b) the parent panel wants to give the focus to us so that we
// forward it to our selected page. We can't deal with this in
// OnSetFocus() because we don't know which direction the focus came
// from in this case and so can't choose between setting the focus to
// first or last panel child
//
// or
//
// c) we ourselves (see MSWTranslateMessage) generated the event
//
wxWindow * const parent = GetParent();
// the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
if ( isFromParent || isFromSelf )
{
// no, it doesn't come from child, case (b) or (c): forward to a
// page but only if direction is backwards (TAB) or from ourselves,
if ( m_nSelection != -1 &&
(!event.GetDirection() || isFromSelf) )
{
// so that the page knows that the event comes from it's parent
// and is being propagated downwards
event.SetEventObject(this);
wxWindow *page = m_pages[m_nSelection];
if ( !page->GetEventHandler()->ProcessEvent(event) )
{
page->SetFocus();
}
//else: page manages focus inside it itself
}
else // otherwise set the focus to the notebook itself
{
SetFocus();
}
}
else
{
// it comes from our child, case (a), pass to the parent, but only
// if the direction is forwards. Otherwise set the focus to the
// notebook itself. The notebook is always the 'first' control of a
// page.
if ( !event.GetDirection() )
{
SetFocus();
}
else if ( parent )
{
event.SetCurrentFocus(this);
parent->GetEventHandler()->ProcessEvent(event);
}
}
}
}
#if wxUSE_UXTHEME
bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
{
wxUxThemeHandle theme(child ? child : this, L"TAB");
if ( !theme )
return false;
// get the notebook client rect (we're not interested in drawing tabs
// themselves)
wxRect r = GetPageSize();
if ( r.IsEmpty() )
return false;
RECT rc;
wxCopyRectToRECT(r, rc);
// map rect to the coords of the window we're drawing in
if ( child )
::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
// we have the content area (page size), but we need to draw all of the
// background for it to be aligned correctly
wxUxThemeEngine::Get()->GetThemeBackgroundExtent
(
theme,
(HDC) hDC,
9 /* TABP_PANE */,
0,
&rc,
&rc
);
wxUxThemeEngine::Get()->DrawThemeBackground
(
theme,
(HDC) hDC,
9 /* TABP_PANE */,
0,
&rc,
NULL
);
return true;
}
WXHBRUSH wxNotebook::QueryBgBitmap()
{
wxRect r = GetPageSize();
if ( r.IsEmpty() )
return 0;
WindowHDC hDC(GetHwnd());
MemoryHDC hDCMem(hDC);
CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
SelectInHDC selectBmp(hDCMem, hBmp);
if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
return 0;
return (WXHBRUSH)::CreatePatternBrush(hBmp);
}
void wxNotebook::UpdateBgBrush()
{
if ( m_hbrBackground )
::DeleteObject((HBRUSH)m_hbrBackground);
if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
{
m_hbrBackground = QueryBgBitmap();
}
else // no themes or we've got user-defined solid colour
{
m_hbrBackground = NULL;
}
}
WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
{
if ( m_hbrBackground )
{
// before drawing with the background brush, we need to position it
// correctly
RECT rc;
::GetWindowRect((HWND)hWnd, &rc);
::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
{
wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
}
return m_hbrBackground;
}
return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
}
bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
{
// solid background colour overrides themed background drawing
if ( !UseBgCol() && DoDrawBackground(hDC, child) )
return true;
// If we're using a solid colour (for example if we've switched off
// theming for this notebook), paint it
if (UseBgCol())
{
wxRect r = GetPageSize();
if ( r.IsEmpty() )
return false;
RECT rc;
wxCopyRectToRECT(r, rc);
// map rect to the coords of the window we're drawing in
if ( child )
::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
wxBrush brush(GetBackgroundColour());
HBRUSH hbr = GetHbrushOf(brush);
::FillRect((HDC) hDC, &rc, hbr);
return true;
}
return wxNotebookBase::MSWPrintChild(hDC, child);
}
#endif // wxUSE_UXTHEME
// Windows only: attempts to get colour for UX theme page background
wxColour wxNotebook::GetThemeBackgroundColour() const
{
#if wxUSE_UXTHEME
if (wxUxThemeEngine::Get())
{
wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
if (hTheme)
{
// This is total guesswork.
// See PlatformSDK\Include\Tmschema.h for values
COLORREF themeColor;
wxUxThemeEngine::Get()->GetThemeColor(
hTheme,
10 /* TABP_BODY */,
1 /* NORMAL */,
3821 /* FILLCOLORHINT */,
&themeColor);
/*
[DS] Workaround for WindowBlinds:
Some themes return a near black theme color using FILLCOLORHINT,
this makes notebook pages have an ugly black background and makes
text (usually black) unreadable. Retry again with FILLCOLOR.
This workaround potentially breaks appearance of some themes,
but in practice it already fixes some themes.
*/
if (themeColor == 1)
{
wxUxThemeEngine::Get()->GetThemeColor(
hTheme,
10 /* TABP_BODY */,
1 /* NORMAL */,
3802 /* FILLCOLOR */,
&themeColor);
}
return wxRGBToColour(themeColor);
}
}
#endif // wxUSE_UXTHEME
return GetBackgroundColour();
}
// ----------------------------------------------------------------------------
// wxNotebook base class virtuals
// ----------------------------------------------------------------------------
#if wxUSE_CONSTRAINTS
// override these 2 functions to do nothing: everything is done in OnSize
void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
{
// don't set the sizes of the pages - their correct size is not yet known
wxControl::SetConstraintSizes(false);
}
bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
{
return true;
}
#endif // wxUSE_CONSTRAINTS
// ----------------------------------------------------------------------------
// wxNotebook Windows message handlers
// ----------------------------------------------------------------------------
bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
WXWORD pos, WXHWND control)
{
// don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
// up-down control
if ( control )
return false;
return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
}
bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
{
wxNotebookEvent event(wxEVT_NULL, m_windowId);
NMHDR* hdr = (NMHDR *)lParam;
switch ( hdr->code ) {
case TCN_SELCHANGE:
event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
break;
case TCN_SELCHANGING:
event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
break;
default:
return wxControl::MSWOnNotify(idCtrl, lParam, result);
}
event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
event.SetOldSelection(m_nSelection);
event.SetEventObject(this);
event.SetInt(idCtrl);
bool processed = GetEventHandler()->ProcessEvent(event);
*result = !event.IsAllowed();
return processed;
}
#endif // wxUSE_NOTEBOOK
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?