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_TITLEBAR_HEIGHT
= 18;
42 static const int FRAME_BUTTON_WIDTH
= 16;
43 static const int FRAME_BUTTON_HEIGHT
= 14;
45 // ============================================================================
46 // wxStdRenderer implementation
47 // ============================================================================
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 wxStdRenderer::wxStdRenderer(const wxColourScheme
*scheme
)
56 m_penBlack
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_DARK
));
57 m_penDarkGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_OUT
));
58 m_penLightGrey
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_IN
));
59 m_penHighlight
= wxPen(wxSCHEME_COLOUR(scheme
, SHADOW_HIGHLIGHT
));
61 m_titlebarFont
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
62 m_titlebarFont
.SetWeight(wxFONTWEIGHT_BOLD
);
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
70 wxStdRenderer::DrawSolidRect(wxDC
& dc
, const wxColour
& col
, const wxRect
& rect
)
72 wxBrush
brush(col
, wxSOLID
);
74 dc
.SetPen(*wxTRANSPARENT_PEN
);
75 dc
.DrawRectangle(rect
);
78 void wxStdRenderer::DrawRect(wxDC
& dc
, wxRect
*rect
, const wxPen
& pen
)
82 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
83 dc
.DrawRectangle(*rect
);
89 void wxStdRenderer::DrawShadedRect(wxDC
& dc
, wxRect
*rect
,
90 const wxPen
& pen1
, const wxPen
& pen2
)
94 dc
.DrawLine(rect
->GetLeft(), rect
->GetTop(),
95 rect
->GetLeft(), rect
->GetBottom());
96 dc
.DrawLine(rect
->GetLeft() + 1, rect
->GetTop(),
97 rect
->GetRight(), rect
->GetTop());
99 dc
.DrawLine(rect
->GetRight(), rect
->GetTop(),
100 rect
->GetRight(), rect
->GetBottom());
101 dc
.DrawLine(rect
->GetLeft(), rect
->GetBottom(),
102 rect
->GetRight() + 1, rect
->GetBottom());
108 // ----------------------------------------------------------------------------
109 // translate various flags into corresponding renderer constants
110 // ----------------------------------------------------------------------------
113 void wxStdRenderer::GetIndicatorsFromFlags(int flags
,
114 IndicatorState
& state
,
115 IndicatorStatus
& status
)
117 if ( flags
& wxCONTROL_SELECTED
)
118 state
= flags
& wxCONTROL_DISABLED
? IndicatorState_SelectedDisabled
119 : IndicatorState_Selected
;
120 else if ( flags
& wxCONTROL_DISABLED
)
121 state
= IndicatorState_Disabled
;
122 else if ( flags
& wxCONTROL_PRESSED
)
123 state
= IndicatorState_Pressed
;
125 state
= IndicatorState_Normal
;
127 status
= flags
& wxCONTROL_CHECKED
? IndicatorStatus_Checked
128 : flags
& wxCONTROL_UNDETERMINED
129 ? IndicatorStatus_Undetermined
130 : IndicatorStatus_Unchecked
;
134 wxStdRenderer::ArrowDirection
wxStdRenderer::GetArrowDirection(wxDirection dir
)
151 wxFAIL_MSG(_T("unknown arrow direction"));
157 // ----------------------------------------------------------------------------
159 // ----------------------------------------------------------------------------
161 void wxStdRenderer::DrawBackground(wxDC
& dc
,
167 wxColour colBg
= col
.Ok() ? col
168 : window
? m_scheme
->GetBackground(window
)
169 : wxSCHEME_COLOUR(m_scheme
, CONTROL
);
171 DrawSolidRect(dc
, colBg
, rect
);
175 void wxStdRenderer::DrawButtonSurface(wxDC
& dc
,
180 DrawBackground(dc
, col
, rect
, flags
);
183 // ----------------------------------------------------------------------------
185 // ----------------------------------------------------------------------------
187 void wxStdRenderer::DrawFocusRect(wxDC
& dc
, const wxRect
& rect
)
189 // draw the pixels manually because the "dots" in wxPen with wxDOT style
190 // may be short traits and not really dots
192 // note that to behave in the same manner as DrawRect(), we must exclude
193 // the bottom and right borders from the rectangle
194 wxCoord x1
= rect
.GetLeft(),
196 x2
= rect
.GetRight(),
197 y2
= rect
.GetBottom();
199 dc
.SetPen(m_penBlack
);
201 // this seems to be closer than what Windows does than wxINVERT although
202 // I'm still not sure if it's correct
203 dc
.SetLogicalFunction(wxAND_REVERSE
);
206 for ( z
= x1
+ 1; z
< x2
; z
+= 2 )
207 dc
.DrawPoint(z
, rect
.GetTop());
209 wxCoord shift
= z
== x2
? 0 : 1;
210 for ( z
= y1
+ shift
; z
< y2
; z
+= 2 )
213 shift
= z
== y2
? 0 : 1;
214 for ( z
= x2
- shift
; z
> x1
; z
-= 2 )
217 shift
= z
== x1
? 0 : 1;
218 for ( z
= y2
- shift
; z
> y1
; z
-= 2 )
221 dc
.SetLogicalFunction(wxCOPY
);
224 void wxStdRenderer::DrawLabel(wxDC
& dc
,
225 const wxString
& label
,
232 DrawButtonLabel(dc
, label
, wxNullBitmap
, rect
, flags
,
233 alignment
, indexAccel
, rectBounds
);
236 void wxStdRenderer::DrawButtonLabel(wxDC
& dc
,
237 const wxString
& label
,
238 const wxBitmap
& image
,
245 wxRect rectLabel
= rect
;
246 if ( !label
.empty() && (flags
& wxCONTROL_DISABLED
) )
248 if ( flags
& wxCONTROL_PRESSED
)
250 // shift the label if a button is pressed
251 rectLabel
.Offset(1, 1);
254 // draw shadow of the text
255 dc
.SetTextForeground(m_penHighlight
.GetColour());
256 wxRect rectShadow
= rect
;
257 rectShadow
.Offset(1, 1);
258 dc
.DrawLabel(label
, rectShadow
, alignment
, indexAccel
);
260 // make the main label text grey
261 dc
.SetTextForeground(m_penDarkGrey
.GetColour());
263 if ( flags
& wxCONTROL_FOCUSED
)
265 // leave enough space for the focus rect
266 rectLabel
.Inflate(-2);
270 dc
.DrawLabel(label
, image
, rectLabel
, alignment
, indexAccel
, rectBounds
);
272 if ( !label
.empty() && (flags
& wxCONTROL_FOCUSED
) )
274 rectLabel
.Inflate(-1);
276 DrawFocusRect(dc
, rectLabel
);
280 // ----------------------------------------------------------------------------
282 // ----------------------------------------------------------------------------
285 We implement standard-looking 3D borders which have the following appearance:
289 WWWWWWWWWWWWWWWWWWWWWWB
290 WHHHHHHHHHHHHHHHHHHHHGB
291 WH GB W = white (HILIGHT)
292 WH GB H = light grey (LIGHT)
293 WH GB G = dark grey (SHADOI)
294 WH GB B = black (DKSHADOI)
297 WGGGGGGGGGGGGGGGGGGGGGB
298 BBBBBBBBBBBBBBBBBBBBBBB
300 The sunken border looks like this:
302 GGGGGGGGGGGGGGGGGGGGGGW
303 GBBBBBBBBBBBBBBBBBBBBHW
310 GHHHHHHHHHHHHHHHHHHHHHW
311 WWWWWWWWWWWWWWWWWWWWWWW
313 The static border (used for the controls which don't get focus) is like
316 GGGGGGGGGGGGGGGGGGGGGGW
324 WWWWWWWWWWWWWWWWWWWWWWW
326 The most complicated is the double border which is a combination of special
327 "anti-sunken" border and an extra border inside it:
329 HHHHHHHHHHHHHHHHHHHHHHB
330 HWWWWWWWWWWWWWWWWWWWWGB
331 HWHHHHHHHHHHHHHHHHHHHGB
336 HWHHHHHHHHHHHHHHHHHHHGB
337 HGGGGGGGGGGGGGGGGGGGGGB
338 BBBBBBBBBBBBBBBBBBBBBBB
340 And the simple border is, well, simple:
342 BBBBBBBBBBBBBBBBBBBBBBB
351 BBBBBBBBBBBBBBBBBBBBBBB
354 void wxStdRenderer::DrawRaisedBorder(wxDC
& dc
, wxRect
*rect
)
356 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penBlack
);
357 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penDarkGrey
);
360 void wxStdRenderer::DrawSunkenBorder(wxDC
& dc
, wxRect
*rect
)
362 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
363 DrawShadedRect(dc
, rect
, m_penBlack
, m_penLightGrey
);
366 void wxStdRenderer::DrawAntiSunkenBorder(wxDC
& dc
, wxRect
*rect
)
368 DrawShadedRect(dc
, rect
, m_penLightGrey
, m_penBlack
);
369 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
372 void wxStdRenderer::DrawBoxBorder(wxDC
& dc
, wxRect
*rect
)
374 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
375 DrawShadedRect(dc
, rect
, m_penHighlight
, m_penDarkGrey
);
378 void wxStdRenderer::DrawStaticBorder(wxDC
& dc
, wxRect
*rect
)
380 DrawShadedRect(dc
, rect
, m_penDarkGrey
, m_penHighlight
);
383 void wxStdRenderer::DrawExtraBorder(wxDC
& dc
, wxRect
*rect
)
385 DrawRect(dc
, rect
, m_penLightGrey
);
388 void wxStdRenderer::DrawBorder(wxDC
& dc
,
390 const wxRect
& rectTotal
,
394 wxRect rect
= rectTotal
;
398 case wxBORDER_SUNKEN
:
399 DrawSunkenBorder(dc
, &rect
);
402 case wxBORDER_DOUBLE
:
403 DrawAntiSunkenBorder(dc
, &rect
);
404 DrawExtraBorder(dc
, &rect
);
407 case wxBORDER_STATIC
:
408 DrawStaticBorder(dc
, &rect
);
411 case wxBORDER_RAISED
:
412 DrawRaisedBorder(dc
, &rect
);
415 case wxBORDER_SIMPLE
:
416 DrawRect(dc
, &rect
, m_penBlack
);
420 wxFAIL_MSG(_T("unknown border type"));
423 case wxBORDER_DEFAULT
:
432 wxRect
wxStdRenderer::GetBorderDimensions(wxBorder border
) const
437 case wxBORDER_SIMPLE
:
438 case wxBORDER_STATIC
:
442 case wxBORDER_RAISED
:
443 case wxBORDER_SUNKEN
:
447 case wxBORDER_DOUBLE
:
452 wxFAIL_MSG(_T("unknown border type"));
455 case wxBORDER_DEFAULT
:
470 void wxStdRenderer::AdjustSize(wxSize
*size
, const wxWindow
*window
)
472 // take into account the border width
473 wxRect rectBorder
= GetBorderDimensions(window
->GetBorder());
474 size
->x
+= rectBorder
.x
+ rectBorder
.width
;
475 size
->y
+= rectBorder
.y
+ rectBorder
.height
;
478 bool wxStdRenderer::AreScrollbarsInsideBorder() const
483 wxCoord
wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight
)
485 return fontHeight
+ 2;
488 void wxStdRenderer::DrawTextBorder(wxDC
& dc
,
494 DrawBorder(dc
, border
, rect
, flags
, rectIn
);
497 // ----------------------------------------------------------------------------
499 // ----------------------------------------------------------------------------
502 wxStdRenderer::DrawHorizontalLine(wxDC
& dc
, wxCoord y
, wxCoord x1
, wxCoord x2
)
504 dc
.SetPen(m_penDarkGrey
);
505 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
507 dc
.SetPen(m_penHighlight
);
509 dc
.DrawLine(x1
, y
, x2
+ 1, y
);
513 wxStdRenderer::DrawVerticalLine(wxDC
& dc
, wxCoord x
, wxCoord y1
, wxCoord y2
)
515 dc
.SetPen(m_penDarkGrey
);
516 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
518 dc
.SetPen(m_penHighlight
);
520 dc
.DrawLine(x
, y1
, x
, y2
+ 1);
523 void wxStdRenderer::DrawFrameWithoutLabel(wxDC
& dc
,
524 const wxRect
& rectFrame
,
525 const wxRect
& rectLabel
)
527 // draw left, bottom and right lines entirely
528 DrawVerticalLine(dc
, rectFrame
.GetLeft(),
529 rectFrame
.GetTop(), rectFrame
.GetBottom() - 2);
530 DrawHorizontalLine(dc
, rectFrame
.GetBottom() - 1,
531 rectFrame
.GetLeft(), rectFrame
.GetRight());
532 DrawVerticalLine(dc
, rectFrame
.GetRight() - 1,
533 rectFrame
.GetTop(), rectFrame
.GetBottom() - 1);
535 // and 2 parts of the top line
536 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
537 rectFrame
.GetLeft() + 1, rectLabel
.GetLeft());
538 DrawHorizontalLine(dc
, rectFrame
.GetTop(),
539 rectLabel
.GetRight(), rectFrame
.GetRight() - 2);
542 void wxStdRenderer::DrawFrameWithLabel(wxDC
& dc
,
543 const wxString
& label
,
544 const wxRect
& rectFrame
,
545 const wxRect
& rectText
,
551 DrawLabel(dc
, label
, rectText
, flags
, alignment
, indexAccel
, &rectLabel
);
553 DrawFrameWithoutLabel(dc
, rectFrame
, rectLabel
);
556 void wxStdRenderer::DrawFrame(wxDC
& dc
,
557 const wxString
& label
,
563 wxCoord height
= 0; // of the label
564 wxRect rectFrame
= rect
;
565 if ( !label
.empty() )
567 // the text should touch the top border of the rect, so the frame
568 // itself should be lower
569 dc
.GetTextExtent(label
, NULL
, &height
);
570 rectFrame
.y
+= height
/ 2;
571 rectFrame
.height
-= height
/ 2;
573 // we have to draw each part of the frame individually as we can't
574 // erase the background beyond the label as it might contain some
575 // pixmap already, so drawing everything and then overwriting part of
576 // the frame with label doesn't work
578 // TODO: the +5 shouldn't be hard coded
580 rectText
.x
= rectFrame
.x
+ 5;
582 rectText
.width
= rectFrame
.width
- 7; // +2 border width
583 rectText
.height
= height
;
585 DrawFrameWithLabel(dc
, label
, rectFrame
, rectText
, flags
,
586 alignment
, indexAccel
);
590 DrawBoxBorder(dc
, &rectFrame
);
594 void wxStdRenderer::DrawItem(wxDC
& dc
,
595 const wxString
& label
,
599 wxDCTextColourChanger
colChanger(dc
);
601 if ( flags
& wxCONTROL_SELECTED
)
603 colChanger
.Set(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
605 const wxColour colBg
= wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
);
608 dc
.DrawRectangle(rect
);
611 wxRect rectText
= rect
;
614 dc
.DrawLabel(label
, wxNullBitmap
, rectText
);
616 if ( flags
& wxCONTROL_FOCUSED
)
618 DrawFocusRect(dc
, rect
);
622 void wxStdRenderer::DrawCheckItemBitmap(wxDC
& dc
,
623 const wxBitmap
& bitmap
,
627 DrawCheckButton(dc
, wxEmptyString
, bitmap
, rect
, flags
);
630 void wxStdRenderer::DrawCheckItem(wxDC
& dc
,
631 const wxString
& label
,
632 const wxBitmap
& bitmap
,
636 wxRect rectBitmap
= rect
;
637 rectBitmap
.width
= GetCheckBitmapSize().x
;
638 DrawCheckItemBitmap(dc
, bitmap
, rectBitmap
, flags
);
640 wxRect rectLabel
= rect
;
641 wxCoord shift
= rectBitmap
.width
+ 2*GetCheckItemMargin();
642 rectLabel
.x
+= shift
;
643 rectLabel
.width
-= shift
;
644 DrawItem(dc
, label
, rectLabel
, flags
);
647 // ----------------------------------------------------------------------------
648 // check and radio bitmaps
649 // ----------------------------------------------------------------------------
651 void wxStdRenderer::DrawCheckButton(wxDC
& dc
,
652 const wxString
& label
,
653 const wxBitmap
& bitmap
,
659 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetCheckBitmap(flags
));
661 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
664 void wxStdRenderer::DrawRadioButton(wxDC
& dc
,
665 const wxString
& label
,
666 const wxBitmap
& bitmap
,
672 wxBitmap
bmp(bitmap
.Ok() ? bitmap
: GetRadioBitmap(flags
));
674 DrawCheckOrRadioButton(dc
, label
, bmp
, rect
, flags
, align
, indexAccel
);
677 void wxStdRenderer::DrawCheckOrRadioButton(wxDC
& dc
,
678 const wxString
& label
,
679 const wxBitmap
& bitmap
,
685 // calculate the position of the bitmap and of the label
686 wxCoord heightBmp
= bitmap
.GetHeight();
688 yBmp
= rect
.y
+ (rect
.height
- heightBmp
) / 2;
691 dc
.GetMultiLineTextExtent(label
, NULL
, &rectLabel
.height
);
692 rectLabel
.y
= rect
.y
+ (rect
.height
- rectLabel
.height
) / 2;
694 // align label vertically with the bitmap - looks nicer like this
695 rectLabel
.y
-= (rectLabel
.height
- heightBmp
) % 2;
697 // calc horz position
698 if ( align
== wxALIGN_RIGHT
)
700 xBmp
= rect
.GetRight() - bitmap
.GetWidth();
701 rectLabel
.x
= rect
.x
+ 3;
702 rectLabel
.SetRight(xBmp
);
704 else // normal (checkbox to the left of the text) case
707 rectLabel
.x
= xBmp
+ bitmap
.GetWidth() + 5;
708 rectLabel
.SetRight(rect
.GetRight());
711 dc
.DrawBitmap(bitmap
, xBmp
, yBmp
, true /* use mask */);
713 DrawLabel(dc
, label
, rectLabel
, flags
,
714 wxALIGN_LEFT
| wxALIGN_TOP
, indexAccel
);
719 void wxStdRenderer::DrawTextLine(wxDC
& dc
,
720 const wxString
& text
,
726 if ( (selStart
== -1) || !(flags
& wxCONTROL_FOCUSED
) )
728 // just draw it as is
729 dc
.DrawText(text
, rect
.x
, rect
.y
);
731 else // we have selection
736 // draw the part before selection
737 wxString
s(text
, (size_t)selStart
);
740 dc
.DrawText(s
, x
, rect
.y
);
742 dc
.GetTextExtent(s
, &width
, NULL
);
746 // draw the selection itself
747 s
= wxString(text
.c_str() + selStart
, text
.c_str() + selEnd
);
750 wxColour colFg
= dc
.GetTextForeground(),
751 colBg
= dc
.GetTextBackground();
752 dc
.SetTextForeground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT_TEXT
));
753 dc
.SetTextBackground(wxSCHEME_COLOUR(m_scheme
, HIGHLIGHT
));
754 dc
.SetBackgroundMode(wxSOLID
);
756 dc
.DrawText(s
, x
, rect
.y
);
757 dc
.GetTextExtent(s
, &width
, NULL
);
760 dc
.SetBackgroundMode(wxTRANSPARENT
);
761 dc
.SetTextBackground(colBg
);
762 dc
.SetTextForeground(colFg
);
765 // draw the final part
766 s
= text
.c_str() + selEnd
;
769 dc
.DrawText(s
, x
, rect
.y
);
774 void wxStdRenderer::DrawLineWrapMark(wxDC
& WXUNUSED(dc
),
775 const wxRect
& WXUNUSED(rect
))
777 // nothing by default
780 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl
* WXUNUSED(text
)) const
786 wxStdRenderer::GetTextTotalArea(const wxTextCtrl
*text
, const wxRect
& rect
) const
788 wxRect rectTotal
= rect
;
789 rectTotal
.Inflate(GetTextBorderWidth(text
));
793 wxRect
wxStdRenderer::GetTextClientArea(const wxTextCtrl
*text
,
795 wxCoord
*extraSpaceBeyond
) const
797 wxRect rectText
= rect
;
798 rectText
.Deflate(GetTextBorderWidth(text
));
800 if ( extraSpaceBeyond
)
801 *extraSpaceBeyond
= 0;
806 #endif // wxUSE_TEXTCTRL
808 // ----------------------------------------------------------------------------
809 // scrollbars drawing
810 // ----------------------------------------------------------------------------
812 void wxStdRenderer::DrawScrollbarArrow(wxDC
& dc
,
817 DrawArrow(dc
, dir
, rect
, flags
);
820 void wxStdRenderer::DrawScrollCorner(wxDC
& dc
, const wxRect
& rect
)
822 DrawSolidRect(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rect
);
825 // ----------------------------------------------------------------------------
826 // scrollbars geometry
827 // ----------------------------------------------------------------------------
832 void wxStdRenderer::GetScrollBarThumbSize(wxCoord length
,
839 // the thumb can't be made less than this number of pixels
840 static const wxCoord thumbMinWidth
= 8; // FIXME: should be configurable
842 *thumbStart
= (length
*thumbPos
) / range
;
843 *thumbEnd
= (length
*(thumbPos
+ thumbSize
)) / range
;
845 if ( *thumbEnd
- *thumbStart
< thumbMinWidth
)
847 // adjust the end if possible
848 if ( *thumbStart
<= length
- thumbMinWidth
)
850 // yes, just make it wider
851 *thumbEnd
= *thumbStart
+ thumbMinWidth
;
853 else // it is at the bottom of the scrollbar
855 // so move it a bit up
856 *thumbStart
= length
- thumbMinWidth
;
862 wxRect
wxStdRenderer::GetScrollbarRect(const wxScrollBar
*scrollbar
,
863 wxScrollBar::Element elem
,
866 if ( thumbPos
== -1 )
868 thumbPos
= scrollbar
->GetThumbPosition();
871 const wxSize sizeArrow
= GetScrollbarArrowSize();
873 wxSize sizeTotal
= scrollbar
->GetClientSize();
874 wxCoord
*start
, *width
;
875 wxCoord length
, arrow
;
877 if ( scrollbar
->IsVertical() )
880 rect
.width
= sizeTotal
.x
;
881 length
= sizeTotal
.y
;
883 width
= &rect
.height
;
889 rect
.height
= sizeTotal
.y
;
890 length
= sizeTotal
.x
;
898 case wxScrollBar::Element_Arrow_Line_1
:
903 case wxScrollBar::Element_Arrow_Line_2
:
904 *start
= length
- arrow
;
908 case wxScrollBar::Element_Arrow_Page_1
:
909 case wxScrollBar::Element_Arrow_Page_2
:
910 // we don't have them at all
913 case wxScrollBar::Element_Thumb
:
914 case wxScrollBar::Element_Bar_1
:
915 case wxScrollBar::Element_Bar_2
:
916 // we need to calculate the thumb position - do it
919 wxCoord thumbStart
, thumbEnd
;
920 int range
= scrollbar
->GetRange();
928 GetScrollBarThumbSize(length
,
930 scrollbar
->GetThumbSize(),
936 if ( elem
== wxScrollBar::Element_Thumb
)
939 *width
= thumbEnd
- thumbStart
;
941 else if ( elem
== wxScrollBar::Element_Bar_1
)
946 else // elem == wxScrollBar::Element_Bar_2
949 *width
= length
- thumbEnd
;
952 // everything is relative to the start of the shaft so far
957 case wxScrollBar::Element_Max
:
959 wxFAIL_MSG( _T("unknown scrollbar element") );
965 wxCoord
wxStdRenderer::GetScrollbarSize(const wxScrollBar
*scrollbar
)
967 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
969 wxCoord sizeArrow
, sizeTotal
;
970 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
972 sizeArrow
= sizeArrowSB
.y
;
973 sizeTotal
= scrollbar
->GetSize().y
;
977 sizeArrow
= sizeArrowSB
.x
;
978 sizeTotal
= scrollbar
->GetSize().x
;
981 return sizeTotal
- 2*sizeArrow
;
985 wxStdRenderer::HitTestScrollbar(const wxScrollBar
*scrollbar
, const wxPoint
& pt
) const
987 // we only need to work with either x or y coord depending on the
988 // orientation, choose one (but still check the other one to verify if the
989 // mouse is in the window at all)
990 const wxSize sizeArrowSB
= GetScrollbarArrowSize();
992 wxCoord coord
, sizeArrow
, sizeTotal
;
993 wxSize size
= scrollbar
->GetSize();
994 if ( scrollbar
->GetWindowStyle() & wxVERTICAL
)
996 if ( pt
.x
< 0 || pt
.x
> size
.x
)
1000 sizeArrow
= sizeArrowSB
.y
;
1005 if ( pt
.y
< 0 || pt
.y
> size
.y
)
1006 return wxHT_NOWHERE
;
1009 sizeArrow
= sizeArrowSB
.x
;
1013 // test for the arrows first as it's faster
1014 if ( coord
< 0 || coord
> sizeTotal
)
1016 return wxHT_NOWHERE
;
1018 else if ( coord
< sizeArrow
)
1020 return wxHT_SCROLLBAR_ARROW_LINE_1
;
1022 else if ( coord
> sizeTotal
- sizeArrow
)
1024 return wxHT_SCROLLBAR_ARROW_LINE_2
;
1028 // calculate the thumb position in pixels
1029 sizeTotal
-= 2*sizeArrow
;
1030 wxCoord thumbStart
, thumbEnd
;
1031 int range
= scrollbar
->GetRange();
1034 // clicking the scrollbar without range has no effect
1035 return wxHT_NOWHERE
;
1039 GetScrollBarThumbSize(sizeTotal
,
1040 scrollbar
->GetThumbPosition(),
1041 scrollbar
->GetThumbSize(),
1047 // now compare with the thumb position
1049 if ( coord
< thumbStart
)
1050 return wxHT_SCROLLBAR_BAR_1
;
1051 else if ( coord
> thumbEnd
)
1052 return wxHT_SCROLLBAR_BAR_2
;
1054 return wxHT_SCROLLBAR_THUMB
;
1060 wxStdRenderer::ScrollbarToPixel(const wxScrollBar
*scrollbar
, int thumbPos
)
1062 int range
= scrollbar
->GetRange();
1065 // the only valid position anyhow
1069 if ( thumbPos
== -1 )
1071 // by default use the current thumb position
1072 thumbPos
= scrollbar
->GetThumbPosition();
1075 const wxSize sizeArrow
= GetScrollbarArrowSize();
1076 return (thumbPos
*GetScrollbarSize(scrollbar
)) / range
1077 + (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
);
1080 int wxStdRenderer::PixelToScrollbar(const wxScrollBar
*scrollbar
, wxCoord coord
)
1082 const wxSize sizeArrow
= GetScrollbarArrowSize();
1083 return ((coord
- (scrollbar
->IsVertical() ? sizeArrow
.y
: sizeArrow
.x
)) *
1084 scrollbar
->GetRange() ) / GetScrollbarSize(scrollbar
);
1087 #endif // wxUSE_SCROLLBAR
1089 // ----------------------------------------------------------------------------
1091 // ----------------------------------------------------------------------------
1095 wxSize
wxStdRenderer::GetStatusBarBorders(wxCoord
*borderBetweenFields
) const
1097 if ( borderBetweenFields
)
1098 *borderBetweenFields
= 2;
1100 return wxSize(2, 2);
1103 void wxStdRenderer::DrawStatusField(wxDC
& dc
,
1105 const wxString
& label
,
1111 if ( style
== wxSB_RAISED
)
1112 DrawBorder(dc
, wxBORDER_RAISED
, rect
, flags
, &rectIn
);
1113 else if ( style
!= wxSB_FLAT
)
1114 DrawBorder(dc
, wxBORDER_STATIC
, rect
, flags
, &rectIn
);
1116 rectIn
.Deflate(GetStatusBarBorders(NULL
));
1118 wxDCClipper
clipper(dc
, rectIn
);
1119 DrawLabel(dc
, label
, rectIn
, flags
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1122 #endif // wxUSE_STATUSBAR
1124 // ----------------------------------------------------------------------------
1125 // top level windows
1126 // ----------------------------------------------------------------------------
1128 int wxStdRenderer::HitTestFrame(const wxRect
& rect
, const wxPoint
& pt
, int flags
) const
1130 wxRect client
= GetFrameClientArea(rect
, flags
);
1132 if ( client
.Contains(pt
) )
1133 return wxHT_TOPLEVEL_CLIENT_AREA
;
1135 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1137 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1139 if ( flags
& wxTOPLEVEL_ICON
)
1141 if ( wxRect(client
.GetPosition(), GetFrameIconSize()).Contains(pt
) )
1142 return wxHT_TOPLEVEL_ICON
;
1145 wxRect
btnRect(client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
,
1146 client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2,
1147 FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1149 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1151 if ( btnRect
.Contains(pt
) )
1152 return wxHT_TOPLEVEL_BUTTON_CLOSE
;
1153 btnRect
.x
-= FRAME_BUTTON_WIDTH
+ 2;
1155 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1157 if ( btnRect
.Contains(pt
) )
1158 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE
;
1159 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1161 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1163 if ( btnRect
.Contains(pt
) )
1164 return wxHT_TOPLEVEL_BUTTON_RESTORE
;
1165 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1167 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1169 if ( btnRect
.Contains(pt
) )
1170 return wxHT_TOPLEVEL_BUTTON_ICONIZE
;
1171 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1173 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1175 if ( btnRect
.Contains(pt
) )
1176 return wxHT_TOPLEVEL_BUTTON_HELP
;
1177 btnRect
.x
-= FRAME_BUTTON_WIDTH
;
1180 if ( pt
.y
>= client
.y
&& pt
.y
< client
.y
+ FRAME_TITLEBAR_HEIGHT
)
1181 return wxHT_TOPLEVEL_TITLEBAR
;
1184 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1186 // we are certainly at one of borders, let's decide which one:
1189 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
1190 if ( pt
.x
< client
.x
)
1191 border
|= wxHT_TOPLEVEL_BORDER_W
;
1192 else if ( pt
.x
>= client
.width
+ client
.x
)
1193 border
|= wxHT_TOPLEVEL_BORDER_E
;
1194 if ( pt
.y
< client
.y
)
1195 border
|= wxHT_TOPLEVEL_BORDER_N
;
1196 else if ( pt
.y
>= client
.height
+ client
.y
)
1197 border
|= wxHT_TOPLEVEL_BORDER_S
;
1201 return wxHT_NOWHERE
;
1204 void wxStdRenderer::DrawFrameTitleBar(wxDC
& dc
,
1206 const wxString
& title
,
1210 int specialButtonFlags
)
1212 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1214 DrawFrameBorder(dc
, rect
, flags
);
1216 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1218 DrawFrameBackground(dc
, rect
, flags
);
1219 if ( flags
& wxTOPLEVEL_ICON
)
1220 DrawFrameIcon(dc
, rect
, icon
, flags
);
1221 DrawFrameTitle(dc
, rect
, title
, flags
);
1223 wxRect client
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1225 x
= client
.GetRight() - 2 - FRAME_BUTTON_WIDTH
;
1226 y
= client
.GetTop() + (FRAME_TITLEBAR_HEIGHT
-FRAME_BUTTON_HEIGHT
)/2;
1228 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1230 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_CLOSE
,
1231 (specialButton
== wxTOPLEVEL_BUTTON_CLOSE
) ?
1232 specialButtonFlags
: 0);
1233 x
-= FRAME_BUTTON_WIDTH
+ 2;
1235 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1237 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_MAXIMIZE
,
1238 (specialButton
== wxTOPLEVEL_BUTTON_MAXIMIZE
) ?
1239 specialButtonFlags
: 0);
1240 x
-= FRAME_BUTTON_WIDTH
;
1242 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1244 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_RESTORE
,
1245 (specialButton
== wxTOPLEVEL_BUTTON_RESTORE
) ?
1246 specialButtonFlags
: 0);
1247 x
-= FRAME_BUTTON_WIDTH
;
1249 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1251 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_ICONIZE
,
1252 (specialButton
== wxTOPLEVEL_BUTTON_ICONIZE
) ?
1253 specialButtonFlags
: 0);
1254 x
-= FRAME_BUTTON_WIDTH
;
1256 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1258 DrawFrameButton(dc
, x
, y
, wxTOPLEVEL_BUTTON_HELP
,
1259 (specialButton
== wxTOPLEVEL_BUTTON_HELP
) ?
1260 specialButtonFlags
: 0);
1265 void wxStdRenderer::DrawFrameBorder(wxDC
& dc
, const wxRect
& rect
, int flags
)
1267 if ( !(flags
& wxTOPLEVEL_BORDER
) )
1272 DrawAntiSunkenBorder(dc
, &r
);
1273 DrawExtraBorder(dc
, &r
);
1274 if ( flags
& wxTOPLEVEL_RESIZEABLE
)
1275 DrawExtraBorder(dc
, &r
);
1278 void wxStdRenderer::DrawFrameBackground(wxDC
& dc
, const wxRect
& rect
, int flags
)
1280 if ( !(flags
& wxTOPLEVEL_TITLEBAR
) )
1283 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1284 ? wxColourScheme::TITLEBAR_ACTIVE
1285 : wxColourScheme::TITLEBAR
);
1287 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1288 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1290 DrawBackground(dc
, col
, r
);
1293 void wxStdRenderer::DrawFrameTitle(wxDC
& dc
,
1295 const wxString
& title
,
1298 wxColour col
= m_scheme
->Get(flags
& wxTOPLEVEL_ACTIVE
1299 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1300 : wxColourScheme::TITLEBAR_TEXT
);
1301 dc
.SetTextForeground(col
);
1303 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1304 r
.height
= FRAME_TITLEBAR_HEIGHT
;
1305 if ( flags
& wxTOPLEVEL_ICON
)
1307 r
.x
+= FRAME_TITLEBAR_HEIGHT
;
1308 r
.width
-= FRAME_TITLEBAR_HEIGHT
+ 2;
1316 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1317 r
.width
-= FRAME_BUTTON_WIDTH
+ 2;
1318 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1319 r
.width
-= FRAME_BUTTON_WIDTH
;
1320 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1321 r
.width
-= FRAME_BUTTON_WIDTH
;
1322 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1323 r
.width
-= FRAME_BUTTON_WIDTH
;
1324 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1325 r
.width
-= FRAME_BUTTON_WIDTH
;
1327 dc
.SetFont(m_titlebarFont
);
1331 dc
.GetTextExtent(title
, &textW
, NULL
);
1332 if ( textW
> r
.width
)
1334 // text is too big, let's shorten it and add "..." after it:
1335 size_t len
= title
.length();
1336 wxCoord WSoFar
, letterW
;
1338 dc
.GetTextExtent(wxT("..."), &WSoFar
, NULL
);
1339 if ( WSoFar
> r
.width
)
1341 // not enough space to draw anything
1346 for (size_t i
= 0; i
< len
; i
++)
1348 dc
.GetTextExtent(title
[i
], &letterW
, NULL
);
1349 if ( letterW
+ WSoFar
> r
.width
)
1356 else // no need to truncate the title
1361 dc
.DrawLabel(s
, wxNullBitmap
, r
, wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
);
1364 void wxStdRenderer::DrawFrameIcon(wxDC
& dc
,
1371 wxRect r
= GetFrameClientArea(rect
, flags
& ~wxTOPLEVEL_TITLEBAR
);
1372 dc
.DrawIcon(icon
, r
.x
, r
.y
);
1376 void wxStdRenderer::DrawFrameButton(wxDC
& dc
,
1377 wxCoord x
, wxCoord y
,
1381 FrameButtonType idx
;
1384 case wxTOPLEVEL_BUTTON_CLOSE
: idx
= FrameButton_Close
; break;
1385 case wxTOPLEVEL_BUTTON_MAXIMIZE
: idx
= FrameButton_Maximize
; break;
1386 case wxTOPLEVEL_BUTTON_ICONIZE
: idx
= FrameButton_Minimize
; break;
1387 case wxTOPLEVEL_BUTTON_RESTORE
: idx
= FrameButton_Restore
; break;
1388 case wxTOPLEVEL_BUTTON_HELP
: idx
= FrameButton_Help
; break;
1390 wxFAIL_MSG(wxT("incorrect button specification"));
1394 wxBitmap bmp
= GetFrameButtonBitmap(idx
);
1398 wxRect
rectBtn(x
, y
, FRAME_BUTTON_WIDTH
, FRAME_BUTTON_HEIGHT
);
1399 if ( flags
& wxCONTROL_PRESSED
)
1401 DrawSunkenBorder(dc
, &rectBtn
);
1403 rectBtn
.Offset(1, 1);
1407 DrawRaisedBorder(dc
, &rectBtn
);
1410 DrawBackground(dc
, wxSCHEME_COLOUR(m_scheme
, CONTROL
), rectBtn
);
1412 wxRect
rectBmp(0, 0, bmp
.GetWidth(), bmp
.GetHeight());
1413 dc
.DrawBitmap(bmp
, rectBmp
.CentreIn(rectBtn
).GetPosition(), true);
1416 int wxStdRenderer::GetFrameBorderWidth(int flags
) const
1418 return flags
& wxTOPLEVEL_RESIZEABLE
? 4 : 3;
1422 wxRect
wxStdRenderer::GetFrameClientArea(const wxRect
& rect
, int flags
) const
1426 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1428 r
.Inflate(-GetFrameBorderWidth(flags
));
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 s
.IncBy(2*GetFrameBorderWidth(flags
));
1450 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1451 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1456 wxSize
wxStdRenderer::GetFrameMinSize(int flags
) const
1460 if ( (flags
& wxTOPLEVEL_BORDER
) && !(flags
& wxTOPLEVEL_MAXIMIZED
) )
1462 s
.IncBy(2*GetFrameBorderWidth(flags
));
1465 if ( flags
& wxTOPLEVEL_TITLEBAR
)
1467 s
.y
+= FRAME_TITLEBAR_HEIGHT
;
1469 if ( flags
& wxTOPLEVEL_ICON
)
1470 s
.x
+= FRAME_TITLEBAR_HEIGHT
+ 2;
1471 if ( flags
& wxTOPLEVEL_BUTTON_CLOSE
)
1472 s
.x
+= FRAME_BUTTON_WIDTH
+ 2;
1473 if ( flags
& wxTOPLEVEL_BUTTON_MAXIMIZE
)
1474 s
.x
+= FRAME_BUTTON_WIDTH
;
1475 if ( flags
& wxTOPLEVEL_BUTTON_RESTORE
)
1476 s
.x
+= FRAME_BUTTON_WIDTH
;
1477 if ( flags
& wxTOPLEVEL_BUTTON_ICONIZE
)
1478 s
.x
+= FRAME_BUTTON_WIDTH
;
1479 if ( flags
& wxTOPLEVEL_BUTTON_HELP
)
1480 s
.x
+= FRAME_BUTTON_WIDTH
;
1486 wxSize
wxStdRenderer::GetFrameIconSize() const
1488 return wxSize(16, 16);