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"
29 #include "wx/univ/stdrend.h"
30 #include "wx/univ/colschem.h"
32 // ----------------------------------------------------------------------------
34 // ----------------------------------------------------------------------------
36 static const int FRAME_BORDER_THICKNESS
= 3;
37 static const int RESIZEABLE_FRAME_BORDER_THICKNESS
= 4;
38 static const int FRAME_TITLEBAR_HEIGHT
= 18;
39 static const int FRAME_BUTTON_WIDTH
= 16;
40 static const int FRAME_BUTTON_HEIGHT
= 14;
42 // ============================================================================
43 // wxStdRenderer implementation
44 // ============================================================================
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 wxStdRenderer::wxStdRenderer(const wxColourScheme
*scheme
)
53 m_penBlack
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_DARK
));
54 m_penDarkGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_OUT
));
55 m_penLightGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_IN
));
56 m_penHighlight
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_HIGHLIGHT
));
58 m_titlebarFont
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
59 m_titlebarFont
.SetWeight(wxFONTWEIGHT_BOLD
);
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
67 wxStdRenderer::DrawSolidRect(wxDC
& dc
, const wxColour
& col
, const wxRect
& rect
)
69 wxBrush
brush(col
, wxSOLID
);
71 dc
.SetPen(*wxTRANSPARENT_PEN
);
72 dc
.DrawRectangle(rect
);
75 void wxStdRenderer::DrawRect(wxDC
& dc
, wxRect
*rect
, const wxPen
& pen
)
79 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
80 dc
.DrawRectangle(*rect
);
86 void wxStdRenderer::DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
87 const wxPen
& pen1
, const wxPen
& pen2
)
91 dc
.DrawLine(rect
->GetLeft(), rect
->GetTop(),
92 rect
->GetLeft(), rect
->GetBottom());
93 dc
.DrawLine(rect
->GetLeft() + 1, rect
->GetTop(),
94 rect
->GetRight(), rect
->GetTop());
96 dc
.DrawLine(rect
->GetRight(), rect
->GetTop(),
97 rect
->GetRight(), rect
->GetBottom());
98 dc
.DrawLine(rect
->GetLeft(), rect
->GetBottom(),
99 rect
->GetRight() + 1, rect
->GetBottom());
105 // ----------------------------------------------------------------------------
106 // translate various flags into corresponding renderer constants
107 // ----------------------------------------------------------------------------
110 void wxStdRenderer::GetIndicatorsFromFlags(int flags
,
111 IndicatorState
& state
,
112 IndicatorStatus
& status
)
114 if ( flags
& wxCONTROL_SELECTED
)
115 state
= flags
& wxCONTROL_DISABLED
? IndicatorState_SelectedDisabled
116 : IndicatorState_Selected
;
117 else if ( flags
& wxCONTROL_DISABLED
)
118 state
= IndicatorState_Disabled
;
119 else if ( flags
& wxCONTROL_PRESSED
)
120 state
= IndicatorState_Pressed
;
122 state
= IndicatorState_Normal
;
124 status
= flags
& wxCONTROL_CHECKED
? IndicatorStatus_Checked
125 : flags
& wxCONTROL_UNDETERMINED
126 ? IndicatorStatus_Undetermined
127 : IndicatorStatus_Unchecked
;
131 wxStdRenderer::ArrowDirection
wxStdRenderer::GetArrowDirection(wxDirection dir
)
148 wxFAIL_MSG(_T("unknown arrow direction"));
154 // ----------------------------------------------------------------------------
156 // ----------------------------------------------------------------------------
158 void wxStdRenderer::DrawBackground(wxDC
& dc
,
164 wxColour colBg
= col
.Ok() ? col
165 : window
? m_scheme
->GetBackground(window
)
166 : wxSCHEME_COLOUR(m_scheme
, CONTROL
);
168 DrawSolidRect(dc
, colBg
, rect
);
172 void wxStdRenderer::DrawButtonSurface(wxDC
& dc
,
177 DrawBackground(dc
, col
, rect
, flags
);
180 // ----------------------------------------------------------------------------
182 // ----------------------------------------------------------------------------
184 void wxStdRenderer::DrawFocusRect(wxDC
& dc
, const wxRect
& rect
)
186 // draw the pixels manually because the "dots" in wxPen with wxDOT style
187 // may be short traits and not really dots
189 // note that to behave in the same manner as DrawRect(), we must exclude
190 // the bottom and right borders from the rectangle
191 wxCoord x1
= rect
.GetLeft(),
193 x2
= rect
.GetRight(),
194 y2
= rect
.GetBottom();
196 dc
.SetPen(m_penBlack
);
198 // this seems to be closer than what Windows does than wxINVERT although
199 // I'm still not sure if it's correct
200 dc
.SetLogicalFunction(wxAND_REVERSE
);
203 for ( z
= x1
+ 1; z
< x2
; z
+= 2 )
204 dc
.DrawPoint(z
, rect
.GetTop());
206 wxCoord shift
= z
== x2
? 0 : 1;
207 for ( z
= y1
+ shift
; z
< y2
; z
+= 2 )
210 shift
= z
== y2
? 0 : 1;
211 for ( z
= x2
- shift
; z
> x1
; z
-= 2 )
214 shift
= z
== x1
? 0 : 1;
215 for ( z
= y2
- shift
; z
> y1
; z
-= 2 )
218 dc
.SetLogicalFunction(wxCOPY
);
221 void wxStdRenderer::DrawLabel(wxDC
& dc
,
222 const wxString
& label
,
229 DrawButtonLabel(dc
, label
, wxNullBitmap
, rect
, flags
,
230 alignment
, indexAccel
, rectBounds
);
233 void wxStdRenderer::DrawButtonLabel(wxDC
& dc
,
234 const wxString
& label
,
235 const wxBitmap
& image
,
242 wxRect rectLabel
= rect
;
243 if ( !label
.empty() && (flags
& wxCONTROL_DISABLED
) )
245 if ( flags
& wxCONTROL_PRESSED
)
247 // shift the label if a button is pressed
248 rectLabel
.Offset(1, 1);
251 // draw shadow of the text
252 dc
.SetTextForeground(m_penHighlight
.GetColour());
253 wxRect rectShadow
= rect
;
254 rectShadow
.Offset(1, 1);
255 dc
.DrawLabel(label
, rectShadow
, alignment
, indexAccel
);
257 // make the main label text grey
258 dc
.SetTextForeground(m_penDarkGrey
.GetColour());
260 if ( flags
& wxCONTROL_FOCUSED
)
262 // leave enough space for the focus rect
263 rectLabel
.Inflate(-2);
267 dc
.DrawLabel(label
, image
, rectLabel
, alignment
, indexAccel
, rectBounds
);
269 if ( !label
.empty() && (flags
& wxCONTROL_FOCUSED
) )
271 rectLabel
.Inflate(-1);
273 DrawFocusRect(dc
, rectLabel
);
277 // ----------------------------------------------------------------------------
279 // ----------------------------------------------------------------------------
282 We implement standard-looking 3D borders which have the following appearance:
286 WWWWWWWWWWWWWWWWWWWWWWB
287 WHHHHHHHHHHHHHHHHHHHHGB
288 WH GB W = white (HILIGHT)
289 WH GB H = light grey (LIGHT)
290 WH GB G = dark grey (SHADOI)
291 WH GB B = black (DKSHADOI)
294 WGGGGGGGGGGGGGGGGGGGGGB
295 BBBBBBBBBBBBBBBBBBBBBBB
297 The sunken border looks like this:
299 GGGGGGGGGGGGGGGGGGGGGGW
300 GBBBBBBBBBBBBBBBBBBBBHW
307 GHHHHHHHHHHHHHHHHHHHHHW
308 WWWWWWWWWWWWWWWWWWWWWWW
310 The static border (used for the controls which don't get focus) is like
313 GGGGGGGGGGGGGGGGGGGGGGW
321 WWWWWWWWWWWWWWWWWWWWWWW
323 The most complicated is the double border which is a combination of special
324 "anti-sunken" border and an extra border inside it:
326 HHHHHHHHHHHHHHHHHHHHHHB
327 HWWWWWWWWWWWWWWWWWWWWGB
328 HWHHHHHHHHHHHHHHHHHHHGB
333 HWHHHHHHHHHHHHHHHHHHHGB
334 HGGGGGGGGGGGGGGGGGGGGGB
335 BBBBBBBBBBBBBBBBBBBBBBB
337 And the simple border is, well, simple:
339 BBBBBBBBBBBBBBBBBBBBBBB
348 BBBBBBBBBBBBBBBBBBBBBBB
351 void wxStdRenderer::DrawRaisedBorder(wxDC
& dc
, wxRect
*rect
)
353 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penBlack
);
354 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penDarkGrey
);
357 void wxStdRenderer::DrawSunkenBorder(wxDC
& dc
, wxRect
*rect
)
359 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
360 DrawShadedRect(dc
, rect
, m_penBlack
, m_penLightGrey
);
363 void wxStdRenderer::DrawAntiSunkenBorder(wxDC
& dc
, wxRect
*rect
)
365 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penBlack
);
366 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
369 void wxStdRenderer::DrawFrameBorder(wxDC
& dc
, wxRect
*rect
)
371 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
372 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
375 void wxStdRenderer::DrawBorder(wxDC
& dc
,
377 const wxRect
& rectTotal
,
381 wxRect rect
= rectTotal
;
385 case wxBORDER_SUNKEN
:
386 DrawSunkenBorder(dc
, &rect
);
389 case wxBORDER_DOUBLE
:
390 DrawAntiSunkenBorder(dc
, &rect
);
391 DrawRect(dc
, &rect
, m_penLightGrey
);
394 case wxBORDER_STATIC
:
395 DrawShadedRect(dc
, &rect
, m_penDarkGrey
, m_penHighlight
);
398 case wxBORDER_RAISED
:
399 DrawRaisedBorder(dc
, &rect
);
402 case wxBORDER_SIMPLE
:
403 DrawRect(dc
, &rect
, m_penBlack
);
407 wxFAIL_MSG(_T("unknown border type"));
410 case wxBORDER_DEFAULT
:
419 wxRect
wxStdRenderer::GetBorderDimensions(wxBorder border
) const
424 case wxBORDER_SIMPLE
:
425 case wxBORDER_STATIC
:
429 case wxBORDER_RAISED
:
430 case wxBORDER_SUNKEN
:
434 case wxBORDER_DOUBLE
:
439 wxFAIL_MSG(_T("unknown border type"));
442 case wxBORDER_DEFAULT
:
457 void wxStdRenderer::AdjustSize(wxSize
*size
, const wxWindow
*window
)
459 // take into account the border width
460 wxRect rectBorder
= GetBorderDimensions(window
->GetBorder());
461 size
->x
+= rectBorder
.x
+ rectBorder
.width
;
462 size
->y
+= rectBorder
.y
+ rectBorder
.height
;
465 bool wxStdRenderer::AreScrollbarsInsideBorder() const
470 wxCoord
wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight
)
472 return fontHeight
+ 2;
475 void wxStdRenderer::DrawTextBorder(wxDC
& dc
,
481 DrawBorder(dc
, border
, rect
, flags
, rectIn
);
484 // ----------------------------------------------------------------------------
486 // ----------------------------------------------------------------------------
489 wxStdRenderer::DrawHorizontalLine(wxDC
& dc
, wxCoord y
, wxCoord x1
, wxCoord x2
)
491 dc
.SetPen(m_penDarkGrey
);
492 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
494 dc
.SetPen(m_penHighlight
);
496 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
500 wxStdRenderer::DrawVerticalLine(wxDC
& dc
, wxCoord x
, wxCoord y1
, wxCoord y2
)
502 dc
.SetPen(m_penDarkGrey
);
503 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
505 dc
.SetPen(m_penHighlight
);
507 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
510 void wxStdRenderer::DrawFrameWithoutLabel(wxDC
& dc
,
511 const wxRect
& rectFrame
,
512 const wxRect
& rectLabel
)
514 // draw left, bottom and right lines entirely
515 DrawVerticalLine(dc
, rectFrame
.GetLeft(),
516 rectFrame
.GetTop(), rectFrame
.GetBottom() - 2);
517 DrawHorizontalLine(dc
, rectFrame
.GetBottom() - 1,
518 rectFrame
.GetLeft(), rectFrame
.GetRight());
519 DrawVerticalLine(dc
, rectFrame
.GetRight() - 1,
520 rectFrame
.GetTop(), rectFrame
.GetBottom() - 1);
522 // and 2 parts of the top line
523 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
524 rectFrame
.GetLeft() + 1, rectLabel
.GetLeft());
525 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
526 rectLabel
.GetRight(), rectFrame
.GetRight() - 2);
529 void wxStdRenderer::DrawFrameWithLabel(wxDC
& dc
,
530 const wxString
& label
,
531 const wxRect
& rectFrame
,
532 const wxRect
& rectText
,
538 DrawLabel(dc
, label
, rectText
, flags
, alignment
, indexAccel
, &rectLabel
);
540 DrawFrameWithoutLabel(dc
, rectFrame
, rectLabel
);
543 void wxStdRenderer::DrawFrame(wxDC
& dc
,
544 const wxString
& label
,
550 wxCoord height
= 0; // of the label
551 wxRect rectFrame
= rect
;
552 if ( !label
.empty() )
554 // the text should touch the top border of the rect, so the frame
555 // itself should be lower
556 dc
.GetTextExtent(label
, NULL
, &height
);
557 rectFrame
.y
+= height
/ 2;
558 rectFrame
.height
-= height
/ 2;
560 // we have to draw each part of the frame individually as we can't
561 // erase the background beyond the label as it might contain some
562 // pixmap already, so drawing everything and then overwriting part of
563 // the frame with label doesn't work
565 // TODO: the +5 shouldn't be hard coded
567 rectText
.x
= rectFrame
.x
+ 5;
569 rectText
.width
= rectFrame
.width
- 7; // +2 border width
570 rectText
.height
= height
;
572 DrawFrameWithLabel(dc
, label
, rectFrame
, rectText
, flags
,
573 alignment
, indexAccel
);
577 DrawFrameBorder(dc
, &rectFrame
);
581 void wxStdRenderer::DrawItem(wxDC
& dc
,
582 const wxString
& label
,
586 wxDCTextColourChanger
colChanger(dc
);
588 if ( flags
& wxCONTROL_SELECTED
)
590 colChanger
.Set(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
592 const wxColour colBg
= wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
);
595 dc
.DrawRectangle(rect
);
598 wxRect rectText
= rect
;
601 dc
.DrawLabel(label
, wxNullBitmap
, rectText
);
603 if ( flags
& wxCONTROL_FOCUSED
)
605 DrawFocusRect(dc
, rect
);
609 void wxStdRenderer::DrawCheckItemBitmap(wxDC
& dc
,
610 const wxBitmap
& bitmap
,
614 DrawCheckButton(dc
, wxEmptyString
, bitmap
, rect
, flags
);
617 void wxStdRenderer::DrawCheckItem(wxDC
& dc
,
618 const wxString
& label
,
619 const wxBitmap
& bitmap
,
623 wxRect rectBitmap
= rect
;
624 rectBitmap
.width
= GetCheckBitmapSize().x
;
625 DrawCheckItemBitmap(dc
, bitmap
, rectBitmap
, flags
);
627 wxRect rectLabel
= rect
;
628 wxCoord shift
= rectBitmap
.width
+ 2*GetCheckItemMargin();
629 rectLabel
.x
+= shift
;
630 rectLabel
.width
-= shift
;
631 DrawItem(dc
, label
, rectLabel
, flags
);
634 // ----------------------------------------------------------------------------
635 // check and radio bitmaps
636 // ----------------------------------------------------------------------------
638 void wxStdRenderer::DrawCheckButton(wxDC
& dc
,
639 const wxString
& label
,
640 const wxBitmap
& bitmap
,
646 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetCheckBitmap(flags
));
648 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
651 void wxStdRenderer::DrawRadioButton(wxDC
& dc
,
652 const wxString
& label
,
653 const wxBitmap
& bitmap
,
659 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetRadioBitmap(flags
));
661 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
664 void wxStdRenderer::DrawCheckOrRadioButton(wxDC
& dc
,
665 const wxString
& label
,
666 const wxBitmap
& bitmap
,
672 // calculate the position of the bitmap and of the label
673 wxCoord heightBmp
= bitmap
.GetHeight();
675 yBmp
= rect
.y
+ (rect
.height
- heightBmp
) / 2;
678 dc
.GetMultiLineTextExtent(label
, NULL
, &rectLabel
.height
);
679 rectLabel
.y
= rect
.y
+ (rect
.height
- rectLabel
.height
) / 2;
681 // align label vertically with the bitmap - looks nicer like this
682 rectLabel
.y
-= (rectLabel
.height
- heightBmp
) % 2;
684 // calc horz position
685 if ( align
== wxALIGN_RIGHT
)
687 xBmp
= rect
.GetRight() - bitmap
.GetWidth();
688 rectLabel
.x
= rect
.x
+ 3;
689 rectLabel
.SetRight(xBmp
);
691 else // normal (checkbox to the left of the text) case
694 rectLabel
.x
= xBmp
+ bitmap
.GetWidth() + 5;
695 rectLabel
.SetRight(rect
.GetRight());
698 dc
.DrawBitmap(bitmap
, xBmp
, yBmp
, true /* use mask */);
700 DrawLabel(dc
, label
, rectLabel
, flags
,
701 wxALIGN_LEFT
| wxALIGN_TOP
, indexAccel
);
706 void wxStdRenderer::DrawTextLine(wxDC
& dc
,
707 const wxString
& text
,
713 if ( (selStart
== -1) || !(flags
& wxCONTROL_FOCUSED
) )
715 // just draw it as is
716 dc
.DrawText(text
, rect
.x
, rect
.y
);
718 else // we have selection
723 // draw the part before selection
724 wxString
s(text
, (size_t)selStart
);
727 dc
.DrawText(s
, x
, rect
.y
);
729 dc
.GetTextExtent(s
, &width
, NULL
);
733 // draw the selection itself
734 s
= wxString(text
.c_str() + selStart
, text
.c_str() + selEnd
);
737 wxColour colFg
= dc
.GetTextForeground(),
738 colBg
= dc
.GetTextBackground();
739 dc
.SetTextForeground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
740 dc
.SetTextBackground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
));
741 dc
.SetBackgroundMode(wxSOLID
);
743 dc
.DrawText(s
, x
, rect
.y
);
744 dc
.GetTextExtent(s
, &width
, NULL
);
747 dc
.SetBackgroundMode(wxTRANSPARENT
);
748 dc
.SetTextBackground(colBg
);
749 dc
.SetTextForeground(colFg
);
752 // draw the final part
753 s
= text
.c_str() + selEnd
;
756 dc
.DrawText(s
, x
, rect
.y
);
761 void wxStdRenderer::DrawLineWrapMark(wxDC
& WXUNUSED(dc
),
762 const wxRect
& WXUNUSED(rect
))
764 // nothing by default
767 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl
* WXUNUSED(text
)) const
773 wxStdRenderer::GetTextTotalArea(const wxTextCtrl
*text
, const wxRect
& rect
) const
775 wxRect rectTotal
= rect
;
776 rectTotal
.Inflate(GetTextBorderWidth(text
));
780 wxRect
wxStdRenderer::GetTextClientArea(const wxTextCtrl
*text
,
782 wxCoord
*extraSpaceBeyond
) const
784 wxRect rectText
= rect
;
785 rectText
.Deflate(GetTextBorderWidth(text
));
787 if ( extraSpaceBeyond
)
788 *extraSpaceBeyond
= 0;
793 #endif // wxUSE_TEXTCTRL
795 // ----------------------------------------------------------------------------
796 // scrollbars drawing
797 // ----------------------------------------------------------------------------
799 void wxStdRenderer::DrawScrollbarArrow(wxDC
& dc
,
804 DrawArrow(dc
, dir
, rect
, flags
);
807 void wxStdRenderer::DrawScrollCorner(wxDC
& dc
, const wxRect
& rect
)
809 DrawSolidRect(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rect
);
812 // ----------------------------------------------------------------------------
813 // scrollbars geometry
814 // ----------------------------------------------------------------------------
819 void wxStdRenderer::GetScrollBarThumbSize(wxCoord length
,
826 // the thumb can't be made less than this number of pixels
827 static const wxCoord thumbMinWidth
= 8; // FIXME: should be configurable
829 *thumbStart
= (length
*thumbPos
) / range
;
830 *thumbEnd
= (length
*(thumbPos
+ thumbSize
)) / range
;
832 if ( *thumbEnd
- *thumbStart
< thumbMinWidth
)
834 // adjust the end if possible
835 if ( *thumbStart
<= length
- thumbMinWidth
)
837 // yes, just make it wider
838 *thumbEnd
= *thumbStart
+ thumbMinWidth
;
840 else // it is at the bottom of the scrollbar
842 // so move it a bit up
843 *thumbStart
= length
- thumbMinWidth
;
849 wxRect
wxStdRenderer::GetScrollbarRect(const wxScrollBar
*scrollbar
,
850 wxScrollBar::Element elem
,
853 if ( thumbPos
== -1 )
855 thumbPos
= scrollbar
->GetThumbPosition();
858 const wxSize sizeArrow
= GetScrollbarArrowSize();
860 wxSize sizeTotal
= scrollbar
->GetClientSize();
861 wxCoord
*start
, *width
;
862 wxCoord length
, arrow
;
864 if ( scrollbar
->IsVertical() )
867 rect
.width
= sizeTotal
.x
;
868 length
= sizeTotal
.y
;
870 width
= &rect
.height
;
876 rect
.height
= sizeTotal
.y
;
877 length
= sizeTotal
.x
;
885 case wxScrollBar::Element_Arrow_Line_1
:
890 case wxScrollBar::Element_Arrow_Line_2
:
891 *start
= length
- arrow
;
895 case wxScrollBar::Element_Arrow_Page_1
:
896 case wxScrollBar::Element_Arrow_Page_2
:
897 // we don't have them at all
900 case wxScrollBar::Element_Thumb
:
901 case wxScrollBar::Element_Bar_1
:
902 case wxScrollBar::Element_Bar_2
:
903 // we need to calculate the thumb position - do it
906 wxCoord thumbStart
, thumbEnd
;
907 int range
= scrollbar
->GetRange();
915 GetScrollBarThumbSize(length
,
917 scrollbar
->GetThumbSize(),
923 if ( elem
== wxScrollBar::Element_Thumb
)
926 *width
= thumbEnd
- thumbStart
;
928 else if ( elem
== wxScrollBar::Element_Bar_1
)
933 else // elem == wxScrollBar::Element_Bar_2
936 *width
= length
- thumbEnd
;
939 // everything is relative to the start of the shaft so far
944 case wxScrollBar::Element_Max
:
946 wxFAIL_MSG( _T("unknown scrollbar element") );
952 wxCoord
wxStdRenderer::GetScrollbarSize(const wxScrollBar
*scrollbar
)
954 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
956 wxCoord sizeArrow
, sizeTotal
;
957 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
959 sizeArrow
= sizeArrowSB
.y
;
960 sizeTotal
= scrollbar
->GetSize().y
;
964 sizeArrow
= sizeArrowSB
.x
;
965 sizeTotal
= scrollbar
->GetSize().x
;
968 return sizeTotal
- 2*sizeArrow
;
972 wxStdRenderer::HitTestScrollbar(const wxScrollBar
*scrollbar
, const wxPoint
& pt
) const
974 // we only need to work with either x or y coord depending on the
975 // orientation, choose one (but still check the other one to verify if the
976 // mouse is in the window at all)
977 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
979 wxCoord coord
, sizeArrow
, sizeTotal
;
980 wxSize size
= scrollbar
->GetSize();
981 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
983 if ( pt
.x
< 0 || pt
.x
> size
.x
)
987 sizeArrow
= sizeArrowSB
.y
;
992 if ( pt
.y
< 0 || pt
.y
> size
.y
)
996 sizeArrow
= sizeArrowSB
.x
;
1000 // test for the arrows first as it's faster
1001 if ( coord
< 0 || coord
> sizeTotal
)
1003 return wxHT_NOWHERE
;
1005 else if ( coord
< sizeArrow
)
1007 return wxHT_SCROLLBAR_ARROW_LINE_1
;
1009 else if ( coord
> sizeTotal
- sizeArrow
)
1011 return wxHT_SCROLLBAR_ARROW_LINE_2
;
1015 // calculate the thumb position in pixels
1016 sizeTotal
-= 2*sizeArrow
;
1017 wxCoord thumbStart
, thumbEnd
;
1018 int range
= scrollbar
->GetRange();
1021 // clicking the scrollbar without range has no effect
1022 return wxHT_NOWHERE
;
1026 GetScrollBarThumbSize(sizeTotal
,
1027 scrollbar
->GetThumbPosition(),
1028 scrollbar
->GetThumbSize(),
1034 // now compare with the thumb position
1036 if ( coord
< thumbStart
)
1037 return wxHT_SCROLLBAR_BAR_1
;
1038 else if ( coord
> thumbEnd
)
1039 return wxHT_SCROLLBAR_BAR_2
;
1041 return wxHT_SCROLLBAR_THUMB
;
1047 wxStdRenderer::ScrollbarToPixel(const wxScrollBar
*scrollbar
, int thumbPos
)
1049 int range
= scrollbar
->GetRange();
1052 // the only valid position anyhow
1056 if ( thumbPos
== -1 )
1058 // by default use the current thumb position
1059 thumbPos
= scrollbar
->GetThumbPosition();
1062 const wxSize sizeArrow
= GetScrollbarArrowSize();
1063 return (thumbPos
*GetScrollbarSize(scrollbar
)) / range
1064 + (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
);
1067 int wxStdRenderer::PixelToScrollbar(const wxScrollBar
*scrollbar
, wxCoord coord
)
1069 const wxSize sizeArrow
= GetScrollbarArrowSize();
1070 return ((coord
- (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
)) *
1071 scrollbar
->GetRange() ) / GetScrollbarSize(scrollbar
);
1074 #endif // wxUSE_SCROLLBAR
1076 // ----------------------------------------------------------------------------
1078 // ----------------------------------------------------------------------------
1082 wxSize
wxStdRenderer::GetStatusBarBorders(wxCoord
*borderBetweenFields
) const
1084 if ( borderBetweenFields
)
1085 *borderBetweenFields
= 2;
1087 return wxSize(2, 2);
1090 void wxStdRenderer::DrawStatusField(wxDC
& dc
,
1092 const wxString
& label
,
1098 if ( style
== wxSB_RAISED
)
1099 DrawBorder(dc
, wxBORDER_RAISED
, rect
, flags
, &rectIn
);
1100 else if ( style
!= wxSB_FLAT
)
1101 DrawBorder(dc
, wxBORDER_STATIC
, rect
, flags
, &rectIn
);
1103 rectIn
.Deflate(GetStatusBarBorders(NULL
));
1105 wxDCClipper
clipper(dc
, rectIn
);
1106 DrawLabel(dc
, label
, rectIn
, flags
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1109 #endif // wxUSE_STATUSBAR
1111 // ----------------------------------------------------------------------------
1112 // top level windows
1113 // ----------------------------------------------------------------------------
1115 int wxStdRenderer::HitTestFrame(const wxRect
& rect
, const wxPoint
& pt
, int flags
) const
1117 wxRect client
= GetFrameClientArea(rect
, flags
);
1119 if ( client
.Contains(pt
) )
1120 return wxHT_TOPLEVEL_CLIENT_AREA
;
1122 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1124 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1126 if ( flags
& wxTOPLEVEL_ICON
)
1128 if ( wxRect(client
.GetPosition(), GetFrameIconSize()).Contains(pt
) )
1129 return wxHT_TOPLEVEL_ICON
;
1132 wxRect
btnRect(client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
,
1133 client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2,
1134 FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1136 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1138 if ( btnRect
.Contains(pt
) )
1139 return wxHT_TOPLEVEL_BUTTON_CLOSE
;
1140 btnRect
.x
-= FRAME_BUTTON_WIDTH
+ 2;
1142 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1144 if ( btnRect
.Contains(pt
) )
1145 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE
;
1146 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1148 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1150 if ( btnRect
.Contains(pt
) )
1151 return wxHT_TOPLEVEL_BUTTON_RESTORE
;
1152 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1154 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1156 if ( btnRect
.Contains(pt
) )
1157 return wxHT_TOPLEVEL_BUTTON_ICONIZE
;
1158 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1160 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1162 if ( btnRect
.Contains(pt
) )
1163 return wxHT_TOPLEVEL_BUTTON_HELP
;
1164 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1167 if ( pt
.y
>= client
.y
&& pt
.y
< client
.y
+ FRAME_TITLEBAR_HEIGHT
)
1168 return wxHT_TOPLEVEL_TITLEBAR
;
1171 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1173 // we are certainly at one of borders, let's decide which one:
1176 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
1177 if ( pt
.x
< client
.x
)
1178 border
|= wxHT_TOPLEVEL_BORDER_W
;
1179 else if ( pt
.x
>= client
.width
+ client
.x
)
1180 border
|= wxHT_TOPLEVEL_BORDER_E
;
1181 if ( pt
.y
< client
.y
)
1182 border
|= wxHT_TOPLEVEL_BORDER_N
;
1183 else if ( pt
.y
>= client
.height
+ client
.y
)
1184 border
|= wxHT_TOPLEVEL_BORDER_S
;
1188 return wxHT_NOWHERE
;
1191 void wxStdRenderer::DrawFrameTitleBar(wxDC
& dc
,
1193 const wxString
& title
,
1197 int specialButtonFlags
)
1199 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1201 DrawFrameBorder(dc
, rect
, flags
);
1203 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1205 DrawFrameBackground(dc
, rect
, flags
);
1206 if ( flags
& wxTOPLEVEL_ICON
)
1207 DrawFrameIcon(dc
, rect
, icon
, flags
);
1208 DrawFrameTitle(dc
, rect
, title
, flags
);
1210 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1212 x
= client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
;
1213 y
= client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2;
1215 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1217 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_CLOSE
,
1218 (specialButton
== wxTOPLEVEL_BUTTON_CLOSE
) ?
1219 specialButtonFlags
: 0);
1220 x
-= FRAME_BUTTON_WIDTH
+ 2;
1222 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1224 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_MAXIMIZE
,
1225 (specialButton
== wxTOPLEVEL_BUTTON_MAXIMIZE
) ?
1226 specialButtonFlags
: 0);
1227 x
-= FRAME_BUTTON_WIDTH
;
1229 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1231 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_RESTORE
,
1232 (specialButton
== wxTOPLEVEL_BUTTON_RESTORE
) ?
1233 specialButtonFlags
: 0);
1234 x
-= FRAME_BUTTON_WIDTH
;
1236 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1238 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_ICONIZE
,
1239 (specialButton
== wxTOPLEVEL_BUTTON_ICONIZE
) ?
1240 specialButtonFlags
: 0);
1241 x
-= FRAME_BUTTON_WIDTH
;
1243 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1245 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_HELP
,
1246 (specialButton
== wxTOPLEVEL_BUTTON_HELP
) ?
1247 specialButtonFlags
: 0);
1252 void wxStdRenderer::DrawFrameBorder(wxDC
& dc
, const wxRect
& rect
, int flags
)
1254 if ( !(flags
& wxTOPLEVEL_BORDER
) )
1259 DrawShadedRect(dc
, &r
, m_penLightGrey
, m_penBlack
);
1260 DrawShadedRect(dc
, &r
, m_penHighlight
, m_penDarkGrey
);
1261 DrawShadedRect(dc
, &r
, m_penLightGrey
, m_penLightGrey
);
1262 if ( flags
& wxTOPLEVEL_RESIZEABLE
)
1263 DrawShadedRect(dc
, &r
, m_penLightGrey
, m_penLightGrey
);
1266 void wxStdRenderer::DrawFrameBackground(wxDC
& dc
, const wxRect
& rect
, int flags
)
1268 if ( !(flags
& wxTOPLEVEL_TITLEBAR
) )
1271 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1272 ? wxColourScheme::TITLEBAR_ACTIVE
1273 : wxColourScheme::TITLEBAR
);
1275 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1276 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1278 DrawBackground(dc
, col
, r
);
1281 void wxStdRenderer::DrawFrameTitle(wxDC
& dc
,
1283 const wxString
& title
,
1286 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1287 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1288 : wxColourScheme::TITLEBAR_TEXT
);
1289 dc
.SetTextForeground(col
);
1291 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1292 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1293 if ( flags
& wxTOPLEVEL_ICON
)
1295 r
.x
+= FRAME_TITLEBAR_HEIGHT
;
1296 r
.width
-= FRAME_TITLEBAR_HEIGHT
+ 2;
1304 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1305 r
.width
-= FRAME_BUTTON_WIDTH
+ 2;
1306 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1307 r
.width
-= FRAME_BUTTON_WIDTH
;
1308 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1309 r
.width
-= FRAME_BUTTON_WIDTH
;
1310 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1311 r
.width
-= FRAME_BUTTON_WIDTH
;
1312 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1313 r
.width
-= FRAME_BUTTON_WIDTH
;
1315 dc
.SetFont(m_titlebarFont
);
1319 dc
.GetTextExtent(title
, &textW
, NULL
);
1320 if ( textW
> r
.width
)
1322 // text is too big, let's shorten it and add "..." after it:
1323 size_t len
= title
.length();
1324 wxCoord WSoFar
, letterW
;
1326 dc
.GetTextExtent(wxT("..."), &WSoFar
, NULL
);
1327 if ( WSoFar
> r
.width
)
1329 // not enough space to draw anything
1334 for (size_t i
= 0; i
< len
; i
++)
1336 dc
.GetTextExtent(title
[i
], &letterW
, NULL
);
1337 if ( letterW
+ WSoFar
> r
.width
)
1344 else // no need to truncate the title
1349 dc
.DrawLabel(s
, wxNullBitmap
, r
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1352 void wxStdRenderer::DrawFrameIcon(wxDC
& dc
,
1359 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1360 dc
.DrawIcon(icon
, r
.x
, r
.y
);
1364 void wxStdRenderer::DrawFrameButton(wxDC
& dc
,
1365 wxCoord x
, wxCoord y
,
1369 FrameButtonType idx
;
1372 case wxTOPLEVEL_BUTTON_CLOSE
: idx
= FrameButton_Close
; break;
1373 case wxTOPLEVEL_BUTTON_MAXIMIZE
: idx
= FrameButton_Maximize
; break;
1374 case wxTOPLEVEL_BUTTON_ICONIZE
: idx
= FrameButton_Minimize
; break;
1375 case wxTOPLEVEL_BUTTON_RESTORE
: idx
= FrameButton_Restore
; break;
1376 case wxTOPLEVEL_BUTTON_HELP
: idx
= FrameButton_Help
; break;
1378 wxFAIL_MSG(wxT("incorrect button specification"));
1382 wxBitmap bmp
= GetFrameButtonBitmap(idx
);
1386 wxRect
rectBtn(x
, y
, FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1387 if ( flags
& wxCONTROL_PRESSED
)
1389 DrawSunkenBorder(dc
, &rectBtn
);
1396 DrawRaisedBorder(dc
, &rectBtn
);
1399 DrawBackground(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rectBtn
);
1401 wxRect
rectBmp(0, 0, bmp
.GetWidth(), bmp
.GetHeight());
1402 dc
.DrawBitmap(bmp
, rectBmp
.CentreIn(rectBtn
).GetPosition(), true);
1406 wxRect
wxStdRenderer::GetFrameClientArea(const wxRect
& rect
, int flags
) const
1410 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1412 int border
= flags
& wxTOPLEVEL_RESIZEABLE
1413 ? RESIZEABLE_FRAME_BORDER_THICKNESS
1414 : FRAME_BORDER_THICKNESS
;
1418 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1420 r
.y
+= FRAME_TITLEBAR_HEIGHT
;
1421 r
.height
-= FRAME_TITLEBAR_HEIGHT
;
1428 wxStdRenderer::GetFrameTotalSize(const wxSize
& clientSize
, int flags
) const
1430 wxSize
s(clientSize
);
1432 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1434 int border
= flags
& wxTOPLEVEL_RESIZEABLE
1435 ? RESIZEABLE_FRAME_BORDER_THICKNESS
1436 : FRAME_BORDER_THICKNESS
;
1441 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1442 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1447 wxSize
wxStdRenderer::GetFrameMinSize(int flags
) const
1451 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1453 int border
= (flags
& wxTOPLEVEL_RESIZEABLE
) ?
1454 RESIZEABLE_FRAME_BORDER_THICKNESS
:
1455 FRAME_BORDER_THICKNESS
;
1460 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1462 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1464 if ( flags
& wxTOPLEVEL_ICON
)
1465 s
.x
+= FRAME_TITLEBAR_HEIGHT
+ 2;
1466 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1467 s
.x
+= FRAME_BUTTON_WIDTH
+ 2;
1468 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1469 s
.x
+= FRAME_BUTTON_WIDTH
;
1470 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1471 s
.x
+= FRAME_BUTTON_WIDTH
;
1472 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1473 s
.x
+= FRAME_BUTTON_WIDTH
;
1474 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1475 s
.x
+= FRAME_BUTTON_WIDTH
;
1481 wxSize
wxStdRenderer::GetFrameIconSize() const
1483 return wxSize(16, 16);