1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/stdrend.cpp
3 // Purpose: implementation of wxStdRenderer
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2006 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
27 #include "wx/settings.h"
30 #include "wx/statusbr.h"
31 #include "wx/toplevel.h"
34 #include "wx/univ/stdrend.h"
35 #include "wx/univ/colschem.h"
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 static const int FRAME_BORDER_THICKNESS
= 3;
42 static const int RESIZEABLE_FRAME_BORDER_THICKNESS
= 4;
43 static const int FRAME_TITLEBAR_HEIGHT
= 18;
44 static const int FRAME_BUTTON_WIDTH
= 16;
45 static const int FRAME_BUTTON_HEIGHT
= 14;
47 // ============================================================================
48 // wxStdRenderer implementation
49 // ============================================================================
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 wxStdRenderer::wxStdRenderer(const wxColourScheme
*scheme
)
58 m_penBlack
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_DARK
));
59 m_penDarkGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_OUT
));
60 m_penLightGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_IN
));
61 m_penHighlight
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_HIGHLIGHT
));
63 m_titlebarFont
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
64 m_titlebarFont
.SetWeight(wxFONTWEIGHT_BOLD
);
67 // ----------------------------------------------------------------------------
69 // ----------------------------------------------------------------------------
72 wxStdRenderer::DrawSolidRect(wxDC
& dc
, const wxColour
& col
, const wxRect
& rect
)
74 wxBrush
brush(col
, wxSOLID
);
76 dc
.SetPen(*wxTRANSPARENT_PEN
);
77 dc
.DrawRectangle(rect
);
80 void wxStdRenderer::DrawRect(wxDC
& dc
, wxRect
*rect
, const wxPen
& pen
)
84 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
85 dc
.DrawRectangle(*rect
);
91 void wxStdRenderer::DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
92 const wxPen
& pen1
, const wxPen
& pen2
)
96 dc
.DrawLine(rect
->GetLeft(), rect
->GetTop(),
97 rect
->GetLeft(), rect
->GetBottom());
98 dc
.DrawLine(rect
->GetLeft() + 1, rect
->GetTop(),
99 rect
->GetRight(), rect
->GetTop());
101 dc
.DrawLine(rect
->GetRight(), rect
->GetTop(),
102 rect
->GetRight(), rect
->GetBottom());
103 dc
.DrawLine(rect
->GetLeft(), rect
->GetBottom(),
104 rect
->GetRight() + 1, rect
->GetBottom());
110 // ----------------------------------------------------------------------------
111 // translate various flags into corresponding renderer constants
112 // ----------------------------------------------------------------------------
115 void wxStdRenderer::GetIndicatorsFromFlags(int flags
,
116 IndicatorState
& state
,
117 IndicatorStatus
& status
)
119 if ( flags
& wxCONTROL_SELECTED
)
120 state
= flags
& wxCONTROL_DISABLED
? IndicatorState_SelectedDisabled
121 : IndicatorState_Selected
;
122 else if ( flags
& wxCONTROL_DISABLED
)
123 state
= IndicatorState_Disabled
;
124 else if ( flags
& wxCONTROL_PRESSED
)
125 state
= IndicatorState_Pressed
;
127 state
= IndicatorState_Normal
;
129 status
= flags
& wxCONTROL_CHECKED
? IndicatorStatus_Checked
130 : flags
& wxCONTROL_UNDETERMINED
131 ? IndicatorStatus_Undetermined
132 : IndicatorStatus_Unchecked
;
136 wxStdRenderer::ArrowDirection
wxStdRenderer::GetArrowDirection(wxDirection dir
)
153 wxFAIL_MSG(_T("unknown arrow direction"));
159 // ----------------------------------------------------------------------------
161 // ----------------------------------------------------------------------------
163 void wxStdRenderer::DrawBackground(wxDC
& dc
,
169 wxColour colBg
= col
.Ok() ? col
170 : window
? m_scheme
->GetBackground(window
)
171 : wxSCHEME_COLOUR(m_scheme
, CONTROL
);
173 DrawSolidRect(dc
, colBg
, rect
);
177 void wxStdRenderer::DrawButtonSurface(wxDC
& dc
,
182 DrawBackground(dc
, col
, rect
, flags
);
185 // ----------------------------------------------------------------------------
187 // ----------------------------------------------------------------------------
189 void wxStdRenderer::DrawFocusRect(wxDC
& dc
, const wxRect
& rect
)
191 // draw the pixels manually because the "dots" in wxPen with wxDOT style
192 // may be short traits and not really dots
194 // note that to behave in the same manner as DrawRect(), we must exclude
195 // the bottom and right borders from the rectangle
196 wxCoord x1
= rect
.GetLeft(),
198 x2
= rect
.GetRight(),
199 y2
= rect
.GetBottom();
201 dc
.SetPen(m_penBlack
);
203 // this seems to be closer than what Windows does than wxINVERT although
204 // I'm still not sure if it's correct
205 dc
.SetLogicalFunction(wxAND_REVERSE
);
208 for ( z
= x1
+ 1; z
< x2
; z
+= 2 )
209 dc
.DrawPoint(z
, rect
.GetTop());
211 wxCoord shift
= z
== x2
? 0 : 1;
212 for ( z
= y1
+ shift
; z
< y2
; z
+= 2 )
215 shift
= z
== y2
? 0 : 1;
216 for ( z
= x2
- shift
; z
> x1
; z
-= 2 )
219 shift
= z
== x1
? 0 : 1;
220 for ( z
= y2
- shift
; z
> y1
; z
-= 2 )
223 dc
.SetLogicalFunction(wxCOPY
);
226 void wxStdRenderer::DrawLabel(wxDC
& dc
,
227 const wxString
& label
,
234 DrawButtonLabel(dc
, label
, wxNullBitmap
, rect
, flags
,
235 alignment
, indexAccel
, rectBounds
);
238 void wxStdRenderer::DrawButtonLabel(wxDC
& dc
,
239 const wxString
& label
,
240 const wxBitmap
& image
,
247 wxRect rectLabel
= rect
;
248 if ( !label
.empty() && (flags
& wxCONTROL_DISABLED
) )
250 if ( flags
& wxCONTROL_PRESSED
)
252 // shift the label if a button is pressed
253 rectLabel
.Offset(1, 1);
256 // draw shadow of the text
257 dc
.SetTextForeground(m_penHighlight
.GetColour());
258 wxRect rectShadow
= rect
;
259 rectShadow
.Offset(1, 1);
260 dc
.DrawLabel(label
, rectShadow
, alignment
, indexAccel
);
262 // make the main label text grey
263 dc
.SetTextForeground(m_penDarkGrey
.GetColour());
265 if ( flags
& wxCONTROL_FOCUSED
)
267 // leave enough space for the focus rect
268 rectLabel
.Inflate(-2);
272 dc
.DrawLabel(label
, image
, rectLabel
, alignment
, indexAccel
, rectBounds
);
274 if ( !label
.empty() && (flags
& wxCONTROL_FOCUSED
) )
276 rectLabel
.Inflate(-1);
278 DrawFocusRect(dc
, rectLabel
);
282 // ----------------------------------------------------------------------------
284 // ----------------------------------------------------------------------------
287 We implement standard-looking 3D borders which have the following appearance:
291 WWWWWWWWWWWWWWWWWWWWWWB
292 WHHHHHHHHHHHHHHHHHHHHGB
293 WH GB W = white (HILIGHT)
294 WH GB H = light grey (LIGHT)
295 WH GB G = dark grey (SHADOI)
296 WH GB B = black (DKSHADOI)
299 WGGGGGGGGGGGGGGGGGGGGGB
300 BBBBBBBBBBBBBBBBBBBBBBB
302 The sunken border looks like this:
304 GGGGGGGGGGGGGGGGGGGGGGW
305 GBBBBBBBBBBBBBBBBBBBBHW
312 GHHHHHHHHHHHHHHHHHHHHHW
313 WWWWWWWWWWWWWWWWWWWWWWW
315 The static border (used for the controls which don't get focus) is like
318 GGGGGGGGGGGGGGGGGGGGGGW
326 WWWWWWWWWWWWWWWWWWWWWWW
328 The most complicated is the double border which is a combination of special
329 "anti-sunken" border and an extra border inside it:
331 HHHHHHHHHHHHHHHHHHHHHHB
332 HWWWWWWWWWWWWWWWWWWWWGB
333 HWHHHHHHHHHHHHHHHHHHHGB
338 HWHHHHHHHHHHHHHHHHHHHGB
339 HGGGGGGGGGGGGGGGGGGGGGB
340 BBBBBBBBBBBBBBBBBBBBBBB
342 And the simple border is, well, simple:
344 BBBBBBBBBBBBBBBBBBBBBBB
353 BBBBBBBBBBBBBBBBBBBBBBB
356 void wxStdRenderer::DrawRaisedBorder(wxDC
& dc
, wxRect
*rect
)
358 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penBlack
);
359 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penDarkGrey
);
362 void wxStdRenderer::DrawSunkenBorder(wxDC
& dc
, wxRect
*rect
)
364 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
365 DrawShadedRect(dc
, rect
, m_penBlack
, m_penLightGrey
);
368 void wxStdRenderer::DrawAntiSunkenBorder(wxDC
& dc
, wxRect
*rect
)
370 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penBlack
);
371 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
374 void wxStdRenderer::DrawBoxBorder(wxDC
& dc
, wxRect
*rect
)
376 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
377 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
380 void wxStdRenderer::DrawStaticBorder(wxDC
& dc
, wxRect
*rect
)
382 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
385 void wxStdRenderer::DrawExtraBorder(wxDC
& dc
, wxRect
*rect
)
387 DrawRect(dc
, rect
, m_penLightGrey
);
390 void wxStdRenderer::DrawBorder(wxDC
& dc
,
392 const wxRect
& rectTotal
,
396 wxRect rect
= rectTotal
;
400 case wxBORDER_SUNKEN
:
401 DrawSunkenBorder(dc
, &rect
);
404 case wxBORDER_DOUBLE
:
405 DrawAntiSunkenBorder(dc
, &rect
);
406 DrawExtraBorder(dc
, &rect
);
409 case wxBORDER_STATIC
:
410 DrawStaticBorder(dc
, &rect
);
413 case wxBORDER_RAISED
:
414 DrawRaisedBorder(dc
, &rect
);
417 case wxBORDER_SIMPLE
:
418 DrawRect(dc
, &rect
, m_penBlack
);
422 wxFAIL_MSG(_T("unknown border type"));
425 case wxBORDER_DEFAULT
:
434 wxRect
wxStdRenderer::GetBorderDimensions(wxBorder border
) const
439 case wxBORDER_SIMPLE
:
440 case wxBORDER_STATIC
:
444 case wxBORDER_RAISED
:
445 case wxBORDER_SUNKEN
:
449 case wxBORDER_DOUBLE
:
454 wxFAIL_MSG(_T("unknown border type"));
457 case wxBORDER_DEFAULT
:
472 void wxStdRenderer::AdjustSize(wxSize
*size
, const wxWindow
*window
)
474 // take into account the border width
475 wxRect rectBorder
= GetBorderDimensions(window
->GetBorder());
476 size
->x
+= rectBorder
.x
+ rectBorder
.width
;
477 size
->y
+= rectBorder
.y
+ rectBorder
.height
;
480 bool wxStdRenderer::AreScrollbarsInsideBorder() const
485 wxCoord
wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight
)
487 return fontHeight
+ 2;
490 void wxStdRenderer::DrawTextBorder(wxDC
& dc
,
496 DrawBorder(dc
, border
, rect
, flags
, rectIn
);
499 // ----------------------------------------------------------------------------
501 // ----------------------------------------------------------------------------
504 wxStdRenderer::DrawHorizontalLine(wxDC
& dc
, wxCoord y
, wxCoord x1
, wxCoord x2
)
506 dc
.SetPen(m_penDarkGrey
);
507 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
509 dc
.SetPen(m_penHighlight
);
511 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
515 wxStdRenderer::DrawVerticalLine(wxDC
& dc
, wxCoord x
, wxCoord y1
, wxCoord y2
)
517 dc
.SetPen(m_penDarkGrey
);
518 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
520 dc
.SetPen(m_penHighlight
);
522 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
525 void wxStdRenderer::DrawFrameWithoutLabel(wxDC
& dc
,
526 const wxRect
& rectFrame
,
527 const wxRect
& rectLabel
)
529 // draw left, bottom and right lines entirely
530 DrawVerticalLine(dc
, rectFrame
.GetLeft(),
531 rectFrame
.GetTop(), rectFrame
.GetBottom() - 2);
532 DrawHorizontalLine(dc
, rectFrame
.GetBottom() - 1,
533 rectFrame
.GetLeft(), rectFrame
.GetRight());
534 DrawVerticalLine(dc
, rectFrame
.GetRight() - 1,
535 rectFrame
.GetTop(), rectFrame
.GetBottom() - 1);
537 // and 2 parts of the top line
538 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
539 rectFrame
.GetLeft() + 1, rectLabel
.GetLeft());
540 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
541 rectLabel
.GetRight(), rectFrame
.GetRight() - 2);
544 void wxStdRenderer::DrawFrameWithLabel(wxDC
& dc
,
545 const wxString
& label
,
546 const wxRect
& rectFrame
,
547 const wxRect
& rectText
,
553 DrawLabel(dc
, label
, rectText
, flags
, alignment
, indexAccel
, &rectLabel
);
555 DrawFrameWithoutLabel(dc
, rectFrame
, rectLabel
);
558 void wxStdRenderer::DrawFrame(wxDC
& dc
,
559 const wxString
& label
,
565 wxCoord height
= 0; // of the label
566 wxRect rectFrame
= rect
;
567 if ( !label
.empty() )
569 // the text should touch the top border of the rect, so the frame
570 // itself should be lower
571 dc
.GetTextExtent(label
, NULL
, &height
);
572 rectFrame
.y
+= height
/ 2;
573 rectFrame
.height
-= height
/ 2;
575 // we have to draw each part of the frame individually as we can't
576 // erase the background beyond the label as it might contain some
577 // pixmap already, so drawing everything and then overwriting part of
578 // the frame with label doesn't work
580 // TODO: the +5 shouldn't be hard coded
582 rectText
.x
= rectFrame
.x
+ 5;
584 rectText
.width
= rectFrame
.width
- 7; // +2 border width
585 rectText
.height
= height
;
587 DrawFrameWithLabel(dc
, label
, rectFrame
, rectText
, flags
,
588 alignment
, indexAccel
);
592 DrawBoxBorder(dc
, &rectFrame
);
596 void wxStdRenderer::DrawItem(wxDC
& dc
,
597 const wxString
& label
,
601 wxDCTextColourChanger
colChanger(dc
);
603 if ( flags
& wxCONTROL_SELECTED
)
605 colChanger
.Set(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
607 const wxColour colBg
= wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
);
610 dc
.DrawRectangle(rect
);
613 wxRect rectText
= rect
;
616 dc
.DrawLabel(label
, wxNullBitmap
, rectText
);
618 if ( flags
& wxCONTROL_FOCUSED
)
620 DrawFocusRect(dc
, rect
);
624 void wxStdRenderer::DrawCheckItemBitmap(wxDC
& dc
,
625 const wxBitmap
& bitmap
,
629 DrawCheckButton(dc
, wxEmptyString
, bitmap
, rect
, flags
);
632 void wxStdRenderer::DrawCheckItem(wxDC
& dc
,
633 const wxString
& label
,
634 const wxBitmap
& bitmap
,
638 wxRect rectBitmap
= rect
;
639 rectBitmap
.width
= GetCheckBitmapSize().x
;
640 DrawCheckItemBitmap(dc
, bitmap
, rectBitmap
, flags
);
642 wxRect rectLabel
= rect
;
643 wxCoord shift
= rectBitmap
.width
+ 2*GetCheckItemMargin();
644 rectLabel
.x
+= shift
;
645 rectLabel
.width
-= shift
;
646 DrawItem(dc
, label
, rectLabel
, flags
);
649 // ----------------------------------------------------------------------------
650 // check and radio bitmaps
651 // ----------------------------------------------------------------------------
653 void wxStdRenderer::DrawCheckButton(wxDC
& dc
,
654 const wxString
& label
,
655 const wxBitmap
& bitmap
,
661 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetCheckBitmap(flags
));
663 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
666 void wxStdRenderer::DrawRadioButton(wxDC
& dc
,
667 const wxString
& label
,
668 const wxBitmap
& bitmap
,
674 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetRadioBitmap(flags
));
676 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
679 void wxStdRenderer::DrawCheckOrRadioButton(wxDC
& dc
,
680 const wxString
& label
,
681 const wxBitmap
& bitmap
,
687 // calculate the position of the bitmap and of the label
688 wxCoord heightBmp
= bitmap
.GetHeight();
690 yBmp
= rect
.y
+ (rect
.height
- heightBmp
) / 2;
693 dc
.GetMultiLineTextExtent(label
, NULL
, &rectLabel
.height
);
694 rectLabel
.y
= rect
.y
+ (rect
.height
- rectLabel
.height
) / 2;
696 // align label vertically with the bitmap - looks nicer like this
697 rectLabel
.y
-= (rectLabel
.height
- heightBmp
) % 2;
699 // calc horz position
700 if ( align
== wxALIGN_RIGHT
)
702 xBmp
= rect
.GetRight() - bitmap
.GetWidth();
703 rectLabel
.x
= rect
.x
+ 3;
704 rectLabel
.SetRight(xBmp
);
706 else // normal (checkbox to the left of the text) case
709 rectLabel
.x
= xBmp
+ bitmap
.GetWidth() + 5;
710 rectLabel
.SetRight(rect
.GetRight());
713 dc
.DrawBitmap(bitmap
, xBmp
, yBmp
, true /* use mask */);
715 DrawLabel(dc
, label
, rectLabel
, flags
,
716 wxALIGN_LEFT
| wxALIGN_TOP
, indexAccel
);
721 void wxStdRenderer::DrawTextLine(wxDC
& dc
,
722 const wxString
& text
,
728 if ( (selStart
== -1) || !(flags
& wxCONTROL_FOCUSED
) )
730 // just draw it as is
731 dc
.DrawText(text
, rect
.x
, rect
.y
);
733 else // we have selection
738 // draw the part before selection
739 wxString
s(text
, (size_t)selStart
);
742 dc
.DrawText(s
, x
, rect
.y
);
744 dc
.GetTextExtent(s
, &width
, NULL
);
748 // draw the selection itself
749 s
= wxString(text
.c_str() + selStart
, text
.c_str() + selEnd
);
752 wxColour colFg
= dc
.GetTextForeground(),
753 colBg
= dc
.GetTextBackground();
754 dc
.SetTextForeground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
755 dc
.SetTextBackground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
));
756 dc
.SetBackgroundMode(wxSOLID
);
758 dc
.DrawText(s
, x
, rect
.y
);
759 dc
.GetTextExtent(s
, &width
, NULL
);
762 dc
.SetBackgroundMode(wxTRANSPARENT
);
763 dc
.SetTextBackground(colBg
);
764 dc
.SetTextForeground(colFg
);
767 // draw the final part
768 s
= text
.c_str() + selEnd
;
771 dc
.DrawText(s
, x
, rect
.y
);
776 void wxStdRenderer::DrawLineWrapMark(wxDC
& WXUNUSED(dc
),
777 const wxRect
& WXUNUSED(rect
))
779 // nothing by default
782 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl
* WXUNUSED(text
)) const
788 wxStdRenderer::GetTextTotalArea(const wxTextCtrl
*text
, const wxRect
& rect
) const
790 wxRect rectTotal
= rect
;
791 rectTotal
.Inflate(GetTextBorderWidth(text
));
795 wxRect
wxStdRenderer::GetTextClientArea(const wxTextCtrl
*text
,
797 wxCoord
*extraSpaceBeyond
) const
799 wxRect rectText
= rect
;
800 rectText
.Deflate(GetTextBorderWidth(text
));
802 if ( extraSpaceBeyond
)
803 *extraSpaceBeyond
= 0;
808 #endif // wxUSE_TEXTCTRL
810 // ----------------------------------------------------------------------------
811 // scrollbars drawing
812 // ----------------------------------------------------------------------------
814 void wxStdRenderer::DrawScrollbarArrow(wxDC
& dc
,
819 DrawArrow(dc
, dir
, rect
, flags
);
822 void wxStdRenderer::DrawScrollCorner(wxDC
& dc
, const wxRect
& rect
)
824 DrawSolidRect(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rect
);
827 // ----------------------------------------------------------------------------
828 // scrollbars geometry
829 // ----------------------------------------------------------------------------
834 void wxStdRenderer::GetScrollBarThumbSize(wxCoord length
,
841 // the thumb can't be made less than this number of pixels
842 static const wxCoord thumbMinWidth
= 8; // FIXME: should be configurable
844 *thumbStart
= (length
*thumbPos
) / range
;
845 *thumbEnd
= (length
*(thumbPos
+ thumbSize
)) / range
;
847 if ( *thumbEnd
- *thumbStart
< thumbMinWidth
)
849 // adjust the end if possible
850 if ( *thumbStart
<= length
- thumbMinWidth
)
852 // yes, just make it wider
853 *thumbEnd
= *thumbStart
+ thumbMinWidth
;
855 else // it is at the bottom of the scrollbar
857 // so move it a bit up
858 *thumbStart
= length
- thumbMinWidth
;
864 wxRect
wxStdRenderer::GetScrollbarRect(const wxScrollBar
*scrollbar
,
865 wxScrollBar::Element elem
,
868 if ( thumbPos
== -1 )
870 thumbPos
= scrollbar
->GetThumbPosition();
873 const wxSize sizeArrow
= GetScrollbarArrowSize();
875 wxSize sizeTotal
= scrollbar
->GetClientSize();
876 wxCoord
*start
, *width
;
877 wxCoord length
, arrow
;
879 if ( scrollbar
->IsVertical() )
882 rect
.width
= sizeTotal
.x
;
883 length
= sizeTotal
.y
;
885 width
= &rect
.height
;
891 rect
.height
= sizeTotal
.y
;
892 length
= sizeTotal
.x
;
900 case wxScrollBar::Element_Arrow_Line_1
:
905 case wxScrollBar::Element_Arrow_Line_2
:
906 *start
= length
- arrow
;
910 case wxScrollBar::Element_Arrow_Page_1
:
911 case wxScrollBar::Element_Arrow_Page_2
:
912 // we don't have them at all
915 case wxScrollBar::Element_Thumb
:
916 case wxScrollBar::Element_Bar_1
:
917 case wxScrollBar::Element_Bar_2
:
918 // we need to calculate the thumb position - do it
921 wxCoord thumbStart
, thumbEnd
;
922 int range
= scrollbar
->GetRange();
930 GetScrollBarThumbSize(length
,
932 scrollbar
->GetThumbSize(),
938 if ( elem
== wxScrollBar::Element_Thumb
)
941 *width
= thumbEnd
- thumbStart
;
943 else if ( elem
== wxScrollBar::Element_Bar_1
)
948 else // elem == wxScrollBar::Element_Bar_2
951 *width
= length
- thumbEnd
;
954 // everything is relative to the start of the shaft so far
959 case wxScrollBar::Element_Max
:
961 wxFAIL_MSG( _T("unknown scrollbar element") );
967 wxCoord
wxStdRenderer::GetScrollbarSize(const wxScrollBar
*scrollbar
)
969 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
971 wxCoord sizeArrow
, sizeTotal
;
972 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
974 sizeArrow
= sizeArrowSB
.y
;
975 sizeTotal
= scrollbar
->GetSize().y
;
979 sizeArrow
= sizeArrowSB
.x
;
980 sizeTotal
= scrollbar
->GetSize().x
;
983 return sizeTotal
- 2*sizeArrow
;
987 wxStdRenderer::HitTestScrollbar(const wxScrollBar
*scrollbar
, const wxPoint
& pt
) const
989 // we only need to work with either x or y coord depending on the
990 // orientation, choose one (but still check the other one to verify if the
991 // mouse is in the window at all)
992 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
994 wxCoord coord
, sizeArrow
, sizeTotal
;
995 wxSize size
= scrollbar
->GetSize();
996 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
998 if ( pt
.x
< 0 || pt
.x
> size
.x
)
1002 sizeArrow
= sizeArrowSB
.y
;
1007 if ( pt
.y
< 0 || pt
.y
> size
.y
)
1008 return wxHT_NOWHERE
;
1011 sizeArrow
= sizeArrowSB
.x
;
1015 // test for the arrows first as it's faster
1016 if ( coord
< 0 || coord
> sizeTotal
)
1018 return wxHT_NOWHERE
;
1020 else if ( coord
< sizeArrow
)
1022 return wxHT_SCROLLBAR_ARROW_LINE_1
;
1024 else if ( coord
> sizeTotal
- sizeArrow
)
1026 return wxHT_SCROLLBAR_ARROW_LINE_2
;
1030 // calculate the thumb position in pixels
1031 sizeTotal
-= 2*sizeArrow
;
1032 wxCoord thumbStart
, thumbEnd
;
1033 int range
= scrollbar
->GetRange();
1036 // clicking the scrollbar without range has no effect
1037 return wxHT_NOWHERE
;
1041 GetScrollBarThumbSize(sizeTotal
,
1042 scrollbar
->GetThumbPosition(),
1043 scrollbar
->GetThumbSize(),
1049 // now compare with the thumb position
1051 if ( coord
< thumbStart
)
1052 return wxHT_SCROLLBAR_BAR_1
;
1053 else if ( coord
> thumbEnd
)
1054 return wxHT_SCROLLBAR_BAR_2
;
1056 return wxHT_SCROLLBAR_THUMB
;
1062 wxStdRenderer::ScrollbarToPixel(const wxScrollBar
*scrollbar
, int thumbPos
)
1064 int range
= scrollbar
->GetRange();
1067 // the only valid position anyhow
1071 if ( thumbPos
== -1 )
1073 // by default use the current thumb position
1074 thumbPos
= scrollbar
->GetThumbPosition();
1077 const wxSize sizeArrow
= GetScrollbarArrowSize();
1078 return (thumbPos
*GetScrollbarSize(scrollbar
)) / range
1079 + (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
);
1082 int wxStdRenderer::PixelToScrollbar(const wxScrollBar
*scrollbar
, wxCoord coord
)
1084 const wxSize sizeArrow
= GetScrollbarArrowSize();
1085 return ((coord
- (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
)) *
1086 scrollbar
->GetRange() ) / GetScrollbarSize(scrollbar
);
1089 #endif // wxUSE_SCROLLBAR
1091 // ----------------------------------------------------------------------------
1093 // ----------------------------------------------------------------------------
1097 wxSize
wxStdRenderer::GetStatusBarBorders(wxCoord
*borderBetweenFields
) const
1099 if ( borderBetweenFields
)
1100 *borderBetweenFields
= 2;
1102 return wxSize(2, 2);
1105 void wxStdRenderer::DrawStatusField(wxDC
& dc
,
1107 const wxString
& label
,
1113 if ( style
== wxSB_RAISED
)
1114 DrawBorder(dc
, wxBORDER_RAISED
, rect
, flags
, &rectIn
);
1115 else if ( style
!= wxSB_FLAT
)
1116 DrawBorder(dc
, wxBORDER_STATIC
, rect
, flags
, &rectIn
);
1118 rectIn
.Deflate(GetStatusBarBorders(NULL
));
1120 wxDCClipper
clipper(dc
, rectIn
);
1121 DrawLabel(dc
, label
, rectIn
, flags
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1124 #endif // wxUSE_STATUSBAR
1126 // ----------------------------------------------------------------------------
1127 // top level windows
1128 // ----------------------------------------------------------------------------
1130 int wxStdRenderer::HitTestFrame(const wxRect
& rect
, const wxPoint
& pt
, int flags
) const
1132 wxRect client
= GetFrameClientArea(rect
, flags
);
1134 if ( client
.Contains(pt
) )
1135 return wxHT_TOPLEVEL_CLIENT_AREA
;
1137 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1139 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1141 if ( flags
& wxTOPLEVEL_ICON
)
1143 if ( wxRect(client
.GetPosition(), GetFrameIconSize()).Contains(pt
) )
1144 return wxHT_TOPLEVEL_ICON
;
1147 wxRect
btnRect(client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
,
1148 client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2,
1149 FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1151 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1153 if ( btnRect
.Contains(pt
) )
1154 return wxHT_TOPLEVEL_BUTTON_CLOSE
;
1155 btnRect
.x
-= FRAME_BUTTON_WIDTH
+ 2;
1157 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1159 if ( btnRect
.Contains(pt
) )
1160 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE
;
1161 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1163 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1165 if ( btnRect
.Contains(pt
) )
1166 return wxHT_TOPLEVEL_BUTTON_RESTORE
;
1167 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1169 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1171 if ( btnRect
.Contains(pt
) )
1172 return wxHT_TOPLEVEL_BUTTON_ICONIZE
;
1173 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1175 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1177 if ( btnRect
.Contains(pt
) )
1178 return wxHT_TOPLEVEL_BUTTON_HELP
;
1179 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1182 if ( pt
.y
>= client
.y
&& pt
.y
< client
.y
+ FRAME_TITLEBAR_HEIGHT
)
1183 return wxHT_TOPLEVEL_TITLEBAR
;
1186 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1188 // we are certainly at one of borders, let's decide which one:
1191 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
1192 if ( pt
.x
< client
.x
)
1193 border
|= wxHT_TOPLEVEL_BORDER_W
;
1194 else if ( pt
.x
>= client
.width
+ client
.x
)
1195 border
|= wxHT_TOPLEVEL_BORDER_E
;
1196 if ( pt
.y
< client
.y
)
1197 border
|= wxHT_TOPLEVEL_BORDER_N
;
1198 else if ( pt
.y
>= client
.height
+ client
.y
)
1199 border
|= wxHT_TOPLEVEL_BORDER_S
;
1203 return wxHT_NOWHERE
;
1206 void wxStdRenderer::DrawFrameTitleBar(wxDC
& dc
,
1208 const wxString
& title
,
1212 int specialButtonFlags
)
1214 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1216 DrawFrameBorder(dc
, rect
, flags
);
1218 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1220 DrawFrameBackground(dc
, rect
, flags
);
1221 if ( flags
& wxTOPLEVEL_ICON
)
1222 DrawFrameIcon(dc
, rect
, icon
, flags
);
1223 DrawFrameTitle(dc
, rect
, title
, flags
);
1225 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1227 x
= client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
;
1228 y
= client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2;
1230 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1232 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_CLOSE
,
1233 (specialButton
== wxTOPLEVEL_BUTTON_CLOSE
) ?
1234 specialButtonFlags
: 0);
1235 x
-= FRAME_BUTTON_WIDTH
+ 2;
1237 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1239 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_MAXIMIZE
,
1240 (specialButton
== wxTOPLEVEL_BUTTON_MAXIMIZE
) ?
1241 specialButtonFlags
: 0);
1242 x
-= FRAME_BUTTON_WIDTH
;
1244 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1246 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_RESTORE
,
1247 (specialButton
== wxTOPLEVEL_BUTTON_RESTORE
) ?
1248 specialButtonFlags
: 0);
1249 x
-= FRAME_BUTTON_WIDTH
;
1251 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1253 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_ICONIZE
,
1254 (specialButton
== wxTOPLEVEL_BUTTON_ICONIZE
) ?
1255 specialButtonFlags
: 0);
1256 x
-= FRAME_BUTTON_WIDTH
;
1258 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1260 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_HELP
,
1261 (specialButton
== wxTOPLEVEL_BUTTON_HELP
) ?
1262 specialButtonFlags
: 0);
1267 void wxStdRenderer::DrawFrameBorder(wxDC
& dc
, const wxRect
& rect
, int flags
)
1269 if ( !(flags
& wxTOPLEVEL_BORDER
) )
1274 DrawAntiSunkenBorder(dc
, &r
);
1275 DrawExtraBorder(dc
, &r
);
1276 if ( flags
& wxTOPLEVEL_RESIZEABLE
)
1277 DrawExtraBorder(dc
, &r
);
1280 void wxStdRenderer::DrawFrameBackground(wxDC
& dc
, const wxRect
& rect
, int flags
)
1282 if ( !(flags
& wxTOPLEVEL_TITLEBAR
) )
1285 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1286 ? wxColourScheme::TITLEBAR_ACTIVE
1287 : wxColourScheme::TITLEBAR
);
1289 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1290 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1292 DrawBackground(dc
, col
, r
);
1295 void wxStdRenderer::DrawFrameTitle(wxDC
& dc
,
1297 const wxString
& title
,
1300 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1301 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1302 : wxColourScheme::TITLEBAR_TEXT
);
1303 dc
.SetTextForeground(col
);
1305 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1306 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1307 if ( flags
& wxTOPLEVEL_ICON
)
1309 r
.x
+= FRAME_TITLEBAR_HEIGHT
;
1310 r
.width
-= FRAME_TITLEBAR_HEIGHT
+ 2;
1318 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1319 r
.width
-= FRAME_BUTTON_WIDTH
+ 2;
1320 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1321 r
.width
-= FRAME_BUTTON_WIDTH
;
1322 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1323 r
.width
-= FRAME_BUTTON_WIDTH
;
1324 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1325 r
.width
-= FRAME_BUTTON_WIDTH
;
1326 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1327 r
.width
-= FRAME_BUTTON_WIDTH
;
1329 dc
.SetFont(m_titlebarFont
);
1333 dc
.GetTextExtent(title
, &textW
, NULL
);
1334 if ( textW
> r
.width
)
1336 // text is too big, let's shorten it and add "..." after it:
1337 size_t len
= title
.length();
1338 wxCoord WSoFar
, letterW
;
1340 dc
.GetTextExtent(wxT("..."), &WSoFar
, NULL
);
1341 if ( WSoFar
> r
.width
)
1343 // not enough space to draw anything
1348 for (size_t i
= 0; i
< len
; i
++)
1350 dc
.GetTextExtent(title
[i
], &letterW
, NULL
);
1351 if ( letterW
+ WSoFar
> r
.width
)
1358 else // no need to truncate the title
1363 dc
.DrawLabel(s
, wxNullBitmap
, r
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1366 void wxStdRenderer::DrawFrameIcon(wxDC
& dc
,
1373 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1374 dc
.DrawIcon(icon
, r
.x
, r
.y
);
1378 void wxStdRenderer::DrawFrameButton(wxDC
& dc
,
1379 wxCoord x
, wxCoord y
,
1383 FrameButtonType idx
;
1386 case wxTOPLEVEL_BUTTON_CLOSE
: idx
= FrameButton_Close
; break;
1387 case wxTOPLEVEL_BUTTON_MAXIMIZE
: idx
= FrameButton_Maximize
; break;
1388 case wxTOPLEVEL_BUTTON_ICONIZE
: idx
= FrameButton_Minimize
; break;
1389 case wxTOPLEVEL_BUTTON_RESTORE
: idx
= FrameButton_Restore
; break;
1390 case wxTOPLEVEL_BUTTON_HELP
: idx
= FrameButton_Help
; break;
1392 wxFAIL_MSG(wxT("incorrect button specification"));
1396 wxBitmap bmp
= GetFrameButtonBitmap(idx
);
1400 wxRect
rectBtn(x
, y
, FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1401 if ( flags
& wxCONTROL_PRESSED
)
1403 DrawSunkenBorder(dc
, &rectBtn
);
1405 rectBtn
.Offset(1, 1);
1409 DrawRaisedBorder(dc
, &rectBtn
);
1412 DrawBackground(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rectBtn
);
1414 wxRect
rectBmp(0, 0, bmp
.GetWidth(), bmp
.GetHeight());
1415 dc
.DrawBitmap(bmp
, rectBmp
.CentreIn(rectBtn
).GetPosition(), true);
1419 wxRect
wxStdRenderer::GetFrameClientArea(const wxRect
& rect
, int flags
) const
1423 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1425 int border
= flags
& wxTOPLEVEL_RESIZEABLE
1426 ? RESIZEABLE_FRAME_BORDER_THICKNESS
1427 : FRAME_BORDER_THICKNESS
;
1431 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1433 r
.y
+= FRAME_TITLEBAR_HEIGHT
;
1434 r
.height
-= FRAME_TITLEBAR_HEIGHT
;
1441 wxStdRenderer::GetFrameTotalSize(const wxSize
& clientSize
, int flags
) const
1443 wxSize
s(clientSize
);
1445 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1447 int border
= flags
& wxTOPLEVEL_RESIZEABLE
1448 ? RESIZEABLE_FRAME_BORDER_THICKNESS
1449 : FRAME_BORDER_THICKNESS
;
1454 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1455 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1460 wxSize
wxStdRenderer::GetFrameMinSize(int flags
) const
1464 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1466 int border
= (flags
& wxTOPLEVEL_RESIZEABLE
) ?
1467 RESIZEABLE_FRAME_BORDER_THICKNESS
:
1468 FRAME_BORDER_THICKNESS
;
1473 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1475 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1477 if ( flags
& wxTOPLEVEL_ICON
)
1478 s
.x
+= FRAME_TITLEBAR_HEIGHT
+ 2;
1479 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1480 s
.x
+= FRAME_BUTTON_WIDTH
+ 2;
1481 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1482 s
.x
+= FRAME_BUTTON_WIDTH
;
1483 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1484 s
.x
+= FRAME_BUTTON_WIDTH
;
1485 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1486 s
.x
+= FRAME_BUTTON_WIDTH
;
1487 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1488 s
.x
+= FRAME_BUTTON_WIDTH
;
1494 wxSize
wxStdRenderer::GetFrameIconSize() const
1496 return wxSize(16, 16);