#if wxUSE_NOTEBOOK
-#include "wx/notebook.h"
+#include "wx/notebook.h"
#ifndef WX_PRECOMP
- #include "wx/string.h"
- #include "wx/dc.h"
- #include "wx/log.h"
- #include "wx/event.h"
- #include "wx/app.h"
+ #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
+ #include "wx/string.h"
+ #include "wx/dc.h"
+ #include "wx/log.h"
+ #include "wx/event.h"
+ #include "wx/app.h"
+ #include "wx/dcclient.h"
+ #include "wx/dcmemory.h"
+ #include "wx/control.h"
#endif // WX_PRECOMP
-#include "wx/imaglist.h"
-#include "wx/control.h"
-#include "wx/sysopt.h"
-#include "wx/dcclient.h"
-#include "wx/dcmemory.h"
+#include "wx/imaglist.h"
+#include "wx/sysopt.h"
-#include "wx/msw/private.h"
-
-#include <windowsx.h>
-
-#include <commctrl.h>
+#include "wx/msw/private.h"
+#include <windowsx.h>
#include "wx/msw/winundef.h"
#if wxUSE_UXTHEME
#endif // USE_NOTEBOOK_ANTIFLICKER
+// ----------------------------------------------------------------------------
+// global functions
+// ----------------------------------------------------------------------------
+
+static bool HasTroubleWithNonTopTabs()
+{
+ const int verComCtl32 = wxApp::GetComCtl32Version();
+
+ // 600 is XP, 616 is Vista -- and both have a problem with tabs not on top
+ // (but don't just test for >= 600 as Microsoft might decide to fix it in
+ // later versions, who knows...)
+ return verComCtl32 >= 600 && verComCtl32 <= 616;
+}
+
// ----------------------------------------------------------------------------
// event table
// ----------------------------------------------------------------------------
void wxNotebook::Init()
{
m_imageList = NULL;
- m_nSelection = -1;
+ m_nSelection = wxNOT_FOUND;
#if wxUSE_UXTHEME
m_hbrBackground = NULL;
long style,
const wxString& name)
{
+ if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
+ {
+#if defined(__POCKETPC__)
+ style |= wxBK_BOTTOM | wxNB_FLAT;
+#else
+ style |= wxBK_TOP;
+#endif
+ }
+
#ifdef __WXWINCE__
// Not sure why, but without this style, there is no border
// around the notebook tabs.
#endif
#if !wxUSE_UXTHEME
- // ComCtl32 notebook tabs simply don't work unless they're on top if we have uxtheme, we can
- // work around it later (after control creation), but if we don't have uxtheme, we have to clear
- // those styles
- const int verComCtl32 = wxApp::GetComCtl32Version();
- if ( verComCtl32 == 600 )
+ // ComCtl32 notebook tabs simply don't work unless they're on top if we
+ // have uxtheme, we can work around it later (after control creation), but
+ // if we have been compiled without uxtheme support, we have to clear those
+ // styles
+ if ( HasTroubleWithNonTopTabs() )
{
style &= ~(wxBK_BOTTOM | wxBK_LEFT | wxBK_RIGHT);
}
#endif //wxUSE_UXTHEME
+#if defined(__WINE__) && wxUSE_UNICODE
+ LPCTSTR className = L"SysTabControl32";
+#else
LPCTSTR className = WC_TABCONTROL;
+#endif
#if USE_NOTEBOOK_ANTIFLICKER
// SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
// comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
// control is simply not rendered correctly), so we disable themes
// if possible, otherwise we simply clear the styles.
- // It's probably not possible to have UXTHEME without ComCtl32 6 or better, but lets
- // check it anyway.
- const int verComCtl32 = wxApp::GetComCtl32Version();
- if ( verComCtl32 == 600 )
+ if ( HasTroubleWithNonTopTabs() &&
+ (style & (wxBK_BOTTOM | wxBK_LEFT | wxBK_RIGHT)) )
{
// check if we use themes at all -- if we don't, we're still okay
- if ( wxUxThemeEngine::GetIfActive() && (style & (wxBK_BOTTOM|wxBK_LEFT|wxBK_RIGHT)))
+ if ( wxUxThemeEngine::GetIfActive() )
{
- wxUxThemeEngine::GetIfActive()->SetWindowTheme((HWND)this->GetHandle(), L"", L"");
- SetBackgroundColour(GetThemeBackgroundColour()); //correct the background color for the new non-themed control
+ wxUxThemeEngine::GetIfActive()->SetWindowTheme(GetHwnd(), L"", L"");
+
+ // correct the background color for the new non-themed control
+ SetBackgroundColour(GetThemeBackgroundColour());
}
}
#endif // wxUSE_UXTHEME
{
wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
- if ( int(nPage) != m_nSelection )
+ if ( m_nSelection == wxNOT_FOUND || nPage != (size_t)m_nSelection )
{
- wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId);
- event.SetSelection(nPage);
- event.SetOldSelection(m_nSelection);
- event.SetEventObject(this);
- if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
+ if ( SendPageChangingEvent(nPage) )
{
// program allows the page change
- event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
- (void)GetEventHandler()->ProcessEvent(event);
+ SendPageChangedEvent(m_nSelection, nPage);
- TabCtrl_SetCurSel(GetHwnd(), nPage);
+ TabCtrl_SetCurSel(GetHwnd(), nPage);
}
}
return m_nSelection;
}
+void wxNotebook::UpdateSelection(int selNew)
+{
+ if ( m_nSelection != wxNOT_FOUND )
+ m_pages[m_nSelection]->Show(false);
+
+ if ( selNew != wxNOT_FOUND )
+ {
+ wxNotebookPage *pPage = m_pages[selNew];
+ pPage->Show(true);
+ }
+
+ // Changing the page should give the focus to it but, as per bug report
+ // http://sf.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
+ // we should not set the focus to it directly since it erroneously
+ // selects radio buttons and breaks keyboard handling for a notebook's
+ // scroll buttons. So give focus to the notebook and not the page.
+
+ // but don't do this is the notebook is hidden
+ if ( ::IsWindowVisible(GetHwnd()) )
+ SetFocus();
+
+ m_nSelection = selNew;
+}
+
+int wxNotebook::ChangeSelection(size_t nPage)
+{
+ wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
+
+ if ( m_nSelection == wxNOT_FOUND || nPage != (size_t)m_nSelection )
+ {
+ TabCtrl_SetCurSel(GetHwnd(), nPage);
+
+ UpdateSelection(nPage);
+ }
+
+ return m_nSelection;
+}
+
bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
{
wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
TC_ITEM tcItem;
tcItem.mask = TCIF_TEXT;
- tcItem.pszText = (wxChar *)strText.c_str();
+ tcItem.pszText = (wxChar *)strText.wx_str();
if ( !HasFlag(wxNB_MULTILINE) )
return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
TC_ITEM tcItem;
tcItem.mask = TCIF_IMAGE;
- return TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) ? tcItem.iImage : wxNOT_FOUND;
+ return TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) ? tcItem.iImage
+ : wxNOT_FOUND;
}
bool wxNotebook::SetPageImage(size_t nPage, int nImage)
if ( imageList )
{
- (void) TabCtrl_SetImageList(GetHwnd(), (HIMAGELIST)imageList->GetHIMAGELIST());
+ (void) TabCtrl_SetImageList(GetHwnd(), GetHimagelistOf(imageList));
}
}
wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
{
+ // we can't use TabCtrl_AdjustRect here because it only works for wxNB_TOP
wxSize sizeTotal = sizePage;
- // We need to make getting tab size part of the wxWidgets API.
wxSize tabSize;
- if (GetPageCount() > 0)
+ if ( GetPageCount() > 0 )
{
RECT rect;
- TabCtrl_GetItemRect((HWND) GetHWND(), 0, & rect);
+ TabCtrl_GetItemRect(GetHwnd(), 0, &rect);
tabSize.x = rect.right - rect.left;
tabSize.y = rect.bottom - rect.top;
}
- if ( HasFlag(wxBK_LEFT) || HasFlag(wxBK_RIGHT) )
+
+ // add an extra margin in both directions
+ const int MARGIN = 8;
+ if ( IsVertical() )
{
- sizeTotal.x += tabSize.x + 7;
- sizeTotal.y += 7;
+ sizeTotal.x += MARGIN;
+ sizeTotal.y += tabSize.y + MARGIN;
}
- else
+ else // horizontal layout
{
- sizeTotal.x += 7;
- sizeTotal.y += tabSize.y + 7;
+ sizeTotal.x += tabSize.x + MARGIN;
+ sizeTotal.y += MARGIN;
}
return sizeTotal;
if ( m_pages.IsEmpty() )
{
// no selection any more, the notebook becamse empty
- m_nSelection = -1;
+ m_nSelection = wxNOT_FOUND;
}
else // notebook still not empty
{
int selNew = TabCtrl_GetCurSel(GetHwnd());
- if (selNew != -1)
+ if ( selNew != wxNOT_FOUND )
{
// No selection change, just refresh the current selection.
// Because it could be that the slection index changed
// m_nSelection must be always valid so reset it before calling
// SetSelection()
- m_nSelection = -1;
+ m_nSelection = wxNOT_FOUND;
SetSelection(selNew);
}
else
TabCtrl_DeleteAllItems(GetHwnd());
- m_nSelection = -1;
+ m_nSelection = wxNOT_FOUND;
InvalidateBestSize();
return true;
if ( !strText.empty() )
{
tcItem.mask |= TCIF_TEXT;
- tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
+ tcItem.pszText = (wxChar *)strText.wx_str(); // const_cast
}
// hide the page: unless it is selected, it shouldn't be shown (and if it
return false;
}
+ // need to update the bg brush when the first page is added
+ // so the first panel gets the correct themed background
+ if ( m_pages.empty() )
+ {
+#if wxUSE_UXTHEME
+ UpdateBgBrush();
+#endif // wxUSE_UXTHEME
+ }
+
// succeeded: save the pointer to the page
m_pages.Insert(pPage, nPage);
// some page should be selected: either this one or the first one if there
// is still no selection
- int selNew = -1;
+ int selNew = wxNOT_FOUND;
if ( bSelect )
selNew = nPage;
- else if ( m_nSelection == -1 )
+ else if ( m_nSelection == wxNOT_FOUND )
selNew = 0;
- if ( selNew != -1 )
+ if ( selNew != wxNOT_FOUND )
SetSelection(selNew);
InvalidateBestSize();
*flags = 0;
if ((hitTestInfo.flags & TCHT_NOWHERE) == TCHT_NOWHERE)
- *flags |= wxNB_HITTEST_NOWHERE;
+ *flags |= wxBK_HITTEST_NOWHERE;
if ((hitTestInfo.flags & TCHT_ONITEM) == TCHT_ONITEM)
- *flags |= wxNB_HITTEST_ONITEM;
+ *flags |= wxBK_HITTEST_ONITEM;
if ((hitTestInfo.flags & TCHT_ONITEMICON) == TCHT_ONITEMICON)
- *flags |= wxNB_HITTEST_ONICON;
+ *flags |= wxBK_HITTEST_ONICON;
if ((hitTestInfo.flags & TCHT_ONITEMLABEL) == TCHT_ONITEMLABEL)
- *flags |= wxNB_HITTEST_ONLABEL;
+ *flags |= wxBK_HITTEST_ONLABEL;
+ if ( item == wxNOT_FOUND && GetPageSize().Contains(pt) )
+ *flags |= wxBK_HITTEST_ONPAGE;
}
return item;
wxBitmap bmp(rc.right, rc.bottom);
memdc.SelectObject(bmp);
+ const wxLayoutDirection dir = dc.GetLayoutDirection();
+ memdc.SetLayoutDirection(dir);
+
// if there is no special brush just use the solid background colour
#if wxUSE_UXTHEME
HBRUSH hbr = (HBRUSH)m_hbrBackground;
MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);
- dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
+ // For some reason in RTL mode, source offset has to be -1, otherwise the
+ // right border (physical) remains unpainted.
+ const wxCoord ofs = dir == wxLayout_RightToLeft ? -1 : 0;
+ dc.Blit(ofs, 0, rc.right, rc.bottom, &memdc, ofs, 0);
}
#endif // USE_NOTEBOOK_ANTIFLICKER
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);
- }
-
- // Changing the page should give the focus to it but, as per bug report
- // http://sf.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
- // we should not set the focus to it directly since it erroneously
- // selects radio buttons and breaks keyboard handling for a notebook's
- // scroll buttons. So give focus to the notebook and not the page.
-
- // but don't do this is the notebook is hidden
- if ( ::IsWindowVisible(GetHwnd()) )
- 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()) )
+ // is it our tab control?
+ if ( event.GetEventObject() == this )
{
- return MSWProcessMessage(wxmsg);
+ UpdateSelection(event.GetSelection());
}
- return false;
+ // we want to give others a chance to process this message as well
+ event.Skip();
}
void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
{
// 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 &&
+ if ( m_nSelection != wxNOT_FOUND &&
(!event.GetDirection() || isFromSelf) )
{
// so that the page knows that the event comes from it's parent
if (hTheme)
{
// This is total guesswork.
- // See PlatformSDK\Include\Tmschema.h for values
+ // See PlatformSDK\Include\Tmschema.h for values.
+ // JACS: can also use 9 (TABP_PANE)
COLORREF themeColor;
- wxUxThemeEngine::Get()->GetThemeColor(
+ bool success = (S_OK == wxUxThemeEngine::Get()->GetThemeColor(
hTheme,
10 /* TABP_BODY */,
1 /* NORMAL */,
3821 /* FILLCOLORHINT */,
- &themeColor);
+ &themeColor));
+ if (!success)
+ return GetBackgroundColour();
/*
[DS] Workaround for WindowBlinds:
&themeColor);
}
- return wxRGBToColour(themeColor);
+ wxColour colour = wxRGBToColour(themeColor);
+
+ // Under Vista, the tab background colour is reported incorrectly.
+ // So for the default theme at least, hard-code the colour to something
+ // that will blend in.
+
+ static int s_AeroStatus = -1;
+ if (s_AeroStatus == -1)
+ {
+ WCHAR szwThemeFile[1024];
+ WCHAR szwThemeColor[256];
+ if (S_OK == wxUxThemeEngine::Get()->GetCurrentThemeName(szwThemeFile, 1024, szwThemeColor, 256, NULL, 0))
+ {
+ wxString themeFile(szwThemeFile), themeColor(szwThemeColor);
+ if (themeFile.Find(wxT("Aero")) != -1 && themeColor == wxT("NormalColor"))
+ s_AeroStatus = 1;
+ else
+ s_AeroStatus = 0;
+ }
+ else
+ s_AeroStatus = 0;
+ }
+
+ if (s_AeroStatus == 1)
+ colour = wxColour(255, 255, 255);
+
+ return colour;
}
}
#endif // wxUSE_UXTHEME