#if wxUSE_NOTEBOOK
-// wxWindows
+// wxWidgets
#ifndef WX_PRECOMP
#include "wx/string.h"
+ #include "wx/dc.h"
#endif // WX_PRECOMP
#include "wx/log.h"
#include "wx/msw/private.h"
-// Windows standard headers
-#ifndef __WIN95__
- #error "wxNotebook is only supported Windows 95 and above"
-#endif //Win95
-
-#include <windowsx.h> // for SetWindowFont
+#include <windowsx.h>
#ifdef __GNUWIN32_OLD__
#include "wx/msw/gnuwin32/extra.h"
#endif
-#if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__))
+#if !(defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__))
#include <commctrl.h>
#endif
#include "wx/msw/winundef.h"
#if wxUSE_UXTHEME
-#include "wx/msw/uxtheme.h"
-
-#include "wx/radiobut.h"
-#include "wx/radiobox.h"
-#include "wx/checkbox.h"
-#include "wx/bmpbuttn.h"
-#include "wx/statline.h"
-#include "wx/statbox.h"
-#include "wx/stattext.h"
-#include "wx/slider.h"
-#include "wx/scrolwin.h"
-#include "wx/panel.h"
+ #include "wx/msw/uxtheme.h"
#endif
// ----------------------------------------------------------------------------
wxFLAGS_MEMBER(wxBORDER_RAISED)
wxFLAGS_MEMBER(wxBORDER_STATIC)
wxFLAGS_MEMBER(wxBORDER_NONE)
-
+
// old style border flags
wxFLAGS_MEMBER(wxSIMPLE_BORDER)
wxFLAGS_MEMBER(wxSUNKEN_BORDER)
wxEVENT_PROPERTY( PageChanged , wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED , wxNotebookEvent )
wxPROPERTY_COLLECTION( PageInfos , wxNotebookPageInfoList , wxNotebookPageInfo* , AddPageInfo , GetPageInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
- wxPROPERTY_FLAGS( WindowStyle , wxNotebookStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
+ wxPROPERTY_FLAGS( WindowStyle , wxNotebookStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
wxEND_PROPERTIES_TABLE()
wxBEGIN_HANDLERS_TABLE(wxNotebook)
wxEND_HANDLERS_TABLE()
-wxCONSTRUCTOR_5( wxNotebook , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle)
+wxCONSTRUCTOR_5( wxNotebook , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle)
wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo)
- wxREADONLY_PROPERTY( Page , wxNotebookPage* , GetPage , , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
+ wxREADONLY_PROPERTY( Page , wxNotebookPage* , GetPage , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
wxREADONLY_PROPERTY( Text , wxString , GetText , wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
wxREADONLY_PROPERTY( Selected , bool , GetSelected , false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
wxREADONLY_PROPERTY( ImageId , int , GetImageId , -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo)
wxEND_HANDLERS_TABLE()
-wxCONSTRUCTOR_4( wxNotebookPageInfo , wxNotebookPage* , Page , wxString , Text , bool , Selected , int , ImageId )
+wxCONSTRUCTOR_4( wxNotebookPageInfo , wxNotebookPage* , Page , wxString , Text , bool , Selected , int , ImageId )
#else
IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
{
m_imageList = NULL;
m_nSelection = -1;
+
+#if wxUSE_UXTHEME
+ m_hbrBackground = NULL;
+#endif // wxUSE_UXTHEME
}
// default for dynamic class
long style,
const wxString& name)
{
- // Does ComCtl32 support non-top tabs?
- int verComCtl32 = wxApp::GetComCtl32Version();
- if ( verComCtl32 < 470 || verComCtl32 >= 600 )
+ // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
+ // control is simply not rendered correctly), so disable them in this case
+ const int verComCtl32 = wxApp::GetComCtl32Version();
+ if ( verComCtl32 == 600 )
{
- if (style & wxNB_BOTTOM)
- style &= ~wxNB_BOTTOM;
-
- if (style & wxNB_LEFT)
- style &= ~wxNB_LEFT;
-
- if (style & wxNB_RIGHT)
- style &= ~wxNB_RIGHT;
+ // check if we use themes at all -- if we don't, we're still ok
+#if wxUSE_UXTHEME
+ if ( wxUxThemeEngine::GetIfActive() )
+#endif
+ {
+ style &= ~(wxNB_BOTTOM | wxNB_LEFT | wxNB_RIGHT);
+ }
}
-
+
if ( !CreateControl(parent, id, pos, size, style | wxTAB_TRAVERSAL,
wxDefaultValidator, name) )
return false;
if ( !MSWCreateControl(WC_TABCONTROL, wxEmptyString, pos, size) )
return false;
- SetBackgroundColour(wxColour(::GetSysColor(COLOR_BTNFACE)));
-
return true;
}
return tabStyle;
}
+wxNotebook::~wxNotebook()
+{
+#if wxUSE_UXTHEME
+ if ( m_hbrBackground )
+ ::DeleteObject((HBRUSH)m_hbrBackground);
+#endif // wxUSE_UXTHEME
+}
+
// ----------------------------------------------------------------------------
// wxNotebook accessors
// ----------------------------------------------------------------------------
int wxNotebook::SetSelection(size_t nPage)
{
- wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
+ wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
if ( int(nPage) != m_nSelection )
{
wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
{
wxSize sizeTotal = sizePage;
-
- // We need to make getting tab size part of the wxWindows API.
+
+ // We need to make getting tab size part of the wxWidgets API.
wxSize tabSize(0, 0);
if (GetPageCount() > 0)
{
// get the page size from the notebook size
GetSize((int *)&rc.right, (int *)&rc.bottom);
- TabCtrl_AdjustRect(m_hwnd, false, &rc);
- page->SetSize(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
+ // This check is to work around a bug in TabCtrl_AdjustRect which will
+ // cause a crash on win2k, or on XP with themes disabled, if the
+ // wxNB_MULTILINE style is used and the rectangle is very small, (such as
+ // when the notebook is first created.) The value of 20 is just
+ // arbitrarily chosen, if there is a better way to determine this value
+ // then please do so. --RD
+ if (rc.right > 20 && rc.bottom > 20)
+ {
+ TabCtrl_AdjustRect(m_hwnd, false, &rc);
+ page->SetSize(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
+ }
}
// ----------------------------------------------------------------------------
}
else // notebook still not empty
{
- // change the selected page if it was deleted or became invalid
- int selNew;
- if ( m_nSelection == int(GetPageCount()) )
+ int selNew = TabCtrl_GetCurSel(m_hwnd);
+ if (selNew != -1)
{
- // last page deleted, make the new last page the new selection
- selNew = m_nSelection - 1;
+ // No selection change, just refresh the current selection.
+ // Because it could be that the slection index changed
+ // we need to update it.
+ // Note: this does not mean the selection it self changed.
+ m_nSelection = selNew;
+ m_pages[m_nSelection]->Refresh();
}
- else if ( int(nPage) <= m_nSelection )
+ else if (int(nPage) == m_nSelection)
{
- // we must show another page, even if it has the same index
- selNew = m_nSelection;
- }
- else // nothing changes for the currently selected page
- {
- selNew = -1;
-
- // we still must refresh the current page: this needs to be done
- // for some unknown reason if the tab control shows the up-down
- // control (i.e. when there are too many pages) -- otherwise after
- // deleting a page nothing at all is shown
- if (m_nSelection >= 0)
- m_pages[m_nSelection]->Refresh();
- }
+ // The selection was deleted.
+
+ // Determine new selection.
+ if (m_nSelection == int(GetPageCount()))
+ selNew = m_nSelection - 1;
+ else
+ selNew = m_nSelection;
- if ( selNew != -1 )
- {
// m_nSelection must be always valid so reset it before calling
// SetSelection()
m_nSelection = -1;
SetSelection(selNew);
}
+ else
+ {
+ wxFAIL; // Windows did not behave ok.
+ }
}
return pageRemoved;
m_nSelection = -1;
+ InvalidateBestSize();
return true;
}
wxASSERT_MSG( pPage->GetParent() == this,
_T("notebook pages must have notebook as parent") );
-#if wxUSE_UXTHEME && wxUSE_UXTHEME_AUTO
- static bool g_TestedForTheme = false;
- static bool g_UseTheme = false;
- if (!g_TestedForTheme)
- {
- int commCtrlVersion = wxTheApp->GetComCtl32Version() ;
-
- g_UseTheme = (commCtrlVersion >= 600);
- g_TestedForTheme = true;
- }
-
- // Automatically apply the theme background,
- // changing the colour of the panel to match the
- // tab page colour. This won't work well with all
- // themes but it's a start.
- if (g_UseTheme && wxUxThemeEngine::Get() && pPage->IsKindOf(CLASSINFO(wxPanel)))
- {
- ApplyThemeBackground(pPage, GetThemeBackgroundColour());
- }
-#endif
-
// add a new tab to the control
// ----------------------------
tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
}
+ // hide the page: unless it is selected, it shouldn't be shown (and if it
+ // is selected it will be shown later)
+ HWND hwnd = GetWinHwnd(pPage);
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
+
+ // this updates internal flag too -- otherwise it would get out of sync
+ // with the real state
+ pPage->Show(false);
+
+
// fit the notebook page to the tab control's display area: this should be
// done before adding it to the notebook or TabCtrl_InsertItem() will
// change the notebooks size itself!
// succeeded: save the pointer to the page
m_pages.Insert(pPage, nPage);
- // for the first page (only) we need to adjust the size again because the
- // notebook size changed: the tabs which hadn't been there before are now
- // shown
- if ( m_pages.GetCount() == 1 )
+ // we may need to adjust the size again if the notebook size changed:
+ // normally this only happens for the first page we add (the tabs which
+ // hadn't been there before are now shown) but for a multiline notebook it
+ // can happen for any page at all as a new row could have been started
+ if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
{
AdjustPageSize(pPage);
}
- // hide the page: unless it is selected, it shouldn't be shown (and if it
- // is selected it will be shown later)
- HWND hwnd = GetWinHwnd(pPage);
- SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
-
- // this updates internal flag too -- otherwise it would get out of sync
- // with the real state
- pPage->Show(false);
-
-
// now deal with the selection
// ---------------------------
if ( selNew != -1 )
SetSelection(selNew);
+ InvalidateBestSize();
return true;
}
void wxNotebook::OnSize(wxSizeEvent& event)
{
+#if wxUSE_UXTHEME
+ UpdateBgBrush();
+#endif // wxUSE_UXTHEME
+
// fit the notebook page to the tab control's display area
RECT rc;
rc.left = rc.top = 0;
GetSize((int *)&rc.right, (int *)&rc.bottom);
+ // 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;
+ }
+ }
+
TabCtrl_AdjustRect(m_hwnd, false, &rc);
int width = rc.right - rc.left,
}
}
+#if wxUSE_UXTHEME
+
+WXHANDLE wxNotebook::QueryBgBitmap(wxWindow *win)
+{
+ RECT rc;
+ GetWindowRect(GetHwnd(), &rc);
+
+ WindowHDC hDC(GetHwnd());
+ MemoryHDC hDCMem(hDC);
+ CompatibleBitmap hBmp(hDC, rc.right - rc.left, rc.bottom - rc.top);
+
+ SelectInHDC selectBmp(hDCMem, hBmp);
+
+ ::SendMessage(GetHwnd(), WM_PRINTCLIENT,
+ (WPARAM)(HDC)hDCMem,
+ PRF_ERASEBKGND | PRF_CLIENT | PRF_NONCLIENT);
+
+ if ( win )
+ {
+ RECT rc2;
+ ::GetWindowRect(GetHwndOf(win), &rc2);
+
+ COLORREF c = ::GetPixel(hDCMem, rc2.left - rc.left, rc2.top - rc.top);
+
+ return (WXHANDLE)c;
+ }
+ else // we are asked to create the brush
+ {
+ return (WXHANDLE)::CreatePatternBrush(hBmp);
+ }
+}
+
+void wxNotebook::UpdateBgBrush()
+{
+ if ( m_hbrBackground )
+ ::DeleteObject((HBRUSH)m_hbrBackground);
+
+ if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
+ {
+ m_hbrBackground = (WXHBRUSH)QueryBgBitmap();
+ }
+ else // no themes
+ {
+ m_hbrBackground = NULL;
+ }
+}
+
+WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, wxWindow *win)
+{
+ if ( m_hbrBackground )
+ {
+ // before drawing with the background brush, we need to position it
+ // correctly
+ RECT rc;
+ ::GetWindowRect(GetHwndOf(win), &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, win);
+}
+
+wxColour wxNotebook::MSWGetBgColourForChild(wxWindow *win)
+{
+ if ( m_hasBgCol )
+ return GetBackgroundColour();
+
+ if ( !wxUxThemeEngine::GetIfActive() )
+ return wxNullColour;
+
+ COLORREF c = (COLORREF)QueryBgBitmap(win);
+
+ return c == CLR_INVALID ? wxNullColour : wxRGBToColour(c);
+}
+
+#endif // wxUSE_UXTHEME
+
// ----------------------------------------------------------------------------
// wxNotebook base class virtuals
// ----------------------------------------------------------------------------
return processed;
}
-// Windows only: attempts to get colour for UX theme page background
-wxColour wxNotebook::GetThemeBackgroundColour()
-{
-#if wxUSE_UXTHEME
- if (wxUxThemeEngine::Get())
- {
- wxUxThemeHandle hTheme(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
- );
-
- wxColour colour(GetRValue(themeColor), GetGValue(themeColor), GetBValue(themeColor));
- return colour;
- }
- }
-#endif // wxUSE_UXTHEME
-
- return GetBackgroundColour();
-}
-
-// Windows only: attempts to apply the UX theme page background to this page
-#if wxUSE_UXTHEME
-void wxNotebook::ApplyThemeBackground(wxWindow* window, const wxColour& colour)
-#else
-void wxNotebook::ApplyThemeBackground(wxWindow*, const wxColour&)
-#endif
-{
-#if wxUSE_UXTHEME
- // Don't set the background for buttons since this will
- // switch it into ownerdraw mode
- if (window->IsKindOf(CLASSINFO(wxButton)) && !window->IsKindOf(CLASSINFO(wxBitmapButton)))
- // This is essential, otherwise you'll see dark grey
- // corners in the buttons.
- ((wxButton*)window)->wxControl::SetBackgroundColour(colour);
- else if (window->IsKindOf(CLASSINFO(wxStaticText)) ||
- window->IsKindOf(CLASSINFO(wxStaticBox)) ||
- window->IsKindOf(CLASSINFO(wxStaticLine)) ||
- window->IsKindOf(CLASSINFO(wxRadioButton)) ||
- window->IsKindOf(CLASSINFO(wxRadioBox)) ||
- window->IsKindOf(CLASSINFO(wxCheckBox)) ||
- window->IsKindOf(CLASSINFO(wxBitmapButton)) ||
- window->IsKindOf(CLASSINFO(wxSlider)) ||
- window->IsKindOf(CLASSINFO(wxPanel)) ||
- (window->IsKindOf(CLASSINFO(wxNotebook)) && (window != this)) ||
- window->IsKindOf(CLASSINFO(wxScrolledWindow))
- )
- {
- window->SetBackgroundColour(colour);
- }
-
- for ( wxWindowList::compatibility_iterator node = window->GetChildren().GetFirst(); node; node = node->GetNext() )
- {
- wxWindow *child = node->GetData();
- ApplyThemeBackground(child, colour);
- }
-#endif
-}
-
-long wxNotebook::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
-{
- static bool g_TestedForTheme = false;
- static bool g_UseTheme = false;
- switch ( nMsg )
- {
- case WM_ERASEBKGND:
- {
- if (!g_TestedForTheme)
- {
- int commCtrlVersion = wxTheApp->GetComCtl32Version() ;
-
- g_UseTheme = (commCtrlVersion >= 600);
- g_TestedForTheme = true;
- }
-
- // If using XP themes, it seems we can get away
- // with not drawing a background, which reduces flicker.
- if (g_UseTheme)
- return true;
- }
- }
-
- return wxControl::MSWWindowProc(nMsg, wParam, lParam);
-}
-
-
#endif // wxUSE_NOTEBOOK