]> git.saurik.com Git - wxWidgets.git/blob - src/univ/stdrend.cpp
Define XML_STATIC in Expat header instead of Expat projects.
[wxWidgets.git] / src / univ / stdrend.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/univ/stdrend.cpp
3 // Purpose:     implementation of wxStdRenderer
4 // Author:      Vadim Zeitlin
5 // Created:     2006-09-16
6 // RCS-ID:      $Id$
7 // Copyright:   (c) 2006 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27     #include "wx/settings.h"
28     #include "wx/brush.h"
29     #include "wx/dc.h"
30     #include "wx/statusbr.h"
31     #include "wx/toplevel.h"
32 #endif //WX_PRECOMP
33
34 #include "wx/univ/stdrend.h"
35 #include "wx/univ/colschem.h"
36
37 // ----------------------------------------------------------------------------
38 // constants
39 // ----------------------------------------------------------------------------
40
41 static const int FRAME_TITLEBAR_HEIGHT             = 18;
42 static const int FRAME_BUTTON_WIDTH                = 16;
43 static const int FRAME_BUTTON_HEIGHT               = 14;
44
45 // the margin between listbox item text and its rectangle
46 static const int ITEM_MARGIN = 1;
47
48 // ============================================================================
49 // wxStdRenderer implementation
50 // ============================================================================
51
52 // ----------------------------------------------------------------------------
53 // ctor
54 // ----------------------------------------------------------------------------
55
56 wxStdRenderer::wxStdRenderer(const wxColourScheme *scheme)
57              : m_scheme(scheme)
58 {
59     m_penBlack = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_DARK));
60     m_penDarkGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_OUT));
61     m_penLightGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_IN));
62     m_penHighlight = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_HIGHLIGHT));
63
64     m_titlebarFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
65     m_titlebarFont.SetWeight(wxFONTWEIGHT_BOLD);
66 }
67
68 // ----------------------------------------------------------------------------
69 // helper functions
70 // ----------------------------------------------------------------------------
71
72 void
73 wxStdRenderer::DrawSolidRect(wxDC& dc, const wxColour& col, const wxRect& rect)
74 {
75     wxBrush brush(col, wxSOLID);
76     dc.SetBrush(brush);
77     dc.SetPen(*wxTRANSPARENT_PEN);
78     dc.DrawRectangle(rect);
79 }
80
81 void wxStdRenderer::DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen)
82 {
83     // draw
84     dc.SetPen(pen);
85     dc.SetBrush(*wxTRANSPARENT_BRUSH);
86     dc.DrawRectangle(*rect);
87
88     // adjust the rect
89     rect->Inflate(-1);
90 }
91
92 void wxStdRenderer::DrawShadedRect(wxDC& dc, wxRect *rect,
93                                    const wxPen& pen1, const wxPen& pen2)
94 {
95     // draw the rectangle
96     dc.SetPen(pen1);
97     dc.DrawLine(rect->GetLeft(), rect->GetTop(),
98                 rect->GetLeft(), rect->GetBottom());
99     dc.DrawLine(rect->GetLeft() + 1, rect->GetTop(),
100                 rect->GetRight(), rect->GetTop());
101     dc.SetPen(pen2);
102     dc.DrawLine(rect->GetRight(), rect->GetTop(),
103                 rect->GetRight(), rect->GetBottom());
104     dc.DrawLine(rect->GetLeft(), rect->GetBottom(),
105                 rect->GetRight() + 1, rect->GetBottom());
106
107     // adjust the rect
108     rect->Inflate(-1);
109 }
110
111 // ----------------------------------------------------------------------------
112 // translate various flags into corresponding renderer constants
113 // ----------------------------------------------------------------------------
114
115 /* static */
116 void wxStdRenderer::GetIndicatorsFromFlags(int flags,
117                                            IndicatorState& state,
118                                            IndicatorStatus& status)
119 {
120     if ( flags & wxCONTROL_SELECTED )
121         state = flags & wxCONTROL_DISABLED ? IndicatorState_SelectedDisabled
122                                            : IndicatorState_Selected;
123     else if ( flags & wxCONTROL_DISABLED )
124         state = IndicatorState_Disabled;
125     else if ( flags & wxCONTROL_PRESSED )
126         state = IndicatorState_Pressed;
127     else
128         state = IndicatorState_Normal;
129
130     status = flags & wxCONTROL_CHECKED ? IndicatorStatus_Checked
131                                        : flags & wxCONTROL_UNDETERMINED
132                                             ? IndicatorStatus_Undetermined
133                                             : IndicatorStatus_Unchecked;
134 }
135
136 /* static */
137 wxStdRenderer::ArrowDirection wxStdRenderer::GetArrowDirection(wxDirection dir)
138 {
139     switch ( dir )
140     {
141         case wxLEFT:
142             return Arrow_Left;
143
144         case wxRIGHT:
145             return Arrow_Right;
146
147         case wxUP:
148             return Arrow_Up;
149
150         case wxDOWN:
151             return Arrow_Down;
152
153         default:
154             wxFAIL_MSG(wxT("unknown arrow direction"));
155     }
156
157     return Arrow_Max;
158 }
159
160 // ----------------------------------------------------------------------------
161 // background
162 // ----------------------------------------------------------------------------
163
164 void wxStdRenderer::DrawBackground(wxDC& dc,
165                                    const wxColour& col,
166                                    const wxRect& rect,
167                                    int WXUNUSED(flags),
168                                    wxWindow *window)
169 {
170     wxColour colBg;
171
172     if (col.IsOk())
173     {
174         colBg = col;
175     }
176     else if (window)
177     {
178         colBg = m_scheme->GetBackground(window);
179     }
180     else
181     {
182         colBg = wxSCHEME_COLOUR(m_scheme, CONTROL);
183     }
184
185     DrawSolidRect(dc, colBg, rect);
186 }
187
188
189 void wxStdRenderer::DrawButtonSurface(wxDC& dc,
190                                       const wxColour& col,
191                                       const wxRect& rect,
192                                       int flags)
193 {
194     DrawBackground(dc, col, rect, flags);
195 }
196
197 // ----------------------------------------------------------------------------
198 // text
199 // ----------------------------------------------------------------------------
200
201 void
202 wxStdRenderer::DrawFocusRect(wxWindow* WXUNUSED(win), wxDC& dc, const wxRect& rect, int WXUNUSED(flags))
203 {
204     // draw the pixels manually because the "dots" in wxPen with wxDOT style
205     // may be short traits and not really dots
206     //
207     // note that to behave in the same manner as DrawRect(), we must exclude
208     // the bottom and right borders from the rectangle
209     wxCoord x1 = rect.GetLeft(),
210             y1 = rect.GetTop(),
211             x2 = rect.GetRight(),
212             y2 = rect.GetBottom();
213
214     dc.SetPen(m_penBlack);
215
216     // this seems to be closer than what Windows does than wxINVERT although
217     // I'm still not sure if it's correct
218     dc.SetLogicalFunction(wxAND_REVERSE);
219
220     wxCoord z;
221     for ( z = x1 + 1; z < x2; z += 2 )
222         dc.DrawPoint(z, rect.GetTop());
223
224     wxCoord shift = z == x2 ? 0 : 1;
225     for ( z = y1 + shift; z < y2; z += 2 )
226         dc.DrawPoint(x2, z);
227
228     shift = z == y2 ? 0 : 1;
229     for ( z = x2 - shift; z > x1; z -= 2 )
230         dc.DrawPoint(z, y2);
231
232     shift = z == x1 ? 0 : 1;
233     for ( z = y2 - shift; z > y1; z -= 2 )
234         dc.DrawPoint(x1, z);
235
236     dc.SetLogicalFunction(wxCOPY);
237 }
238
239 void wxStdRenderer::DrawLabel(wxDC& dc,
240                               const wxString& label,
241                               const wxRect& rect,
242                               int flags,
243                               int alignment,
244                               int indexAccel,
245                               wxRect *rectBounds)
246 {
247     DrawButtonLabel(dc, label, wxNullBitmap, rect, flags,
248                     alignment, indexAccel, rectBounds);
249 }
250
251 void wxStdRenderer::DrawButtonLabel(wxDC& dc,
252                                     const wxString& label,
253                                     const wxBitmap& image,
254                                     const wxRect& rect,
255                                     int flags,
256                                     int alignment,
257                                     int indexAccel,
258                                     wxRect *rectBounds)
259 {
260     wxDCTextColourChanger clrChanger(dc);
261
262     wxRect rectLabel = rect;
263     if ( !label.empty() && (flags & wxCONTROL_DISABLED) )
264     {
265         if ( flags & wxCONTROL_PRESSED )
266         {
267             // shift the label if a button is pressed
268             rectLabel.Offset(1, 1);
269         }
270
271         // draw shadow of the text
272         clrChanger.Set(m_penHighlight.GetColour());
273         wxRect rectShadow = rect;
274         rectShadow.Offset(1, 1);
275         dc.DrawLabel(label, rectShadow, alignment, indexAccel);
276
277         // make the main label text grey
278         clrChanger.Set(m_penDarkGrey.GetColour());
279
280         if ( flags & wxCONTROL_FOCUSED )
281         {
282             // leave enough space for the focus rect
283             rectLabel.Inflate(-2);
284         }
285     }
286
287     dc.DrawLabel(label, image, rectLabel, alignment, indexAccel, rectBounds);
288
289     if ( !label.empty() && (flags & wxCONTROL_FOCUSED) )
290     {
291         rectLabel.Inflate(-1);
292
293         DrawFocusRect(NULL, dc, rectLabel);
294     }
295 }
296
297 // ----------------------------------------------------------------------------
298 // borders
299 // ----------------------------------------------------------------------------
300
301 /*
302    We implement standard-looking 3D borders which have the following appearance:
303
304    The raised border:
305
306    WWWWWWWWWWWWWWWWWWWWWWB
307    WHHHHHHHHHHHHHHHHHHHHGB
308    WH                   GB  W = white       (HILIGHT)
309    WH                   GB  H = light grey  (LIGHT)
310    WH                   GB  G = dark grey   (SHADOI)
311    WH                   GB  B = black       (DKSHADOI)
312    WH                   GB
313    WH                   GB
314    WGGGGGGGGGGGGGGGGGGGGGB
315    BBBBBBBBBBBBBBBBBBBBBBB
316
317    The sunken border looks like this:
318
319    GGGGGGGGGGGGGGGGGGGGGGW
320    GBBBBBBBBBBBBBBBBBBBBHW
321    GB                   HW
322    GB                   HW
323    GB                   HW
324    GB                   HW
325    GB                   HW
326    GB                   HW
327    GHHHHHHHHHHHHHHHHHHHHHW
328    WWWWWWWWWWWWWWWWWWWWWWW
329
330    The static border (used for the controls which don't get focus) is like
331    this:
332
333    GGGGGGGGGGGGGGGGGGGGGGW
334    G                     W
335    G                     W
336    G                     W
337    G                     W
338    G                     W
339    G                     W
340    G                     W
341    WWWWWWWWWWWWWWWWWWWWWWW
342
343    The most complicated is the double border which is a combination of special
344    "anti-sunken" border and an extra border inside it:
345
346    HHHHHHHHHHHHHHHHHHHHHHB
347    HWWWWWWWWWWWWWWWWWWWWGB
348    HWHHHHHHHHHHHHHHHHHHHGB
349    HWH                 HGB
350    HWH                 HGB
351    HWH                 HGB
352    HWH                 HGB
353    HWHHHHHHHHHHHHHHHHHHHGB
354    HGGGGGGGGGGGGGGGGGGGGGB
355    BBBBBBBBBBBBBBBBBBBBBBB
356
357    And the simple border is, well, simple:
358
359    BBBBBBBBBBBBBBBBBBBBBBB
360    B                     B
361    B                     B
362    B                     B
363    B                     B
364    B                     B
365    B                     B
366    B                     B
367    B                     B
368    BBBBBBBBBBBBBBBBBBBBBBB
369 */
370
371 void wxStdRenderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
372 {
373     DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
374     DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
375 }
376
377 void wxStdRenderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
378 {
379     DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
380     DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
381 }
382
383 void wxStdRenderer::DrawAntiSunkenBorder(wxDC& dc, wxRect *rect)
384 {
385     DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
386     DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
387 }
388
389 void wxStdRenderer::DrawBoxBorder(wxDC& dc, wxRect *rect)
390 {
391     DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
392     DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
393 }
394
395 void wxStdRenderer::DrawStaticBorder(wxDC& dc, wxRect *rect)
396 {
397     DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
398 }
399
400 void wxStdRenderer::DrawExtraBorder(wxDC& dc, wxRect *rect)
401 {
402     DrawRect(dc, rect, m_penLightGrey);
403 }
404
405 void wxStdRenderer::DrawBorder(wxDC& dc,
406                                wxBorder border,
407                                const wxRect& rectTotal,
408                                int WXUNUSED(flags),
409                                wxRect *rectIn)
410 {
411     wxRect rect = rectTotal;
412
413     switch ( border )
414     {
415         case wxBORDER_SUNKEN:
416         case wxBORDER_THEME:
417             DrawSunkenBorder(dc, &rect);
418             break;
419
420         // wxBORDER_DOUBLE and wxBORDER_THEME are currently the same value.
421 #if 0
422         case wxBORDER_DOUBLE:
423             DrawAntiSunkenBorder(dc, &rect);
424             DrawExtraBorder(dc, &rect);
425             break;
426 #endif
427
428         case wxBORDER_STATIC:
429             DrawStaticBorder(dc, &rect);
430             break;
431
432         case wxBORDER_RAISED:
433             DrawRaisedBorder(dc, &rect);
434             break;
435
436         case wxBORDER_SIMPLE:
437             DrawRect(dc, &rect, m_penBlack);
438             break;
439
440         default:
441             wxFAIL_MSG(wxT("unknown border type"));
442             // fall through
443
444         case wxBORDER_DEFAULT:
445         case wxBORDER_NONE:
446             break;
447     }
448
449     if ( rectIn )
450         *rectIn = rect;
451 }
452
453 wxRect wxStdRenderer::GetBorderDimensions(wxBorder border) const
454 {
455     wxCoord width;
456     switch ( border )
457     {
458         case wxBORDER_SIMPLE:
459         case wxBORDER_STATIC:
460             width = 1;
461             break;
462
463         case wxBORDER_RAISED:
464         case wxBORDER_SUNKEN:
465         case wxBORDER_THEME:
466             width = 2;
467             break;
468 #if 0
469         case wxBORDER_DOUBLE:
470             width = 3;
471             break;
472 #endif
473         default:
474             wxFAIL_MSG(wxT("unknown border type"));
475             // fall through
476
477         case wxBORDER_DEFAULT:
478         case wxBORDER_NONE:
479             width = 0;
480             break;
481     }
482
483     wxRect rect;
484     rect.x =
485     rect.y =
486     rect.width =
487     rect.height = width;
488
489     return rect;
490 }
491
492 void wxStdRenderer::AdjustSize(wxSize *size, const wxWindow *window)
493 {
494     // take into account the border width
495     wxRect rectBorder = GetBorderDimensions(window->GetBorder());
496     size->x += rectBorder.x + rectBorder.width;
497     size->y += rectBorder.y + rectBorder.height;
498 }
499
500 bool wxStdRenderer::AreScrollbarsInsideBorder() const
501 {
502     return false;
503 }
504
505 wxCoord wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight)
506 {
507     return fontHeight + 2*ITEM_MARGIN;
508 }
509
510 void wxStdRenderer::DrawTextBorder(wxDC& dc,
511                                    wxBorder border,
512                                    const wxRect& rect,
513                                    int flags,
514                                    wxRect *rectIn)
515 {
516     DrawBorder(dc, border, rect, flags, rectIn);
517 }
518
519 // ----------------------------------------------------------------------------
520 // lines and boxes
521 // ----------------------------------------------------------------------------
522
523 void
524 wxStdRenderer::DrawHorizontalLine(wxDC& dc, wxCoord y, wxCoord x1, wxCoord x2)
525 {
526     dc.SetPen(m_penDarkGrey);
527     dc.DrawLine(x1, y, x2 + 1, y);
528
529     dc.SetPen(m_penHighlight);
530     y++;
531     dc.DrawLine(x1, y, x2 + 1, y);
532 }
533
534 void
535 wxStdRenderer::DrawVerticalLine(wxDC& dc, wxCoord x, wxCoord y1, wxCoord y2)
536 {
537     dc.SetPen(m_penDarkGrey);
538     dc.DrawLine(x, y1, x, y2 + 1);
539
540     dc.SetPen(m_penHighlight);
541     x++;
542     dc.DrawLine(x, y1, x, y2 + 1);
543 }
544
545 void wxStdRenderer::DrawFrameWithoutLabel(wxDC& dc,
546                                           const wxRect& rectFrame,
547                                           const wxRect& rectLabel)
548 {
549     // draw left, bottom and right lines entirely
550     DrawVerticalLine(dc, rectFrame.GetLeft(),
551                      rectFrame.GetTop(), rectFrame.GetBottom() - 2);
552     DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
553                        rectFrame.GetLeft(), rectFrame.GetRight());
554     DrawVerticalLine(dc, rectFrame.GetRight() - 1,
555                      rectFrame.GetTop(), rectFrame.GetBottom() - 1);
556
557     // and 2 parts of the top line
558     DrawHorizontalLine(dc, rectFrame.GetTop(),
559                        rectFrame.GetLeft() + 1, rectLabel.GetLeft());
560     DrawHorizontalLine(dc, rectFrame.GetTop(),
561                        rectLabel.GetRight(), rectFrame.GetRight() - 2);
562 }
563
564 void wxStdRenderer::DrawFrameWithLabel(wxDC& dc,
565                                        const wxString& label,
566                                        const wxRect& rectFrame,
567                                        const wxRect& rectText,
568                                        int flags,
569                                        int alignment,
570                                        int indexAccel)
571 {
572     wxRect rectLabel;
573     DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
574
575     DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
576 }
577
578 void wxStdRenderer::DrawFrame(wxDC& dc,
579                               const wxString& label,
580                               const wxRect& rect,
581                               int flags,
582                               int alignment,
583                               int indexAccel)
584 {
585     wxCoord height = 0; // of the label
586     wxRect rectFrame = rect;
587     if ( !label.empty() )
588     {
589         // the text should touch the top border of the rect, so the frame
590         // itself should be lower
591         dc.GetTextExtent(label, NULL, &height);
592         rectFrame.y += height / 2;
593         rectFrame.height -= height / 2;
594
595         // we have to draw each part of the frame individually as we can't
596         // erase the background beyond the label as it might contain some
597         // pixmap already, so drawing everything and then overwriting part of
598         // the frame with label doesn't work
599
600         // TODO: the +5 shouldn't be hard coded
601         wxRect rectText;
602         rectText.x = rectFrame.x + 5;
603         rectText.y = rect.y;
604         rectText.width = rectFrame.width - 7; // +2 border width
605         rectText.height = height;
606
607         DrawFrameWithLabel(dc, label, rectFrame, rectText, flags,
608                            alignment, indexAccel);
609     }
610     else // no label
611     {
612         DrawBoxBorder(dc, &rectFrame);
613     }
614 }
615
616 void wxStdRenderer::DrawItem(wxDC& dc,
617                              const wxString& label,
618                              const wxRect& rect,
619                              int flags)
620 {
621     wxDCTextColourChanger colChanger(dc);
622
623     if ( flags & wxCONTROL_SELECTED )
624     {
625         colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
626
627         const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
628         dc.SetBrush(colBg);
629         dc.SetPen(colBg);
630         dc.DrawRectangle(rect);
631     }
632
633     // horizontal adjustment is arbitrary
634     wxRect rectText = rect;
635     rectText.Deflate(2, ITEM_MARGIN);
636     dc.DrawLabel(label, wxNullBitmap, rectText);
637
638     if ( flags & wxCONTROL_FOCUSED )
639     {
640         DrawFocusRect(NULL, dc, rect, flags);
641     }
642 }
643
644 void wxStdRenderer::DrawCheckItemBitmap(wxDC& dc,
645                                         const wxBitmap& bitmap,
646                                         const wxRect& rect,
647                                         int flags)
648 {
649     DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags);
650 }
651
652 void wxStdRenderer::DrawCheckItem(wxDC& dc,
653                                   const wxString& label,
654                                   const wxBitmap& bitmap,
655                                   const wxRect& rect,
656                                   int flags)
657 {
658     wxRect rectBitmap = rect;
659     rectBitmap.width = GetCheckBitmapSize().x;
660     DrawCheckItemBitmap(dc, bitmap, rectBitmap, flags);
661
662     wxRect rectLabel = rect;
663     wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin();
664     rectLabel.x += shift;
665     rectLabel.width -= shift;
666     DrawItem(dc, label, rectLabel, flags);
667 }
668
669 // ----------------------------------------------------------------------------
670 // check and radio bitmaps
671 // ----------------------------------------------------------------------------
672
673 void wxStdRenderer::DrawCheckButton(wxDC& dc,
674                                     const wxString& label,
675                                     const wxBitmap& bitmap,
676                                     const wxRect& rect,
677                                     int flags,
678                                     wxAlignment align,
679                                     int indexAccel)
680 {
681     if (bitmap.IsOk())
682         DrawCheckOrRadioButton(dc, label, bitmap, rect, flags, align, indexAccel);
683     else
684         DrawCheckOrRadioButton(dc, label, GetCheckBitmap(flags), rect, flags, align, indexAccel);
685 }
686
687 void wxStdRenderer::DrawRadioButton(wxDC& dc,
688                                     const wxString& label,
689                                     const wxBitmap& bitmap,
690                                     const wxRect& rect,
691                                     int flags,
692                                     wxAlignment align,
693                                     int indexAccel)
694 {
695     if (bitmap.IsOk())
696         DrawCheckOrRadioButton(dc, label, bitmap, rect, flags, align, indexAccel);
697     else
698         DrawCheckOrRadioButton(dc, label, GetRadioBitmap(flags), rect, flags, align, indexAccel);
699
700 }
701
702 void wxStdRenderer::DrawCheckOrRadioButton(wxDC& dc,
703                                            const wxString& label,
704                                            const wxBitmap& bitmap,
705                                            const wxRect& rect,
706                                            int flags,
707                                            wxAlignment align,
708                                            int indexAccel)
709 {
710     // calculate the position of the bitmap and of the label
711     wxCoord heightBmp = bitmap.GetHeight();
712     wxCoord xBmp,
713             yBmp = rect.y + (rect.height - heightBmp) / 2;
714
715     wxRect rectLabel;
716     dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
717     rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
718
719     // align label vertically with the bitmap - looks nicer like this
720     rectLabel.y -= (rectLabel.height - heightBmp) % 2;
721
722     // calc horz position
723     if ( align == wxALIGN_RIGHT )
724     {
725         xBmp = rect.GetRight() - bitmap.GetWidth();
726         rectLabel.x = rect.x + 3;
727         rectLabel.SetRight(xBmp);
728     }
729     else // normal (checkbox to the left of the text) case
730     {
731         xBmp = rect.x;
732         rectLabel.x = xBmp + bitmap.GetWidth() + 5;
733         rectLabel.SetRight(rect.GetRight());
734     }
735
736     dc.DrawBitmap(bitmap, xBmp, yBmp, true /* use mask */);
737
738     DrawLabel(dc, label, rectLabel, flags,
739               wxALIGN_LEFT | wxALIGN_TOP, indexAccel);
740 }
741
742 #if wxUSE_TEXTCTRL
743
744 void wxStdRenderer::DrawTextLine(wxDC& dc,
745                                  const wxString& text,
746                                  const wxRect& rect,
747                                  int selStart,
748                                  int selEnd,
749                                  int flags)
750 {
751     if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
752     {
753         // just draw it as is
754         dc.DrawText(text, rect.x, rect.y);
755     }
756     else // we have selection
757     {
758         wxCoord width,
759                 x = rect.x;
760
761         // draw the part before selection
762         wxString s(text, (size_t)selStart);
763         if ( !s.empty() )
764         {
765             dc.DrawText(s, x, rect.y);
766
767             dc.GetTextExtent(s, &width, NULL);
768             x += width;
769         }
770
771         // draw the selection itself
772         s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
773         if ( !s.empty() )
774         {
775             wxColour colFg = dc.GetTextForeground(),
776                      colBg = dc.GetTextBackground();
777             dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
778             dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT));
779             dc.SetBackgroundMode(wxSOLID);
780
781             dc.DrawText(s, x, rect.y);
782             dc.GetTextExtent(s, &width, NULL);
783             x += width;
784
785             dc.SetBackgroundMode(wxTRANSPARENT);
786             dc.SetTextBackground(colBg);
787             dc.SetTextForeground(colFg);
788         }
789
790         // draw the final part
791         s = text.c_str() + selEnd;
792         if ( !s.empty() )
793         {
794             dc.DrawText(s, x, rect.y);
795         }
796     }
797 }
798
799 void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
800                                      const wxRect& WXUNUSED(rect))
801 {
802     // nothing by default
803 }
804
805 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
806 {
807     return 1;
808 }
809
810 wxRect
811 wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
812 {
813     wxRect rectTotal = rect;
814     rectTotal.Inflate(GetTextBorderWidth(text));
815     return rectTotal;
816 }
817
818 wxRect wxStdRenderer::GetTextClientArea(const wxTextCtrl *text,
819                                         const wxRect& rect,
820                                         wxCoord *extraSpaceBeyond) const
821 {
822     wxRect rectText = rect;
823     rectText.Deflate(GetTextBorderWidth(text));
824
825     if ( extraSpaceBeyond )
826         *extraSpaceBeyond = 0;
827
828     return rectText;
829 }
830
831 #endif // wxUSE_TEXTCTRL
832
833 // ----------------------------------------------------------------------------
834 // scrollbars drawing
835 // ----------------------------------------------------------------------------
836
837 void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
838                                        wxDirection dir,
839                                        const wxRect& rect,
840                                        int flags)
841 {
842     DrawArrow(dc, dir, rect, flags);
843 }
844
845 void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
846 {
847     DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
848 }
849
850 // ----------------------------------------------------------------------------
851 // status bar
852 // ----------------------------------------------------------------------------
853
854 #if wxUSE_STATUSBAR
855
856 wxSize wxStdRenderer::GetStatusBarBorders() const
857 {
858     // Rendered border may be different depending on field's style, we use
859     // the largest value so that any field certainly fits into the borders
860     // we return:
861     wxRect raised = GetBorderDimensions(wxBORDER_RAISED);
862     wxRect flat = GetBorderDimensions(wxBORDER_STATIC);
863     wxASSERT_MSG( raised.x == raised.width && raised.y == raised.height &&
864                   flat.x == flat.width && flat.y == flat.height,
865                   wxT("this code expects uniform borders, you must override GetStatusBarBorders") );
866
867     // take the larger of flat/raised values:
868     wxSize border(wxMax(raised.x, flat.x), wxMax(raised.y, flat.y));
869
870     return border;
871 }
872
873 wxCoord wxStdRenderer::GetStatusBarBorderBetweenFields() const
874 {
875     return 2;
876 }
877
878 wxSize wxStdRenderer::GetStatusBarFieldMargins() const
879 {
880     return wxSize(2, 2);
881 }
882
883 void wxStdRenderer::DrawStatusField(wxDC& dc,
884                                     const wxRect& rect,
885                                     const wxString& label,
886                                     int flags,
887                                     int style)
888 {
889     wxRect rectIn;
890
891     if ( style == wxSB_RAISED )
892         DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
893     else if ( style != wxSB_FLAT )
894         DrawBorder(dc, wxBORDER_STATIC, rect, flags, &rectIn);
895     else
896         rectIn = rect;
897
898     rectIn.Deflate(GetStatusBarFieldMargins());
899
900     wxDCClipper clipper(dc, rectIn);
901     DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
902 }
903
904 #endif // wxUSE_STATUSBAR
905
906 // ----------------------------------------------------------------------------
907 // top level windows
908 // ----------------------------------------------------------------------------
909
910 int wxStdRenderer::HitTestFrame(const wxRect& rect, const wxPoint& pt, int flags) const
911 {
912     wxRect client = GetFrameClientArea(rect, flags);
913
914     if ( client.Contains(pt) )
915         return wxHT_TOPLEVEL_CLIENT_AREA;
916
917     if ( flags & wxTOPLEVEL_TITLEBAR )
918     {
919         wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
920
921         if ( flags & wxTOPLEVEL_ICON )
922         {
923             if ( wxRect(client.GetPosition(), GetFrameIconSize()).Contains(pt) )
924                 return wxHT_TOPLEVEL_ICON;
925         }
926
927         wxRect btnRect(client.GetRight() - 2 - FRAME_BUTTON_WIDTH,
928                        client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2,
929                        FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
930
931         if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
932         {
933             if ( btnRect.Contains(pt) )
934                 return wxHT_TOPLEVEL_BUTTON_CLOSE;
935             btnRect.x -= FRAME_BUTTON_WIDTH + 2;
936         }
937         if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
938         {
939             if ( btnRect.Contains(pt) )
940                 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE;
941             btnRect.x -= FRAME_BUTTON_WIDTH;
942         }
943         if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
944         {
945             if ( btnRect.Contains(pt) )
946                 return wxHT_TOPLEVEL_BUTTON_RESTORE;
947             btnRect.x -= FRAME_BUTTON_WIDTH;
948         }
949         if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
950         {
951             if ( btnRect.Contains(pt) )
952                 return wxHT_TOPLEVEL_BUTTON_ICONIZE;
953             btnRect.x -= FRAME_BUTTON_WIDTH;
954         }
955         if ( flags & wxTOPLEVEL_BUTTON_HELP )
956         {
957             if ( btnRect.Contains(pt) )
958                 return wxHT_TOPLEVEL_BUTTON_HELP;
959             btnRect.x -= FRAME_BUTTON_WIDTH;
960         }
961
962         if ( pt.y >= client.y && pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
963             return wxHT_TOPLEVEL_TITLEBAR;
964     }
965
966     if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
967     {
968         // we are certainly at one of borders, let's decide which one:
969
970         int border = 0;
971         // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
972         if ( pt.x < client.x )
973             border |= wxHT_TOPLEVEL_BORDER_W;
974         else if ( pt.x >= client.width + client.x )
975             border |= wxHT_TOPLEVEL_BORDER_E;
976         if ( pt.y < client.y )
977             border |= wxHT_TOPLEVEL_BORDER_N;
978         else if ( pt.y >= client.height + client.y )
979             border |= wxHT_TOPLEVEL_BORDER_S;
980         return border;
981     }
982
983     return wxHT_NOWHERE;
984 }
985
986 void wxStdRenderer::DrawFrameTitleBar(wxDC& dc,
987                                       const wxRect& rect,
988                                       const wxString& title,
989                                       const wxIcon& icon,
990                                       int flags,
991                                       int specialButton,
992                                       int specialButtonFlags)
993 {
994     if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
995     {
996         DrawFrameBorder(dc, rect, flags);
997     }
998     if ( flags & wxTOPLEVEL_TITLEBAR )
999     {
1000         DrawFrameBackground(dc, rect, flags);
1001         if ( flags & wxTOPLEVEL_ICON )
1002             DrawFrameIcon(dc, rect, icon, flags);
1003         DrawFrameTitle(dc, rect, title, flags);
1004
1005         wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1006         wxCoord x,y;
1007         x = client.GetRight() - 2 - FRAME_BUTTON_WIDTH;
1008         y = client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2;
1009
1010         if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1011         {
1012             DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_CLOSE,
1013                             (specialButton == wxTOPLEVEL_BUTTON_CLOSE) ?
1014                             specialButtonFlags : 0);
1015             x -= FRAME_BUTTON_WIDTH + 2;
1016         }
1017         if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1018         {
1019             DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_MAXIMIZE,
1020                             (specialButton == wxTOPLEVEL_BUTTON_MAXIMIZE) ?
1021                             specialButtonFlags : 0);
1022             x -= FRAME_BUTTON_WIDTH;
1023         }
1024         if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1025         {
1026             DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_RESTORE,
1027                             (specialButton == wxTOPLEVEL_BUTTON_RESTORE) ?
1028                             specialButtonFlags : 0);
1029             x -= FRAME_BUTTON_WIDTH;
1030         }
1031         if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1032         {
1033             DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_ICONIZE,
1034                             (specialButton == wxTOPLEVEL_BUTTON_ICONIZE) ?
1035                             specialButtonFlags : 0);
1036             x -= FRAME_BUTTON_WIDTH;
1037         }
1038         if ( flags & wxTOPLEVEL_BUTTON_HELP )
1039         {
1040             DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_HELP,
1041                             (specialButton == wxTOPLEVEL_BUTTON_HELP) ?
1042                             specialButtonFlags : 0);
1043         }
1044     }
1045 }
1046
1047 void wxStdRenderer::DrawFrameBorder(wxDC& dc, const wxRect& rect, int flags)
1048 {
1049     if ( !(flags & wxTOPLEVEL_BORDER) )
1050         return;
1051
1052     wxRect r(rect);
1053
1054     DrawAntiSunkenBorder(dc, &r);
1055     DrawExtraBorder(dc, &r);
1056     if ( flags & wxTOPLEVEL_RESIZEABLE )
1057         DrawExtraBorder(dc, &r);
1058 }
1059
1060 void wxStdRenderer::DrawFrameBackground(wxDC& dc, const wxRect& rect, int flags)
1061 {
1062     if ( !(flags & wxTOPLEVEL_TITLEBAR) )
1063         return;
1064
1065     wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1066                                     ? wxColourScheme::TITLEBAR_ACTIVE
1067                                     : wxColourScheme::TITLEBAR);
1068
1069     wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1070     r.height = FRAME_TITLEBAR_HEIGHT;
1071
1072     DrawBackground(dc, col, r);
1073 }
1074
1075 void wxStdRenderer::DrawFrameTitle(wxDC& dc,
1076                                    const wxRect& rect,
1077                                    const wxString& title,
1078                                    int flags)
1079 {
1080     wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1081                                     ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1082                                     : wxColourScheme::TITLEBAR_TEXT);
1083     dc.SetTextForeground(col);
1084
1085     wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1086     r.height = FRAME_TITLEBAR_HEIGHT;
1087     if ( flags & wxTOPLEVEL_ICON )
1088     {
1089         r.x += FRAME_TITLEBAR_HEIGHT;
1090         r.width -= FRAME_TITLEBAR_HEIGHT + 2;
1091     }
1092     else
1093     {
1094         r.x += 1;
1095         r.width -= 3;
1096     }
1097
1098     if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1099         r.width -= FRAME_BUTTON_WIDTH + 2;
1100     if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1101         r.width -= FRAME_BUTTON_WIDTH;
1102     if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1103         r.width -= FRAME_BUTTON_WIDTH;
1104     if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1105         r.width -= FRAME_BUTTON_WIDTH;
1106     if ( flags & wxTOPLEVEL_BUTTON_HELP )
1107         r.width -= FRAME_BUTTON_WIDTH;
1108
1109     dc.SetFont(m_titlebarFont);
1110
1111     wxString s;
1112     wxCoord textW;
1113     dc.GetTextExtent(title, &textW, NULL);
1114     if ( textW > r.width )
1115     {
1116         // text is too big, let's shorten it and add "..." after it:
1117         size_t len = title.length();
1118         wxCoord WSoFar, letterW;
1119
1120         dc.GetTextExtent(wxT("..."), &WSoFar, NULL);
1121         if ( WSoFar > r.width )
1122         {
1123             // not enough space to draw anything
1124             return;
1125         }
1126
1127         s.Alloc(len);
1128         for (size_t i = 0; i < len; i++)
1129         {
1130             dc.GetTextExtent(title[i], &letterW, NULL);
1131             if ( letterW + WSoFar > r.width )
1132                 break;
1133             WSoFar += letterW;
1134             s << title[i];
1135         }
1136         s << wxT("...");
1137     }
1138     else // no need to truncate the title
1139     {
1140         s = title;
1141     }
1142
1143     dc.DrawLabel(s, wxNullBitmap, r, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1144 }
1145
1146 void wxStdRenderer::DrawFrameIcon(wxDC& dc,
1147                                   const wxRect& rect,
1148                                   const wxIcon& icon,
1149                                   int flags)
1150 {
1151     if ( icon.IsOk() )
1152     {
1153         wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1154         dc.DrawIcon(icon, r.x, r.y);
1155     }
1156 }
1157
1158 void wxStdRenderer::DrawFrameButton(wxDC& dc,
1159                                     wxCoord x, wxCoord y,
1160                                     int button,
1161                                     int flags)
1162 {
1163     FrameButtonType idx;
1164     switch (button)
1165     {
1166         case wxTOPLEVEL_BUTTON_CLOSE:    idx = FrameButton_Close; break;
1167         case wxTOPLEVEL_BUTTON_MAXIMIZE: idx = FrameButton_Maximize; break;
1168         case wxTOPLEVEL_BUTTON_ICONIZE:  idx = FrameButton_Minimize; break;
1169         case wxTOPLEVEL_BUTTON_RESTORE:  idx = FrameButton_Restore; break;
1170         case wxTOPLEVEL_BUTTON_HELP:     idx = FrameButton_Help; break;
1171         default:
1172             wxFAIL_MSG(wxT("incorrect button specification"));
1173             return;
1174     }
1175
1176     wxBitmap bmp = GetFrameButtonBitmap(idx);
1177     if ( !bmp.IsOk() )
1178         return;
1179
1180     wxRect rectBtn(x, y, FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
1181     if ( flags & wxCONTROL_PRESSED )
1182     {
1183         DrawSunkenBorder(dc, &rectBtn);
1184
1185         rectBtn.Offset(1, 1);
1186     }
1187     else
1188     {
1189         DrawRaisedBorder(dc, &rectBtn);
1190     }
1191
1192     DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rectBtn);
1193
1194     wxRect rectBmp(0, 0, bmp.GetWidth(), bmp.GetHeight());
1195     dc.DrawBitmap(bmp, rectBmp.CentreIn(rectBtn).GetPosition(), true);
1196 }
1197
1198 int wxStdRenderer::GetFrameBorderWidth(int flags) const
1199 {
1200     return flags & wxTOPLEVEL_RESIZEABLE ? 4 : 3;
1201 }
1202
1203
1204 wxRect wxStdRenderer::GetFrameClientArea(const wxRect& rect, int flags) const
1205 {
1206     wxRect r(rect);
1207
1208     if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1209     {
1210         r.Inflate(-GetFrameBorderWidth(flags));
1211     }
1212
1213     if ( flags & wxTOPLEVEL_TITLEBAR )
1214     {
1215         r.y += FRAME_TITLEBAR_HEIGHT;
1216         r.height -= FRAME_TITLEBAR_HEIGHT;
1217     }
1218
1219     return r;
1220 }
1221
1222 wxSize
1223 wxStdRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) const
1224 {
1225     wxSize s(clientSize);
1226
1227     if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1228     {
1229         s.IncBy(2*GetFrameBorderWidth(flags));
1230     }
1231
1232     if ( flags & wxTOPLEVEL_TITLEBAR )
1233         s.y += FRAME_TITLEBAR_HEIGHT;
1234
1235     return s;
1236 }
1237
1238 wxSize wxStdRenderer::GetFrameMinSize(int flags) const
1239 {
1240     wxSize s;
1241
1242     if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1243     {
1244         s.IncBy(2*GetFrameBorderWidth(flags));
1245     }
1246
1247     if ( flags & wxTOPLEVEL_TITLEBAR )
1248     {
1249         s.y += FRAME_TITLEBAR_HEIGHT;
1250
1251         if ( flags & wxTOPLEVEL_ICON )
1252             s.x += FRAME_TITLEBAR_HEIGHT + 2;
1253         if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1254             s.x += FRAME_BUTTON_WIDTH + 2;
1255         if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1256             s.x += FRAME_BUTTON_WIDTH;
1257         if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1258             s.x += FRAME_BUTTON_WIDTH;
1259         if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1260             s.x += FRAME_BUTTON_WIDTH;
1261         if ( flags & wxTOPLEVEL_BUTTON_HELP )
1262             s.x += FRAME_BUTTON_WIDTH;
1263     }
1264
1265     return s;
1266 }
1267
1268 wxSize wxStdRenderer::GetFrameIconSize() const
1269 {
1270     return wxSize(16, 16);
1271 }