#include "wx/msw/uxtheme.h"
#include "wx/msw/private.h"
#include "wx/msw/missing.h"
+#include "wx/msw/dc.h"
+
+// the values coincide with those in tmschema.h
+#define BP_GROUPBOX 4
+
+#define GBS_NORMAL 1
+
+#define TMT_FONT 210
// ----------------------------------------------------------------------------
// wxWin macros
if ( !MSWCreateControl(wxT("BUTTON"), label, pos, size) )
return false;
+ // Always use LTR layout. Otherwise, the label would be mirrored.
+ SetLayoutDirection(wxLayout_LeftToRight);
+
#ifndef __WXWINCE__
if (!wxSystemOptions::IsFalse(wxT("msw.staticbox.optimized-paint")))
Connect(wxEVT_PAINT, wxPaintEventHandler(wxStaticBox::OnPaint));
return true;
}
-wxBorder wxStaticBox::GetDefaultBorder() const
-{
- return wxBORDER_NONE;
-}
-
WXDWORD wxStaticBox::MSWGetStyle(long style, WXDWORD *exstyle) const
{
long styleWin = wxStaticBoxBase::MSWGetStyle(style, exstyle);
*exstyle = 0;
}
- return styleWin | BS_GROUPBOX;
+ styleWin |= BS_GROUPBOX;
+
+ if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
+ {
+ // Make sure label is on the right
+ styleWin |= BS_RIGHT;
+ }
+
+ return styleWin;
}
wxSize wxStaticBox::DoGetBestSize() const
return 0;
}
+ if ( nMsg == WM_UPDATEUISTATE )
+ {
+ // DefWindowProc() redraws just the static box text when it gets this
+ // message and it does it using the standard (blue in standard theme)
+ // colour and not our own label colour that we use in PaintForeground()
+ // resulting in the label mysteriously changing the colour when e.g.
+ // "Alt" is pressed anywhere in the window, see #12497.
+ //
+ // To avoid this we simply refresh the window forcing our own code
+ // redrawing the label in the correct colour to be called. This is
+ // inefficient but there doesn't seem to be anything else we can do.
+ //
+ // Notice that the problem is XP-specific and doesn't arise under later
+ // systems.
+ if ( m_hasFgCol && wxGetWinVersion() == wxWinVersion_XP )
+ Refresh();
+ }
+
return wxControl::MSWWindowProc(nMsg, wParam, lParam);
}
AutoHRGN hrgnRect(::CreateRectRgn(left, top, right, bottom));
if ( !hrgnRect )
{
- wxLogLastError(_T("CreateRectRgn()"));
+ wxLogLastError(wxT("CreateRectRgn()"));
return;
}
// we did it
// 3. this is backwards compatible behaviour and some people rely on it,
// see http://groups.google.com/groups?selm=4252E932.3080801%40able.es
- wxWindow *parent = GetParent();
- HBRUSH hbr = (HBRUSH)parent->MSWGetBgBrush(dc.GetHDC(), GetHWND());
+ wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+ HBRUSH hbr = MSWGetBgBrush(impl->GetHDC());
// if there is no special brush for painting this control, just use the
// solid background colour
wxBrush brush;
if ( !hbr )
{
- brush = wxBrush(parent->GetBackgroundColour());
+ brush = wxBrush(GetParent()->GetBackgroundColour());
hbr = GetHbrushOf(brush);
}
- ::FillRect(GetHdcOf(dc), &rc, hbr);
+ ::FillRect(GetHdcOf(*impl), &rc, hbr);
}
-void wxStaticBox::PaintForeground(wxDC& dc, const RECT& WXUNUSED(rc))
+void wxStaticBox::PaintForeground(wxDC& dc, const RECT& rc)
{
- MSWDefWindowProc(WM_PAINT, (WPARAM)GetHdcOf(dc), 0);
+ wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+ MSWDefWindowProc(WM_PAINT, (WPARAM)GetHdcOf(*impl), 0);
// when using XP themes, neither setting the text colour nor transparent
// background mode doesn't change anything: the static box def window proc
// still draws the label in its own colours, so we need to redraw the text
// ourselves if we have a non default fg colour
- if ( wxUxThemeEngine::GetIfActive() )
+ if ( m_hasFgCol && wxUxThemeEngine::GetIfActive() )
{
// draw over the text in default colour in our colour
- dc.SetFont(GetFont());
+ HDC hdc = GetHdcOf(*impl);
+ ::SetTextColor(hdc, GetForegroundColour().GetPixel());
+
+ const bool rtl = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft;
+ if ( rtl )
+ ::SetTextAlign(hdc, TA_RTLREADING | TA_RIGHT);
- HDC hdc = GetHdcOf(dc);
- if ( m_hasFgCol )
+ // Get dimensions of the label
+ const wxString label = GetLabel();
+
+ // choose the correct font
+ AutoHFONT font;
+ SelectInHDC selFont;
+ if ( m_hasFont )
{
- ::SetTextColor(hdc, GetForegroundColour().GetPixel());
+ selFont.Init(hdc, GetHfontOf(GetFont()));
}
- else
+ else // no font set, use the one set by the theme
{
wxUxThemeHandle hTheme(this, L"BUTTON");
- if (hTheme)
+ if ( hTheme )
{
- COLORREF col;
- wxUxThemeEngine::Get()->GetThemeColor(
- hTheme,
- 4 /* BP_GROUPBOX */,
- 1 /* GBS_NORMAL */,
- 3803 /* TMT_TEXTCOLOR */,
- &col);
-
- ::SetTextColor(hdc, col);
- }
- else
- {
- // can't open the theme - default to blue
- ::SetTextColor(hdc, 0x00D54600);
+ wxUxThemeFont themeFont;
+ if ( wxUxThemeEngine::Get()->GetThemeFont
+ (
+ hTheme,
+ hdc,
+ BP_GROUPBOX,
+ GBS_NORMAL,
+ TMT_FONT,
+ themeFont.GetPtr()
+ ) == S_OK )
+ {
+ font.Init(themeFont.GetLOGFONT());
+ if ( font )
+ selFont.Init(hdc, font);
+ }
}
}
- // FIXME: value of x is hardcoded as this is what it is on my system,
- // no idea if it's true everywhere
- // TODO: RTL?
- const int x = 9;
- const int y = dc.GetCharHeight();
- const wxString label = GetLabel();
+ // Get the font extent
+ int width, height;
+ dc.GetTextExtent(wxStripMenuCodes(label, wxStrip_Mnemonics),
+ &width, &height);
+
+ int x;
+ int y = height;
// first we need to correctly paint the background of the label
// as Windows ignores the brush offset when doing it
- RECT rc = { x, 0, GetSize().x, y };
- ::DrawText(hdc, label, label.length(), &rc,
- DT_SINGLELINE | DT_VCENTER | DT_CALCRECT);
+ //
+ // FIXME: value of x is hardcoded as this is what it is on my system,
+ // no idea if it's true everywhere
+ RECT dimensions = {0, 0, 0, y};
+ if ( !rtl )
+ {
+ x = 9;
+ dimensions.left = x;
+ dimensions.right = x + width;
+ }
+ else
+ {
+ x = rc.right - 7;
+ dimensions.left = x - width;
+ dimensions.right = x;
+ }
// need to adjust the rectangle to cover all the label background
- rc.left -= 2;
- rc.right += 2;
- rc.bottom += 2;
- PaintBackground(dc, rc);
+ dimensions.left -= 2;
+ dimensions.right += 2;
+ dimensions.bottom += 2;
+
+ if ( UseBgCol() )
+ {
+ // our own background colour should be used for the background of
+ // the label: this is consistent with the behaviour under pre-XP
+ // systems (i.e. without visual themes) and generally makes sense
+ wxBrush brush = wxBrush(GetBackgroundColour());
+ wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+ ::FillRect(GetHdcOf(*impl), &dimensions, GetHbrushOf(brush));
+ }
+ else // paint parent background
+ {
+ PaintBackground(dc, dimensions);
+ }
+
+ UINT drawTextFlags = DT_SINGLELINE | DT_VCENTER;
+
+ // determine the state of UI queues to draw the text correctly under XP
+ // and later systems
+ static const bool isXPorLater = wxGetWinVersion() >= wxWinVersion_XP;
+ if ( isXPorLater )
+ {
+ if ( ::SendMessage(GetHwnd(), WM_QUERYUISTATE, 0, 0) &
+ UISF_HIDEACCEL )
+ {
+ drawTextFlags |= DT_HIDEPREFIX;
+ }
+ }
// now draw the text
- RECT rc2 = { x, 0, GetSize().x, y };
- ::DrawText(hdc, label, label.length(), &rc2,
- DT_SINGLELINE | DT_VCENTER);
+ if ( !rtl )
+ {
+ RECT rc2 = { x, 0, x + width, y };
+ ::DrawText(hdc, label.wx_str(), label.length(), &rc2,
+ drawTextFlags);
+ }
+ else // RTL
+ {
+ RECT rc2 = { x, 0, x - width, y };
+ ::DrawText(hdc, label.wx_str(), label.length(), &rc2,
+ drawTextFlags | DT_RTLREADING);
+ }
}
}
dc.Blit(border, 0, rc.right - border, borderTop,
&memdc, border, 0);
// bottom
- dc.Blit(border, rc.bottom - border, rc.right - border, rc.bottom,
+ dc.Blit(border, rc.bottom - border, rc.right - border, border,
&memdc, border, rc.bottom - border);
// left
dc.Blit(0, 0, border, rc.bottom,
&memdc, 0, 0);
- // right
- dc.Blit(rc.right - border, 0, rc.right, rc.bottom,
- &memdc, rc.right - border, 0);
+ // right (note that upper and bottom right corners were already part of the
+ // first two blits so we shouldn't overwrite them here to avoi flicker)
+ dc.Blit(rc.right - border, borderTop,
+ border, rc.bottom - borderTop - border,
+ &memdc, rc.right - border, borderTop);
// create the region excluding box children
// and also the box itself
MSWGetRegionWithoutSelf((WXHRGN) hrgn, rc.right, rc.bottom);
- HDCClipper clipToBg(GetHdcOf(dc), hrgn);
+ wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+ HDCClipper clipToBg(GetHdcOf(*impl), hrgn);
// paint the inside of the box (excluding box itself and child controls)
PaintBackground(dc, rc);