From 687192d86a52b2779ff0c73a32403c1a0a257385 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 24 Dec 2017 20:07:05 +0100 Subject: [PATCH] Add support for arbitrary window labels in wxStaticBox to wxMSW Just reparent the label window and position it accordingly and, also, avoid painting over it in MSW-specific code. --- include/wx/msw/statbox.h | 20 ++++++++++++ interface/wx/statbox.h | 2 +- src/msw/statbox.cpp | 66 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/include/wx/msw/statbox.h b/include/wx/msw/statbox.h index 87ad173cba..89eb8fcdde 100644 --- a/include/wx/msw/statbox.h +++ b/include/wx/msw/statbox.h @@ -27,6 +27,16 @@ public: Create(parent, id, label, pos, size, style, name); } + wxStaticBox(wxWindow* parent, wxWindowID id, + wxWindow* label, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString &name = wxStaticBoxNameStr) + { + Create(parent, id, label, pos, size, style, name); + } + bool Create(wxWindow *parent, wxWindowID id, const wxString& label, const wxPoint& pos = wxDefaultPosition, @@ -34,6 +44,13 @@ public: long style = 0, const wxString& name = wxStaticBoxNameStr); + bool Create(wxWindow *parent, wxWindowID id, + wxWindow* label, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxStaticBoxNameStr); + /// Implementation only virtual void GetBordersForSizer(int *borderTop, int *borderOther) const wxOVERRIDE; @@ -66,5 +83,8 @@ protected: wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxStaticBox); }; +// Indicate that we have the ctor overload taking wxWindow as label. +#define wxHAS_WINDOW_LABEL_IN_STATIC_BOX + #endif // _WX_MSW_STATBOX_H_ diff --git a/interface/wx/statbox.h b/interface/wx/statbox.h index d57949ee9b..d7aae13cc0 100644 --- a/interface/wx/statbox.h +++ b/interface/wx/statbox.h @@ -111,7 +111,7 @@ public: } @endcode - Currently this constructor is only available in wxGTK, use + Currently this constructor is only available in wxGTK and wxMSW, use @c wxHAS_WINDOW_LABEL_IN_STATIC_BOX to check whether it can be used at compile-time. diff --git a/src/msw/statbox.cpp b/src/msw/statbox.cpp index 6596e1b573..9ca1b792bd 100644 --- a/src/msw/statbox.cpp +++ b/src/msw/statbox.cpp @@ -107,6 +107,27 @@ bool wxStaticBox::Create(wxWindow *parent, return true; } +bool wxStaticBox::Create(wxWindow* parent, + wxWindowID id, + wxWindow* labelWin, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + wxCHECK_MSG( labelWin, false, wxS("Label window can't be null") ); + + if ( !Create(parent, id, wxString(), pos, size, style, name) ) + return false; + + m_labelWin = labelWin; + m_labelWin->Reparent(this); + + m_labelWin->Move(FromDIP(LABEL_HORZ_OFFSET), 0); + + return true; +} + WXDWORD wxStaticBox::MSWGetStyle(long style, WXDWORD *exstyle) const { long styleWin = wxStaticBoxBase::MSWGetStyle(style, exstyle); @@ -269,7 +290,21 @@ void wxStaticBox::MSWGetRegionWithoutSelf(WXHRGN hRgn, int w, int h) GetBordersForSizer(&borderTop, &border); // top - SubtractRectFromRgn(hrgn, 0, 0, w, borderTop); + if ( m_labelWin ) + { + // Don't exclude the entire rectangle at the top, we do need to paint + // the background of the gap between the label window and the box + // frame. + const wxRect labelRect = m_labelWin->GetRect(); + const int gap = FromDIP(LABEL_HORZ_BORDER); + + SubtractRectFromRgn(hrgn, 0, 0, labelRect.GetLeft() - gap, borderTop); + SubtractRectFromRgn(hrgn, labelRect.GetRight() + gap, 0, w, borderTop); + } + else + { + SubtractRectFromRgn(hrgn, 0, 0, w, borderTop); + } // bottom SubtractRectFromRgn(hrgn, 0, h - border, w, h); @@ -415,7 +450,7 @@ void wxStaticBox::PaintForeground(wxDC& dc, const RECT&) // 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 ( m_hasFgCol && wxUxThemeEngine::GetIfActive() ) + if ( m_hasFgCol && wxUxThemeEngine::GetIfActive() && !m_labelWin ) { // draw over the text in default colour in our colour HDC hdc = GetHdcOf(*impl); @@ -535,8 +570,31 @@ void wxStaticBox::OnPaint(wxPaintEvent& WXUNUSED(event)) GetBordersForSizer(&borderTop, &border); // top - dc.Blit(border, 0, rc.right - border, borderTop, - &memdc, border, 0); + if ( m_labelWin ) + { + // We also have to exclude the area taken by the label window, + // otherwise there would be flicker when it draws itself on top of it. + const wxRect labelRect = m_labelWin->GetRect(); + + // We also leave a small border around label window to make it appear + // more similarly to a plain text label. + const int gap = FromDIP(LABEL_HORZ_BORDER); + + dc.Blit(border, 0, + labelRect.GetLeft() - gap - border, + borderTop, + &memdc, border, 0); + dc.Blit(labelRect.GetRight() + gap, 0, + rc.right - (labelRect.GetRight() + gap), + borderTop, + &memdc, border, 0); + } + else + { + dc.Blit(border, 0, rc.right - border, borderTop, + &memdc, border, 0); + } + // bottom dc.Blit(border, rc.bottom - border, rc.right - border, border, &memdc, border, rc.bottom - border);