1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/statbox.cpp
3 // Purpose: wxStaticBox
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22
23 #if wxUSE_STATBOX
24
25 #include "wx/statbox.h"
26
27 #ifndef WX_PRECOMP
28 #include "wx/app.h"
29 #include "wx/dcclient.h"
30 #include "wx/dcmemory.h"
31 #include "wx/image.h"
32 #include "wx/sizer.h"
33 #endif
34
35 #include "wx/notebook.h"
36 #include "wx/sysopt.h"
37
38 #include "wx/msw/uxtheme.h"
39
40 #include <windowsx.h> // needed by GET_X_LPARAM and GET_Y_LPARAM macros
41
42 #include "wx/msw/private.h"
43 #include "wx/msw/missing.h"
44 #include "wx/msw/dc.h"
45 #include "wx/msw/private/winstyle.h"
46
47 namespace
48 {
49
50 // Offset of the first pixel of the label from the box left border.
51 //
52 // FIXME: value is hardcoded as this is what it is on my system, no idea if
53 // it's true everywhere
54 const int LABEL_HORZ_OFFSET = 9;
55
56 // Extra borders around the label on left/right and bottom sides.
57 const int LABEL_HORZ_BORDER = 2;
58 const int LABEL_VERT_BORDER = 2;
59
60 // Offset of the box contents from left/right/bottom edge (top one is
61 // different, see GetBordersForSizer()). This one is completely arbitrary.
62 const int CHILDREN_OFFSET = 5;
63
64 } // anonymous namespace
65
66 // ----------------------------------------------------------------------------
67 // wxWin macros
68 // ----------------------------------------------------------------------------
69
70 // ============================================================================
71 // implementation
72 // ============================================================================
73
74 // ----------------------------------------------------------------------------
75 // wxStaticBox
76 // ----------------------------------------------------------------------------
77
Create(wxWindow * parent,wxWindowID id,const wxString & label,const wxPoint & pos,const wxSize & size,long style,const wxString & name)78 bool wxStaticBox::Create(wxWindow *parent,
79 wxWindowID id,
80 const wxString& label,
81 const wxPoint& pos,
82 const wxSize& size,
83 long style,
84 const wxString& name)
85 {
86 if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
87 return false;
88
89 if ( !MSWCreateControl(wxT("BUTTON"), label, pos, size) )
90 return false;
91
92 if (!wxSystemOptions::IsFalse(wxT("msw.staticbox.optimized-paint")))
93 {
94 Bind(wxEVT_PAINT, &wxStaticBox::OnPaint, this);
95
96 // Our OnPaint() completely erases our background, so don't do it in
97 // WM_ERASEBKGND too to avoid flicker.
98 SetBackgroundStyle(wxBG_STYLE_PAINT);
99 }
100
101 return true;
102 }
103
Create(wxWindow * parent,wxWindowID id,wxWindow * labelWin,const wxPoint & pos,const wxSize & size,long style,const wxString & name)104 bool wxStaticBox::Create(wxWindow* parent,
105 wxWindowID id,
106 wxWindow* labelWin,
107 const wxPoint& pos,
108 const wxSize& size,
109 long style,
110 const wxString& name)
111 {
112 wxCHECK_MSG( labelWin, false, wxS("Label window can't be null") );
113
114 if ( !Create(parent, id, wxString(), pos, size, style, name) )
115 return false;
116
117 m_labelWin = labelWin;
118 m_labelWin->Reparent(this);
119
120 PositionLabelWindow();
121
122 return true;
123 }
124
PositionLabelWindow()125 void wxStaticBox::PositionLabelWindow()
126 {
127 m_labelWin->SetSize(m_labelWin->GetBestSize());
128 m_labelWin->Move(FromDIP(LABEL_HORZ_OFFSET), 0);
129 }
130
GetCompositeWindowParts() const131 wxWindowList wxStaticBox::GetCompositeWindowParts() const
132 {
133 wxWindowList parts;
134 if ( m_labelWin )
135 parts.push_back(m_labelWin);
136 return parts;
137 }
138
MSWGetStyle(long style,WXDWORD * exstyle) const139 WXDWORD wxStaticBox::MSWGetStyle(long style, WXDWORD *exstyle) const
140 {
141 long styleWin = wxStaticBoxBase::MSWGetStyle(style, exstyle);
142
143 // no need for it anymore, must be removed for wxRadioBox child
144 // buttons to be able to repaint themselves
145 styleWin &= ~WS_CLIPCHILDREN;
146
147 if ( exstyle )
148 {
149 // We may have children inside this static box, so use this style for
150 // TAB navigation to work if we ever use IsDialogMessage() to implement
151 // it (currently we don't because it's too buggy and implement TAB
152 // navigation ourselves, but this could change in the future).
153 *exstyle |= WS_EX_CONTROLPARENT;
154
155 if (wxSystemOptions::IsFalse(wxT("msw.staticbox.optimized-paint")))
156 *exstyle |= WS_EX_TRANSPARENT;
157 }
158
159 styleWin |= BS_GROUPBOX;
160
161 return styleWin;
162 }
163
DoGetBestSize() const164 wxSize wxStaticBox::DoGetBestSize() const
165 {
166 wxSize best;
167
168 // Calculate the size needed by the label
169 int cx, cy;
170 wxGetCharSize(GetHWND(), &cx, &cy, GetFont());
171
172 int wBox;
173 GetTextExtent(GetLabelText(wxGetWindowText(m_hWnd)), &wBox, &cy);
174
175 wBox += 3*cx;
176 int hBox = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
177
178 // If there is a sizer then the base best size is the sizer's minimum
179 if (GetSizer() != NULL)
180 {
181 wxSize cm(GetSizer()->CalcMin());
182 best = ClientToWindowSize(cm);
183 // adjust for a long label if needed
184 best.x = wxMax(best.x, wBox);
185 }
186 // otherwise the best size falls back to the label size
187 else
188 {
189 best = wxSize(wBox, hBox);
190 }
191 return best;
192 }
193
GetBordersForSizer(int * borderTop,int * borderOther) const194 void wxStaticBox::GetBordersForSizer(int *borderTop, int *borderOther) const
195 {
196 // Base class version doesn't leave enough space at the top when the label
197 // is empty, so we can't use it here, even though the code is pretty
198 // similar.
199 if ( m_labelWin )
200 {
201 *borderTop = m_labelWin->GetSize().y;
202 }
203 else if ( !GetLabel().empty() )
204 {
205 *borderTop = GetCharHeight();
206 }
207 else // No label window nor text.
208 {
209 // This is completely arbitrary, but using the full char height in
210 // this case too seems bad as it leaves too much space at the top
211 // (although it does have the advantage of aligning the controls
212 // inside static boxes with and without labels vertically).
213 *borderTop = 2*FromDIP(CHILDREN_OFFSET);
214 }
215
216 *borderTop += FromDIP(LABEL_VERT_BORDER);
217
218 *borderOther = FromDIP(CHILDREN_OFFSET);
219 }
220
SetBackgroundColour(const wxColour & colour)221 bool wxStaticBox::SetBackgroundColour(const wxColour& colour)
222 {
223 // Do _not_ call the immediate base class method, we don't need to set the
224 // label window (which is the only sub-window of this composite window)
225 // background explicitly because it will almost always be a wxCheckBox or
226 // wxRadioButton which inherits its background from the box anyhow, so
227 // setting it would be at best useless.
228 return wxStaticBoxBase::SetBackgroundColour(colour);
229 }
230
SetFont(const wxFont & font)231 bool wxStaticBox::SetFont(const wxFont& font)
232 {
233 if ( !wxCompositeWindowSettersOnly<wxStaticBoxBase>::SetFont(font) )
234 return false;
235
236 // We need to reposition the label as its size may depend on the font.
237 if ( m_labelWin )
238 {
239 PositionLabelWindow();
240 }
241
242 return true;
243 }
244
MSWWindowProc(WXUINT nMsg,WXWPARAM wParam,WXLPARAM lParam)245 WXLRESULT wxStaticBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
246 {
247 if ( nMsg == WM_NCHITTEST )
248 {
249 // This code breaks some other processing such as enter/leave tracking
250 // so it's off by default.
251
252 static int s_useHTClient = -1;
253 if (s_useHTClient == -1)
254 s_useHTClient = wxSystemOptions::GetOptionInt(wxT("msw.staticbox.htclient"));
255 if (s_useHTClient == 1)
256 {
257 int xPos = GET_X_LPARAM(lParam);
258 int yPos = GET_Y_LPARAM(lParam);
259
260 ScreenToClient(&xPos, &yPos);
261
262 // Make sure you can drag by the top of the groupbox, but let
263 // other (enclosed) controls get mouse events also
264 if ( yPos < 10 )
265 return (long)HTCLIENT;
266 }
267 }
268
269 if ( nMsg == WM_PRINTCLIENT )
270 {
271 // we have to process WM_PRINTCLIENT ourselves as otherwise child
272 // windows' background (eg buttons in radio box) would never be drawn
273 // unless we have a parent with non default background
274
275 // so check first if we have one
276 if ( !HandlePrintClient((WXHDC)wParam) )
277 {
278 // no, we don't, erase the background ourselves
279 RECT rc;
280 ::GetClientRect(GetHwnd(), &rc);
281 wxDCTemp dc((WXHDC)wParam);
282 PaintBackground(dc, rc);
283 }
284
285 return 0;
286 }
287
288 if ( nMsg == WM_UPDATEUISTATE )
289 {
290 // DefWindowProc() redraws just the static box text when it gets this
291 // message and it does it using the standard (blue in standard theme)
292 // colour and not our own label colour that we use in PaintForeground()
293 // resulting in the label mysteriously changing the colour when e.g.
294 // "Alt" is pressed anywhere in the window, see #12497.
295 //
296 // To avoid this we simply refresh the window forcing our own code
297 // redrawing the label in the correct colour to be called. This is
298 // inefficient but there doesn't seem to be anything else we can do.
299 //
300 // Notice that the problem is XP-specific and doesn't arise under later
301 // systems.
302 if ( m_hasFgCol && wxGetWinVersion() == wxWinVersion_XP )
303 Refresh();
304 }
305
306 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
307 }
308
309 // ----------------------------------------------------------------------------
310 // static box drawing
311 // ----------------------------------------------------------------------------
312
313 /*
314 We draw the static box ourselves because it's the only way to prevent it
315 from flickering horribly on resize (because everything inside the box is
316 erased twice: once when the box itself is repainted and second time when
317 the control inside it is repainted) without using WS_EX_TRANSPARENT style as
318 we used to do and which resulted in other problems.
319 */
320
321 // MSWGetRegionWithoutSelf helper: removes the given rectangle from region
322 static inline void
SubtractRectFromRgn(HRGN hrgn,int left,int top,int right,int bottom)323 SubtractRectFromRgn(HRGN hrgn, int left, int top, int right, int bottom)
324 {
325 AutoHRGN hrgnRect(::CreateRectRgn(left, top, right, bottom));
326 if ( !hrgnRect )
327 {
328 wxLogLastError(wxT("CreateRectRgn()"));
329 return;
330 }
331
332 ::CombineRgn(hrgn, hrgn, hrgnRect, RGN_DIFF);
333 }
334
MSWGetRegionWithoutSelf(WXHRGN hRgn,int w,int h)335 void wxStaticBox::MSWGetRegionWithoutSelf(WXHRGN hRgn, int w, int h)
336 {
337 HRGN hrgn = (HRGN)hRgn;
338
339 // remove the area occupied by the static box borders from the region
340 int borderTop, border;
341 GetBordersForSizer(&borderTop, &border);
342
343 // top
344 if ( m_labelWin )
345 {
346 // Don't exclude the entire rectangle at the top, we do need to paint
347 // the background of the gap between the label window and the box
348 // frame.
349 const wxRect labelRect = m_labelWin->GetRect();
350 const int gap = FromDIP(LABEL_HORZ_BORDER);
351
352 SubtractRectFromRgn(hrgn, 0, 0, labelRect.GetLeft() - gap, borderTop);
353 SubtractRectFromRgn(hrgn, labelRect.GetRight() + gap, 0, w, borderTop);
354 }
355 else
356 {
357 SubtractRectFromRgn(hrgn, 0, 0, w, borderTop);
358 }
359
360 // bottom
361 SubtractRectFromRgn(hrgn, 0, h - border, w, h);
362
363 // left
364 SubtractRectFromRgn(hrgn, 0, 0, border, h);
365
366 // right
367 SubtractRectFromRgn(hrgn, w - border, 0, w, h);
368 }
369
370 namespace {
AdjustRectForRtl(wxLayoutDirection dir,RECT const & childRect,RECT const & boxRect)371 RECT AdjustRectForRtl(wxLayoutDirection dir, RECT const& childRect, RECT const& boxRect) {
372 RECT ret = childRect;
373 if( dir == wxLayout_RightToLeft ) {
374 // The clipping region too is mirrored in RTL layout.
375 // We need to mirror screen coordinates relative to static box window priot to
376 // intersecting with region.
377 ret.right = boxRect.right - childRect.left - boxRect.left;
378 ret.left = boxRect.right - childRect.right - boxRect.left;
379 }
380
381 return ret;
382 }
383 }
384
MSWGetRegionWithoutChildren()385 WXHRGN wxStaticBox::MSWGetRegionWithoutChildren()
386 {
387 RECT boxRc;
388 ::GetWindowRect(GetHwnd(), &boxRc);
389 HRGN hrgn = ::CreateRectRgn(boxRc.left, boxRc.top, boxRc.right + 1, boxRc.bottom + 1);
390 bool foundThis = false;
391
392 // Iterate over all sibling windows as in the old wxWidgets API the
393 // controls appearing inside the static box were created as its siblings
394 // and not children. This is now deprecated but should still work.
395 //
396 // Also notice that we must iterate over all windows, not just all
397 // wxWindows, as there may be composite windows etc.
398 HWND child;
399 for ( child = ::GetWindow(GetHwndOf(GetParent()), GW_CHILD);
400 child;
401 child = ::GetWindow(child, GW_HWNDNEXT) )
402 {
403 if ( ! ::IsWindowVisible(child) )
404 {
405 // if the window isn't visible then it doesn't need clipped
406 continue;
407 }
408
409 wxMSWWinStyleUpdater updateStyle(child);
410 wxString str(wxGetWindowClass(child));
411 str.UpperCase();
412 if ( str == wxT("BUTTON") && updateStyle.IsOn(BS_GROUPBOX) )
413 {
414 if ( child == GetHwnd() )
415 foundThis = true;
416
417 // Any static boxes below this one in the Z-order can't be clipped
418 // since if we have the case where a static box with a low Z-order
419 // is nested inside another static box with a high Z-order then the
420 // nested static box would be painted over. Doing it this way
421 // unfortunately results in flicker if the Z-order of nested static
422 // boxes is not inside (lowest) to outside (highest) but at least
423 // they are still shown.
424 if ( foundThis )
425 continue;
426 }
427
428 RECT rc;
429 ::GetWindowRect(child, &rc);
430 rc = AdjustRectForRtl(GetLayoutDirection(), rc, boxRc );
431 if ( ::RectInRegion(hrgn, &rc) )
432 {
433 // need to remove WS_CLIPSIBLINGS from all sibling windows
434 // that are within this staticbox if set
435 if ( updateStyle.IsOn(WS_CLIPSIBLINGS) )
436 {
437 updateStyle.TurnOff(WS_CLIPSIBLINGS).Apply();
438
439 // MSDN: "If you have changed certain window data using
440 // SetWindowLong, you must call SetWindowPos to have the
441 // changes take effect."
442 ::SetWindowPos(child, NULL, 0, 0, 0, 0,
443 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
444 SWP_FRAMECHANGED);
445 }
446
447 AutoHRGN hrgnChild(::CreateRectRgnIndirect(&rc));
448 ::CombineRgn(hrgn, hrgn, hrgnChild, RGN_DIFF);
449 }
450 }
451
452 // Also iterate over all children of the static box, we need to clip them
453 // out as well.
454 for ( child = ::GetWindow(GetHwnd(), GW_CHILD);
455 child;
456 child = ::GetWindow(child, GW_HWNDNEXT) )
457 {
458 if ( !::IsWindowVisible(child) )
459 {
460 // if the window isn't visible then it doesn't need clipped
461 continue;
462 }
463
464 RECT rc;
465 ::GetWindowRect(child, &rc);
466 rc = AdjustRectForRtl(GetLayoutDirection(), rc, boxRc );
467 AutoHRGN hrgnChild(::CreateRectRgnIndirect(&rc));
468 ::CombineRgn(hrgn, hrgn, hrgnChild, RGN_DIFF);
469 }
470
471 return (WXHRGN)hrgn;
472 }
473
474 // helper for OnPaint(): really erase the background, i.e. do it even if we
475 // don't have any non default brush for doing it (DoEraseBackground() doesn't
476 // do anything in such case)
PaintBackground(wxDC & dc,const RECT & rc)477 void wxStaticBox::PaintBackground(wxDC& dc, const RECT& rc)
478 {
479 wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
480 HBRUSH hbr = MSWGetBgBrush(impl->GetHDC());
481
482 // if there is no special brush for painting this control, just use the
483 // solid background colour
484 wxBrush brush;
485 if ( !hbr )
486 {
487 brush = wxBrush(GetParent()->GetBackgroundColour());
488 hbr = GetHbrushOf(brush);
489 }
490
491 ::FillRect(GetHdcOf(*impl), &rc, hbr);
492 }
493
PaintForeground(wxDC & dc,const RECT &)494 void wxStaticBox::PaintForeground(wxDC& dc, const RECT&)
495 {
496 wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
497 MSWDefWindowProc(WM_PAINT, (WPARAM)GetHdcOf(*impl), 0);
498
499 #if wxUSE_UXTHEME
500 // when using XP themes, neither setting the text colour nor transparent
501 // background mode doesn't change anything: the static box def window proc
502 // still draws the label in its own colours, so we need to redraw the text
503 // ourselves if we have a non default fg colour
504 if ( m_hasFgCol && wxUxThemeIsActive() && !m_labelWin )
505 {
506 // draw over the text in default colour in our colour
507 HDC hdc = GetHdcOf(*impl);
508 ::SetTextColor(hdc, GetForegroundColour().GetPixel());
509
510 // Get dimensions of the label
511 const wxString label = GetLabel();
512
513 // choose the correct font
514 AutoHFONT font;
515 SelectInHDC selFont;
516 if ( m_hasFont )
517 {
518 selFont.Init(hdc, GetHfontOf(GetFont()));
519 }
520 else // no font set, use the one set by the theme
521 {
522 wxUxThemeHandle hTheme(this, L"BUTTON");
523 if ( hTheme )
524 {
525 wxUxThemeFont themeFont;
526 if ( ::GetThemeFont
527 (
528 hTheme,
529 hdc,
530 BP_GROUPBOX,
531 GBS_NORMAL,
532 TMT_FONT,
533 themeFont.GetPtr()
534 ) == S_OK )
535 {
536 font.Init(themeFont.GetLOGFONT());
537 if ( font )
538 selFont.Init(hdc, font);
539 }
540 }
541 }
542
543 // Get the font extent
544 int width, height;
545 dc.GetTextExtent(wxStripMenuCodes(label, wxStrip_Mnemonics),
546 &width, &height);
547
548 // first we need to correctly paint the background of the label
549 // as Windows ignores the brush offset when doing it
550 // NOTE: Border intentionally does not use DIPs in order to match native look
551 const int x = LABEL_HORZ_OFFSET;
552 RECT dimensions = { x, 0, 0, height };
553 dimensions.left = x;
554 dimensions.right = x + width;
555
556 // need to adjust the rectangle to cover all the label background
557 dimensions.left -= LABEL_HORZ_BORDER;
558 dimensions.right += LABEL_HORZ_BORDER;
559 dimensions.bottom += LABEL_VERT_BORDER;
560
561 if ( UseBgCol() )
562 {
563 // our own background colour should be used for the background of
564 // the label: this is consistent with the behaviour under pre-XP
565 // systems (i.e. without visual themes) and generally makes sense
566 wxBrush brush = wxBrush(GetBackgroundColour());
567 ::FillRect(hdc, &dimensions, GetHbrushOf(brush));
568 }
569 else // paint parent background
570 {
571 PaintBackground(dc, dimensions);
572 }
573
574 UINT drawTextFlags = DT_SINGLELINE | DT_VCENTER;
575
576 // determine the state of UI queues to draw the text correctly under XP
577 // and later systems
578 static const bool isXPorLater = wxGetWinVersion() >= wxWinVersion_XP;
579 if ( isXPorLater )
580 {
581 if ( ::SendMessage(GetHwnd(), WM_QUERYUISTATE, 0, 0) &
582 UISF_HIDEACCEL )
583 {
584 drawTextFlags |= DT_HIDEPREFIX;
585 }
586 }
587
588 // now draw the text
589 RECT rc2 = { x, 0, x + width, height };
590 ::DrawText(hdc, label.t_str(), label.length(), &rc2,
591 drawTextFlags);
592 }
593 #endif // wxUSE_UXTHEME
594 }
595
OnPaint(wxPaintEvent & WXUNUSED (event))596 void wxStaticBox::OnPaint(wxPaintEvent& WXUNUSED(event))
597 {
598 RECT rc;
599 ::GetClientRect(GetHwnd(), &rc);
600 wxPaintDC dc(this);
601
602 // No need to do anything if the client rectangle is empty and, worse,
603 // doing it would result in an assert when creating the bitmap below.
604 if ( !rc.right || !rc.bottom )
605 return;
606
607 // draw the entire box in a memory DC
608 wxMemoryDC memdc(&dc);
609 wxBitmap bitmap(rc.right, rc.bottom);
610 memdc.SelectObject(bitmap);
611
612 PaintBackground(memdc, rc);
613 PaintForeground(memdc, rc);
614
615 // now only blit the static box border itself, not the interior, to avoid
616 // flicker when background is drawn below
617 //
618 // note that it seems to be faster to do 4 small blits here and then paint
619 // directly into wxPaintDC than painting background in wxMemoryDC and then
620 // blitting everything at once to wxPaintDC, this is why we do it like this
621 int borderTop, border;
622 GetBordersForSizer(&borderTop, &border);
623
624 // top
625 if ( m_labelWin )
626 {
627 // We also have to exclude the area taken by the label window,
628 // otherwise there would be flicker when it draws itself on top of it.
629 const wxRect labelRect = m_labelWin->GetRect();
630
631 // We also leave a small border around label window to make it appear
632 // more similarly to a plain text label.
633 const int gap = FromDIP(LABEL_HORZ_BORDER);
634
635 dc.Blit(border, 0,
636 labelRect.GetLeft() - gap - border,
637 borderTop,
638 &memdc, border, 0);
639 dc.Blit(labelRect.GetRight() + gap, 0,
640 rc.right - (labelRect.GetRight() + gap),
641 borderTop,
642 &memdc, border, 0);
643 }
644 else
645 {
646 dc.Blit(border, 0, rc.right - border, borderTop,
647 &memdc, border, 0);
648 }
649
650 // bottom
651 dc.Blit(border, rc.bottom - border, rc.right - border, border,
652 &memdc, border, rc.bottom - border);
653 // left
654 dc.Blit(0, 0, border, rc.bottom,
655 &memdc, 0, 0);
656 // right (note that upper and bottom right corners were already part of the
657 // first two blits so we shouldn't overwrite them here to avoi flicker)
658 dc.Blit(rc.right - border, borderTop,
659 border, rc.bottom - borderTop - border,
660 &memdc, rc.right - border, borderTop);
661
662
663 // create the region excluding box children
664 AutoHRGN hrgn((HRGN)MSWGetRegionWithoutChildren());
665 RECT rcWin;
666 ::GetWindowRect(GetHwnd(), &rcWin);
667 ::OffsetRgn(hrgn, -rcWin.left, -rcWin.top);
668
669 // and also the box itself
670 MSWGetRegionWithoutSelf((WXHRGN) hrgn, rc.right, rc.bottom);
671 wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
672 HDCClipper clipToBg(GetHdcOf(*impl), hrgn);
673
674 // paint the inside of the box (excluding box itself and child controls)
675 PaintBackground(dc, rc);
676 }
677
678 #endif // wxUSE_STATBOX
679