offset the text correctly inside the item rect in DrawItem(), it was off by 1
[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(_T("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 = col.Ok() ? col
171 : window ? m_scheme->GetBackground(window)
172 : wxSCHEME_COLOUR(m_scheme, CONTROL);
173
174 DrawSolidRect(dc, colBg, rect);
175 }
176
177
178 void wxStdRenderer::DrawButtonSurface(wxDC& dc,
179 const wxColour& col,
180 const wxRect& rect,
181 int flags)
182 {
183 DrawBackground(dc, col, rect, flags);
184 }
185
186 // ----------------------------------------------------------------------------
187 // text
188 // ----------------------------------------------------------------------------
189
190 void
191 wxStdRenderer::DrawFocusRect(wxDC& dc, const wxRect& rect, int WXUNUSED(flags))
192 {
193 // draw the pixels manually because the "dots" in wxPen with wxDOT style
194 // may be short traits and not really dots
195 //
196 // note that to behave in the same manner as DrawRect(), we must exclude
197 // the bottom and right borders from the rectangle
198 wxCoord x1 = rect.GetLeft(),
199 y1 = rect.GetTop(),
200 x2 = rect.GetRight(),
201 y2 = rect.GetBottom();
202
203 dc.SetPen(m_penBlack);
204
205 // this seems to be closer than what Windows does than wxINVERT although
206 // I'm still not sure if it's correct
207 dc.SetLogicalFunction(wxAND_REVERSE);
208
209 wxCoord z;
210 for ( z = x1 + 1; z < x2; z += 2 )
211 dc.DrawPoint(z, rect.GetTop());
212
213 wxCoord shift = z == x2 ? 0 : 1;
214 for ( z = y1 + shift; z < y2; z += 2 )
215 dc.DrawPoint(x2, z);
216
217 shift = z == y2 ? 0 : 1;
218 for ( z = x2 - shift; z > x1; z -= 2 )
219 dc.DrawPoint(z, y2);
220
221 shift = z == x1 ? 0 : 1;
222 for ( z = y2 - shift; z > y1; z -= 2 )
223 dc.DrawPoint(x1, z);
224
225 dc.SetLogicalFunction(wxCOPY);
226 }
227
228 void wxStdRenderer::DrawLabel(wxDC& dc,
229 const wxString& label,
230 const wxRect& rect,
231 int flags,
232 int alignment,
233 int indexAccel,
234 wxRect *rectBounds)
235 {
236 DrawButtonLabel(dc, label, wxNullBitmap, rect, flags,
237 alignment, indexAccel, rectBounds);
238 }
239
240 void wxStdRenderer::DrawButtonLabel(wxDC& dc,
241 const wxString& label,
242 const wxBitmap& image,
243 const wxRect& rect,
244 int flags,
245 int alignment,
246 int indexAccel,
247 wxRect *rectBounds)
248 {
249 wxRect rectLabel = rect;
250 if ( !label.empty() && (flags & wxCONTROL_DISABLED) )
251 {
252 if ( flags & wxCONTROL_PRESSED )
253 {
254 // shift the label if a button is pressed
255 rectLabel.Offset(1, 1);
256 }
257
258 // draw shadow of the text
259 dc.SetTextForeground(m_penHighlight.GetColour());
260 wxRect rectShadow = rect;
261 rectShadow.Offset(1, 1);
262 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
263
264 // make the main label text grey
265 dc.SetTextForeground(m_penDarkGrey.GetColour());
266
267 if ( flags & wxCONTROL_FOCUSED )
268 {
269 // leave enough space for the focus rect
270 rectLabel.Inflate(-2);
271 }
272 }
273
274 dc.DrawLabel(label, image, rectLabel, alignment, indexAccel, rectBounds);
275
276 if ( !label.empty() && (flags & wxCONTROL_FOCUSED) )
277 {
278 rectLabel.Inflate(-1);
279
280 DrawFocusRect(dc, rectLabel);
281 }
282 }
283
284 // ----------------------------------------------------------------------------
285 // borders
286 // ----------------------------------------------------------------------------
287
288 /*
289 We implement standard-looking 3D borders which have the following appearance:
290
291 The raised border:
292
293 WWWWWWWWWWWWWWWWWWWWWWB
294 WHHHHHHHHHHHHHHHHHHHHGB
295 WH GB W = white (HILIGHT)
296 WH GB H = light grey (LIGHT)
297 WH GB G = dark grey (SHADOI)
298 WH GB B = black (DKSHADOI)
299 WH GB
300 WH GB
301 WGGGGGGGGGGGGGGGGGGGGGB
302 BBBBBBBBBBBBBBBBBBBBBBB
303
304 The sunken border looks like this:
305
306 GGGGGGGGGGGGGGGGGGGGGGW
307 GBBBBBBBBBBBBBBBBBBBBHW
308 GB HW
309 GB HW
310 GB HW
311 GB HW
312 GB HW
313 GB HW
314 GHHHHHHHHHHHHHHHHHHHHHW
315 WWWWWWWWWWWWWWWWWWWWWWW
316
317 The static border (used for the controls which don't get focus) is like
318 this:
319
320 GGGGGGGGGGGGGGGGGGGGGGW
321 G W
322 G W
323 G W
324 G W
325 G W
326 G W
327 G W
328 WWWWWWWWWWWWWWWWWWWWWWW
329
330 The most complicated is the double border which is a combination of special
331 "anti-sunken" border and an extra border inside it:
332
333 HHHHHHHHHHHHHHHHHHHHHHB
334 HWWWWWWWWWWWWWWWWWWWWGB
335 HWHHHHHHHHHHHHHHHHHHHGB
336 HWH HGB
337 HWH HGB
338 HWH HGB
339 HWH HGB
340 HWHHHHHHHHHHHHHHHHHHHGB
341 HGGGGGGGGGGGGGGGGGGGGGB
342 BBBBBBBBBBBBBBBBBBBBBBB
343
344 And the simple border is, well, simple:
345
346 BBBBBBBBBBBBBBBBBBBBBBB
347 B B
348 B B
349 B B
350 B B
351 B B
352 B B
353 B B
354 B B
355 BBBBBBBBBBBBBBBBBBBBBBB
356 */
357
358 void wxStdRenderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
359 {
360 DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
361 DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
362 }
363
364 void wxStdRenderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
365 {
366 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
367 DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
368 }
369
370 void wxStdRenderer::DrawAntiSunkenBorder(wxDC& dc, wxRect *rect)
371 {
372 DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
373 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
374 }
375
376 void wxStdRenderer::DrawBoxBorder(wxDC& dc, wxRect *rect)
377 {
378 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
379 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
380 }
381
382 void wxStdRenderer::DrawStaticBorder(wxDC& dc, wxRect *rect)
383 {
384 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
385 }
386
387 void wxStdRenderer::DrawExtraBorder(wxDC& dc, wxRect *rect)
388 {
389 DrawRect(dc, rect, m_penLightGrey);
390 }
391
392 void wxStdRenderer::DrawBorder(wxDC& dc,
393 wxBorder border,
394 const wxRect& rectTotal,
395 int WXUNUSED(flags),
396 wxRect *rectIn)
397 {
398 wxRect rect = rectTotal;
399
400 switch ( border )
401 {
402 case wxBORDER_SUNKEN:
403 DrawSunkenBorder(dc, &rect);
404 break;
405
406 case wxBORDER_DOUBLE:
407 DrawAntiSunkenBorder(dc, &rect);
408 DrawExtraBorder(dc, &rect);
409 break;
410
411 case wxBORDER_STATIC:
412 DrawStaticBorder(dc, &rect);
413 break;
414
415 case wxBORDER_RAISED:
416 DrawRaisedBorder(dc, &rect);
417 break;
418
419 case wxBORDER_SIMPLE:
420 DrawRect(dc, &rect, m_penBlack);
421 break;
422
423 default:
424 wxFAIL_MSG(_T("unknown border type"));
425 // fall through
426
427 case wxBORDER_DEFAULT:
428 case wxBORDER_NONE:
429 break;
430 }
431
432 if ( rectIn )
433 *rectIn = rect;
434 }
435
436 wxRect wxStdRenderer::GetBorderDimensions(wxBorder border) const
437 {
438 wxCoord width;
439 switch ( border )
440 {
441 case wxBORDER_SIMPLE:
442 case wxBORDER_STATIC:
443 width = 1;
444 break;
445
446 case wxBORDER_RAISED:
447 case wxBORDER_SUNKEN:
448 width = 2;
449 break;
450
451 case wxBORDER_DOUBLE:
452 width = 3;
453 break;
454
455 default:
456 wxFAIL_MSG(_T("unknown border type"));
457 // fall through
458
459 case wxBORDER_DEFAULT:
460 case wxBORDER_NONE:
461 width = 0;
462 break;
463 }
464
465 wxRect rect;
466 rect.x =
467 rect.y =
468 rect.width =
469 rect.height = width;
470
471 return rect;
472 }
473
474 void wxStdRenderer::AdjustSize(wxSize *size, const wxWindow *window)
475 {
476 // take into account the border width
477 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
478 size->x += rectBorder.x + rectBorder.width;
479 size->y += rectBorder.y + rectBorder.height;
480 }
481
482 bool wxStdRenderer::AreScrollbarsInsideBorder() const
483 {
484 return false;
485 }
486
487 wxCoord wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight)
488 {
489 return fontHeight + 2*ITEM_MARGIN;
490 }
491
492 void wxStdRenderer::DrawTextBorder(wxDC& dc,
493 wxBorder border,
494 const wxRect& rect,
495 int flags,
496 wxRect *rectIn)
497 {
498 DrawBorder(dc, border, rect, flags, rectIn);
499 }
500
501 // ----------------------------------------------------------------------------
502 // lines and boxes
503 // ----------------------------------------------------------------------------
504
505 void
506 wxStdRenderer::DrawHorizontalLine(wxDC& dc, wxCoord y, wxCoord x1, wxCoord x2)
507 {
508 dc.SetPen(m_penDarkGrey);
509 dc.DrawLine(x1, y, x2 + 1, y);
510
511 dc.SetPen(m_penHighlight);
512 y++;
513 dc.DrawLine(x1, y, x2 + 1, y);
514 }
515
516 void
517 wxStdRenderer::DrawVerticalLine(wxDC& dc, wxCoord x, wxCoord y1, wxCoord y2)
518 {
519 dc.SetPen(m_penDarkGrey);
520 dc.DrawLine(x, y1, x, y2 + 1);
521
522 dc.SetPen(m_penHighlight);
523 x++;
524 dc.DrawLine(x, y1, x, y2 + 1);
525 }
526
527 void wxStdRenderer::DrawFrameWithoutLabel(wxDC& dc,
528 const wxRect& rectFrame,
529 const wxRect& rectLabel)
530 {
531 // draw left, bottom and right lines entirely
532 DrawVerticalLine(dc, rectFrame.GetLeft(),
533 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
534 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
535 rectFrame.GetLeft(), rectFrame.GetRight());
536 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
537 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
538
539 // and 2 parts of the top line
540 DrawHorizontalLine(dc, rectFrame.GetTop(),
541 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
542 DrawHorizontalLine(dc, rectFrame.GetTop(),
543 rectLabel.GetRight(), rectFrame.GetRight() - 2);
544 }
545
546 void wxStdRenderer::DrawFrameWithLabel(wxDC& dc,
547 const wxString& label,
548 const wxRect& rectFrame,
549 const wxRect& rectText,
550 int flags,
551 int alignment,
552 int indexAccel)
553 {
554 wxRect rectLabel;
555 DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
556
557 DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
558 }
559
560 void wxStdRenderer::DrawFrame(wxDC& dc,
561 const wxString& label,
562 const wxRect& rect,
563 int flags,
564 int alignment,
565 int indexAccel)
566 {
567 wxCoord height = 0; // of the label
568 wxRect rectFrame = rect;
569 if ( !label.empty() )
570 {
571 // the text should touch the top border of the rect, so the frame
572 // itself should be lower
573 dc.GetTextExtent(label, NULL, &height);
574 rectFrame.y += height / 2;
575 rectFrame.height -= height / 2;
576
577 // we have to draw each part of the frame individually as we can't
578 // erase the background beyond the label as it might contain some
579 // pixmap already, so drawing everything and then overwriting part of
580 // the frame with label doesn't work
581
582 // TODO: the +5 shouldn't be hard coded
583 wxRect rectText;
584 rectText.x = rectFrame.x + 5;
585 rectText.y = rect.y;
586 rectText.width = rectFrame.width - 7; // +2 border width
587 rectText.height = height;
588
589 DrawFrameWithLabel(dc, label, rectFrame, rectText, flags,
590 alignment, indexAccel);
591 }
592 else // no label
593 {
594 DrawBoxBorder(dc, &rectFrame);
595 }
596 }
597
598 void wxStdRenderer::DrawItem(wxDC& dc,
599 const wxString& label,
600 const wxRect& rect,
601 int flags)
602 {
603 wxDCTextColourChanger colChanger(dc);
604
605 if ( flags & wxCONTROL_SELECTED )
606 {
607 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
608
609 const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
610 dc.SetBrush(colBg);
611 dc.SetPen(colBg);
612 dc.DrawRectangle(rect);
613 }
614
615 // horizontal adjustment is arbitrary
616 wxRect rectText = rect;
617 rectText.Deflate(2, ITEM_MARGIN);
618 dc.DrawLabel(label, wxNullBitmap, rectText);
619
620 if ( flags & wxCONTROL_FOCUSED )
621 {
622 DrawFocusRect(dc, rect, flags);
623 }
624 }
625
626 void wxStdRenderer::DrawCheckItemBitmap(wxDC& dc,
627 const wxBitmap& bitmap,
628 const wxRect& rect,
629 int flags)
630 {
631 DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags);
632 }
633
634 void wxStdRenderer::DrawCheckItem(wxDC& dc,
635 const wxString& label,
636 const wxBitmap& bitmap,
637 const wxRect& rect,
638 int flags)
639 {
640 wxRect rectBitmap = rect;
641 rectBitmap.width = GetCheckBitmapSize().x;
642 DrawCheckItemBitmap(dc, bitmap, rectBitmap, flags);
643
644 wxRect rectLabel = rect;
645 wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin();
646 rectLabel.x += shift;
647 rectLabel.width -= shift;
648 DrawItem(dc, label, rectLabel, flags);
649 }
650
651 // ----------------------------------------------------------------------------
652 // check and radio bitmaps
653 // ----------------------------------------------------------------------------
654
655 void wxStdRenderer::DrawCheckButton(wxDC& dc,
656 const wxString& label,
657 const wxBitmap& bitmap,
658 const wxRect& rect,
659 int flags,
660 wxAlignment align,
661 int indexAccel)
662 {
663 wxBitmap bmp(bitmap.Ok() ? bitmap : GetCheckBitmap(flags));
664
665 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
666 }
667
668 void wxStdRenderer::DrawRadioButton(wxDC& dc,
669 const wxString& label,
670 const wxBitmap& bitmap,
671 const wxRect& rect,
672 int flags,
673 wxAlignment align,
674 int indexAccel)
675 {
676 wxBitmap bmp(bitmap.Ok() ? bitmap : GetRadioBitmap(flags));
677
678 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
679 }
680
681 void wxStdRenderer::DrawCheckOrRadioButton(wxDC& dc,
682 const wxString& label,
683 const wxBitmap& bitmap,
684 const wxRect& rect,
685 int flags,
686 wxAlignment align,
687 int indexAccel)
688 {
689 // calculate the position of the bitmap and of the label
690 wxCoord heightBmp = bitmap.GetHeight();
691 wxCoord xBmp,
692 yBmp = rect.y + (rect.height - heightBmp) / 2;
693
694 wxRect rectLabel;
695 dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
696 rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
697
698 // align label vertically with the bitmap - looks nicer like this
699 rectLabel.y -= (rectLabel.height - heightBmp) % 2;
700
701 // calc horz position
702 if ( align == wxALIGN_RIGHT )
703 {
704 xBmp = rect.GetRight() - bitmap.GetWidth();
705 rectLabel.x = rect.x + 3;
706 rectLabel.SetRight(xBmp);
707 }
708 else // normal (checkbox to the left of the text) case
709 {
710 xBmp = rect.x;
711 rectLabel.x = xBmp + bitmap.GetWidth() + 5;
712 rectLabel.SetRight(rect.GetRight());
713 }
714
715 dc.DrawBitmap(bitmap, xBmp, yBmp, true /* use mask */);
716
717 DrawLabel(dc, label, rectLabel, flags,
718 wxALIGN_LEFT | wxALIGN_TOP, indexAccel);
719 }
720
721 #if wxUSE_TEXTCTRL
722
723 void wxStdRenderer::DrawTextLine(wxDC& dc,
724 const wxString& text,
725 const wxRect& rect,
726 int selStart,
727 int selEnd,
728 int flags)
729 {
730 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
731 {
732 // just draw it as is
733 dc.DrawText(text, rect.x, rect.y);
734 }
735 else // we have selection
736 {
737 wxCoord width,
738 x = rect.x;
739
740 // draw the part before selection
741 wxString s(text, (size_t)selStart);
742 if ( !s.empty() )
743 {
744 dc.DrawText(s, x, rect.y);
745
746 dc.GetTextExtent(s, &width, NULL);
747 x += width;
748 }
749
750 // draw the selection itself
751 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
752 if ( !s.empty() )
753 {
754 wxColour colFg = dc.GetTextForeground(),
755 colBg = dc.GetTextBackground();
756 dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
757 dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT));
758 dc.SetBackgroundMode(wxSOLID);
759
760 dc.DrawText(s, x, rect.y);
761 dc.GetTextExtent(s, &width, NULL);
762 x += width;
763
764 dc.SetBackgroundMode(wxTRANSPARENT);
765 dc.SetTextBackground(colBg);
766 dc.SetTextForeground(colFg);
767 }
768
769 // draw the final part
770 s = text.c_str() + selEnd;
771 if ( !s.empty() )
772 {
773 dc.DrawText(s, x, rect.y);
774 }
775 }
776 }
777
778 void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
779 const wxRect& WXUNUSED(rect))
780 {
781 // nothing by default
782 }
783
784 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
785 {
786 return 1;
787 }
788
789 wxRect
790 wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
791 {
792 wxRect rectTotal = rect;
793 rectTotal.Inflate(GetTextBorderWidth(text));
794 return rectTotal;
795 }
796
797 wxRect wxStdRenderer::GetTextClientArea(const wxTextCtrl *text,
798 const wxRect& rect,
799 wxCoord *extraSpaceBeyond) const
800 {
801 wxRect rectText = rect;
802 rectText.Deflate(GetTextBorderWidth(text));
803
804 if ( extraSpaceBeyond )
805 *extraSpaceBeyond = 0;
806
807 return rectText;
808 }
809
810 #endif // wxUSE_TEXTCTRL
811
812 // ----------------------------------------------------------------------------
813 // scrollbars drawing
814 // ----------------------------------------------------------------------------
815
816 void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
817 wxDirection dir,
818 const wxRect& rect,
819 int flags)
820 {
821 DrawArrow(dc, dir, rect, flags);
822 }
823
824 void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
825 {
826 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
827 }
828
829 // ----------------------------------------------------------------------------
830 // scrollbars geometry
831 // ----------------------------------------------------------------------------
832
833 #if wxUSE_SCROLLBAR
834
835 /* static */
836 void wxStdRenderer::GetScrollBarThumbSize(wxCoord length,
837 int thumbPos,
838 int thumbSize,
839 int range,
840 wxCoord *thumbStart,
841 wxCoord *thumbEnd)
842 {
843 // the thumb can't be made less than this number of pixels
844 static const wxCoord thumbMinWidth = 8; // FIXME: should be configurable
845
846 *thumbStart = (length*thumbPos) / range;
847 *thumbEnd = (length*(thumbPos + thumbSize)) / range;
848
849 if ( *thumbEnd - *thumbStart < thumbMinWidth )
850 {
851 // adjust the end if possible
852 if ( *thumbStart <= length - thumbMinWidth )
853 {
854 // yes, just make it wider
855 *thumbEnd = *thumbStart + thumbMinWidth;
856 }
857 else // it is at the bottom of the scrollbar
858 {
859 // so move it a bit up
860 *thumbStart = length - thumbMinWidth;
861 *thumbEnd = length;
862 }
863 }
864 }
865
866 wxRect wxStdRenderer::GetScrollbarRect(const wxScrollBar *scrollbar,
867 wxScrollBar::Element elem,
868 int thumbPos) const
869 {
870 if ( thumbPos == -1 )
871 {
872 thumbPos = scrollbar->GetThumbPosition();
873 }
874
875 const wxSize sizeArrow = GetScrollbarArrowSize();
876
877 wxSize sizeTotal = scrollbar->GetClientSize();
878 wxCoord *start, *width;
879 wxCoord length, arrow;
880 wxRect rect;
881 if ( scrollbar->IsVertical() )
882 {
883 rect.x = 0;
884 rect.width = sizeTotal.x;
885 length = sizeTotal.y;
886 start = &rect.y;
887 width = &rect.height;
888 arrow = sizeArrow.y;
889 }
890 else // horizontal
891 {
892 rect.y = 0;
893 rect.height = sizeTotal.y;
894 length = sizeTotal.x;
895 start = &rect.x;
896 width = &rect.width;
897 arrow = sizeArrow.x;
898 }
899
900 switch ( elem )
901 {
902 case wxScrollBar::Element_Arrow_Line_1:
903 *start = 0;
904 *width = arrow;
905 break;
906
907 case wxScrollBar::Element_Arrow_Line_2:
908 *start = length - arrow;
909 *width = arrow;
910 break;
911
912 case wxScrollBar::Element_Arrow_Page_1:
913 case wxScrollBar::Element_Arrow_Page_2:
914 // we don't have them at all
915 break;
916
917 case wxScrollBar::Element_Thumb:
918 case wxScrollBar::Element_Bar_1:
919 case wxScrollBar::Element_Bar_2:
920 // we need to calculate the thumb position - do it
921 {
922 length -= 2*arrow;
923 wxCoord thumbStart, thumbEnd;
924 int range = scrollbar->GetRange();
925 if ( !range )
926 {
927 thumbStart =
928 thumbEnd = 0;
929 }
930 else
931 {
932 GetScrollBarThumbSize(length,
933 thumbPos,
934 scrollbar->GetThumbSize(),
935 range,
936 &thumbStart,
937 &thumbEnd);
938 }
939
940 if ( elem == wxScrollBar::Element_Thumb )
941 {
942 *start = thumbStart;
943 *width = thumbEnd - thumbStart;
944 }
945 else if ( elem == wxScrollBar::Element_Bar_1 )
946 {
947 *start = 0;
948 *width = thumbStart;
949 }
950 else // elem == wxScrollBar::Element_Bar_2
951 {
952 *start = thumbEnd;
953 *width = length - thumbEnd;
954 }
955
956 // everything is relative to the start of the shaft so far
957 *start += arrow;
958 }
959 break;
960
961 case wxScrollBar::Element_Max:
962 default:
963 wxFAIL_MSG( _T("unknown scrollbar element") );
964 }
965
966 return rect;
967 }
968
969 wxCoord wxStdRenderer::GetScrollbarSize(const wxScrollBar *scrollbar)
970 {
971 const wxSize sizeArrowSB = GetScrollbarArrowSize();
972
973 wxCoord sizeArrow, sizeTotal;
974 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
975 {
976 sizeArrow = sizeArrowSB.y;
977 sizeTotal = scrollbar->GetSize().y;
978 }
979 else // horizontal
980 {
981 sizeArrow = sizeArrowSB.x;
982 sizeTotal = scrollbar->GetSize().x;
983 }
984
985 return sizeTotal - 2*sizeArrow;
986 }
987
988 wxHitTest
989 wxStdRenderer::HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const
990 {
991 // we only need to work with either x or y coord depending on the
992 // orientation, choose one (but still check the other one to verify if the
993 // mouse is in the window at all)
994 const wxSize sizeArrowSB = GetScrollbarArrowSize();
995
996 wxCoord coord, sizeArrow, sizeTotal;
997 wxSize size = scrollbar->GetSize();
998 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
999 {
1000 if ( pt.x < 0 || pt.x > size.x )
1001 return wxHT_NOWHERE;
1002
1003 coord = pt.y;
1004 sizeArrow = sizeArrowSB.y;
1005 sizeTotal = size.y;
1006 }
1007 else // horizontal
1008 {
1009 if ( pt.y < 0 || pt.y > size.y )
1010 return wxHT_NOWHERE;
1011
1012 coord = pt.x;
1013 sizeArrow = sizeArrowSB.x;
1014 sizeTotal = size.x;
1015 }
1016
1017 // test for the arrows first as it's faster
1018 if ( coord < 0 || coord > sizeTotal )
1019 {
1020 return wxHT_NOWHERE;
1021 }
1022 else if ( coord < sizeArrow )
1023 {
1024 return wxHT_SCROLLBAR_ARROW_LINE_1;
1025 }
1026 else if ( coord > sizeTotal - sizeArrow )
1027 {
1028 return wxHT_SCROLLBAR_ARROW_LINE_2;
1029 }
1030 else
1031 {
1032 // calculate the thumb position in pixels
1033 sizeTotal -= 2*sizeArrow;
1034 wxCoord thumbStart, thumbEnd;
1035 int range = scrollbar->GetRange();
1036 if ( !range )
1037 {
1038 // clicking the scrollbar without range has no effect
1039 return wxHT_NOWHERE;
1040 }
1041 else
1042 {
1043 GetScrollBarThumbSize(sizeTotal,
1044 scrollbar->GetThumbPosition(),
1045 scrollbar->GetThumbSize(),
1046 range,
1047 &thumbStart,
1048 &thumbEnd);
1049 }
1050
1051 // now compare with the thumb position
1052 coord -= sizeArrow;
1053 if ( coord < thumbStart )
1054 return wxHT_SCROLLBAR_BAR_1;
1055 else if ( coord > thumbEnd )
1056 return wxHT_SCROLLBAR_BAR_2;
1057 else
1058 return wxHT_SCROLLBAR_THUMB;
1059 }
1060 }
1061
1062
1063 wxCoord
1064 wxStdRenderer::ScrollbarToPixel(const wxScrollBar *scrollbar, int thumbPos)
1065 {
1066 int range = scrollbar->GetRange();
1067 if ( !range )
1068 {
1069 // the only valid position anyhow
1070 return 0;
1071 }
1072
1073 if ( thumbPos == -1 )
1074 {
1075 // by default use the current thumb position
1076 thumbPos = scrollbar->GetThumbPosition();
1077 }
1078
1079 const wxSize sizeArrow = GetScrollbarArrowSize();
1080 return (thumbPos*GetScrollbarSize(scrollbar)) / range
1081 + (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x);
1082 }
1083
1084 int wxStdRenderer::PixelToScrollbar(const wxScrollBar *scrollbar, wxCoord coord)
1085 {
1086 const wxSize sizeArrow = GetScrollbarArrowSize();
1087 return ((coord - (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x)) *
1088 scrollbar->GetRange() ) / GetScrollbarSize(scrollbar);
1089 }
1090
1091 #endif // wxUSE_SCROLLBAR
1092
1093 // ----------------------------------------------------------------------------
1094 // status bar
1095 // ----------------------------------------------------------------------------
1096
1097 #if wxUSE_STATUSBAR
1098
1099 wxSize wxStdRenderer::GetStatusBarBorders() const
1100 {
1101 // Rendered border may be different depending on field's style, we use
1102 // the largest value so that any field certainly fits into the borders
1103 // we return:
1104 wxRect raised = GetBorderDimensions(wxBORDER_RAISED);
1105 wxRect flat = GetBorderDimensions(wxBORDER_STATIC);
1106 wxASSERT_MSG( raised.x == raised.width && raised.y == raised.height &&
1107 flat.x == flat.width && flat.y == flat.height,
1108 _T("this code expects uniform borders, you must override GetStatusBarBorders") );
1109
1110 // take the larger of flat/raised values:
1111 wxSize border(wxMax(raised.x, flat.x), wxMax(raised.y, flat.y));
1112
1113 return border;
1114 }
1115
1116 wxCoord wxStdRenderer::GetStatusBarBorderBetweenFields() const
1117 {
1118 return 2;
1119 }
1120
1121 wxSize wxStdRenderer::GetStatusBarFieldMargins() const
1122 {
1123 return wxSize(2, 2);
1124 }
1125
1126 void wxStdRenderer::DrawStatusField(wxDC& dc,
1127 const wxRect& rect,
1128 const wxString& label,
1129 int flags,
1130 int style)
1131 {
1132 wxRect rectIn;
1133
1134 if ( style == wxSB_RAISED )
1135 DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
1136 else if ( style != wxSB_FLAT )
1137 DrawBorder(dc, wxBORDER_STATIC, rect, flags, &rectIn);
1138
1139 rectIn.Deflate(GetStatusBarFieldMargins());
1140
1141 wxDCClipper clipper(dc, rectIn);
1142 DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1143 }
1144
1145 #endif // wxUSE_STATUSBAR
1146
1147 // ----------------------------------------------------------------------------
1148 // top level windows
1149 // ----------------------------------------------------------------------------
1150
1151 int wxStdRenderer::HitTestFrame(const wxRect& rect, const wxPoint& pt, int flags) const
1152 {
1153 wxRect client = GetFrameClientArea(rect, flags);
1154
1155 if ( client.Contains(pt) )
1156 return wxHT_TOPLEVEL_CLIENT_AREA;
1157
1158 if ( flags & wxTOPLEVEL_TITLEBAR )
1159 {
1160 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1161
1162 if ( flags & wxTOPLEVEL_ICON )
1163 {
1164 if ( wxRect(client.GetPosition(), GetFrameIconSize()).Contains(pt) )
1165 return wxHT_TOPLEVEL_ICON;
1166 }
1167
1168 wxRect btnRect(client.GetRight() - 2 - FRAME_BUTTON_WIDTH,
1169 client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2,
1170 FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
1171
1172 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1173 {
1174 if ( btnRect.Contains(pt) )
1175 return wxHT_TOPLEVEL_BUTTON_CLOSE;
1176 btnRect.x -= FRAME_BUTTON_WIDTH + 2;
1177 }
1178 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1179 {
1180 if ( btnRect.Contains(pt) )
1181 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE;
1182 btnRect.x -= FRAME_BUTTON_WIDTH;
1183 }
1184 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1185 {
1186 if ( btnRect.Contains(pt) )
1187 return wxHT_TOPLEVEL_BUTTON_RESTORE;
1188 btnRect.x -= FRAME_BUTTON_WIDTH;
1189 }
1190 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1191 {
1192 if ( btnRect.Contains(pt) )
1193 return wxHT_TOPLEVEL_BUTTON_ICONIZE;
1194 btnRect.x -= FRAME_BUTTON_WIDTH;
1195 }
1196 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1197 {
1198 if ( btnRect.Contains(pt) )
1199 return wxHT_TOPLEVEL_BUTTON_HELP;
1200 btnRect.x -= FRAME_BUTTON_WIDTH;
1201 }
1202
1203 if ( pt.y >= client.y && pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
1204 return wxHT_TOPLEVEL_TITLEBAR;
1205 }
1206
1207 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1208 {
1209 // we are certainly at one of borders, let's decide which one:
1210
1211 int border = 0;
1212 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
1213 if ( pt.x < client.x )
1214 border |= wxHT_TOPLEVEL_BORDER_W;
1215 else if ( pt.x >= client.width + client.x )
1216 border |= wxHT_TOPLEVEL_BORDER_E;
1217 if ( pt.y < client.y )
1218 border |= wxHT_TOPLEVEL_BORDER_N;
1219 else if ( pt.y >= client.height + client.y )
1220 border |= wxHT_TOPLEVEL_BORDER_S;
1221 return border;
1222 }
1223
1224 return wxHT_NOWHERE;
1225 }
1226
1227 void wxStdRenderer::DrawFrameTitleBar(wxDC& dc,
1228 const wxRect& rect,
1229 const wxString& title,
1230 const wxIcon& icon,
1231 int flags,
1232 int specialButton,
1233 int specialButtonFlags)
1234 {
1235 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1236 {
1237 DrawFrameBorder(dc, rect, flags);
1238 }
1239 if ( flags & wxTOPLEVEL_TITLEBAR )
1240 {
1241 DrawFrameBackground(dc, rect, flags);
1242 if ( flags & wxTOPLEVEL_ICON )
1243 DrawFrameIcon(dc, rect, icon, flags);
1244 DrawFrameTitle(dc, rect, title, flags);
1245
1246 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1247 wxCoord x,y;
1248 x = client.GetRight() - 2 - FRAME_BUTTON_WIDTH;
1249 y = client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2;
1250
1251 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1252 {
1253 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_CLOSE,
1254 (specialButton == wxTOPLEVEL_BUTTON_CLOSE) ?
1255 specialButtonFlags : 0);
1256 x -= FRAME_BUTTON_WIDTH + 2;
1257 }
1258 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1259 {
1260 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_MAXIMIZE,
1261 (specialButton == wxTOPLEVEL_BUTTON_MAXIMIZE) ?
1262 specialButtonFlags : 0);
1263 x -= FRAME_BUTTON_WIDTH;
1264 }
1265 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1266 {
1267 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_RESTORE,
1268 (specialButton == wxTOPLEVEL_BUTTON_RESTORE) ?
1269 specialButtonFlags : 0);
1270 x -= FRAME_BUTTON_WIDTH;
1271 }
1272 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1273 {
1274 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_ICONIZE,
1275 (specialButton == wxTOPLEVEL_BUTTON_ICONIZE) ?
1276 specialButtonFlags : 0);
1277 x -= FRAME_BUTTON_WIDTH;
1278 }
1279 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1280 {
1281 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_HELP,
1282 (specialButton == wxTOPLEVEL_BUTTON_HELP) ?
1283 specialButtonFlags : 0);
1284 }
1285 }
1286 }
1287
1288 void wxStdRenderer::DrawFrameBorder(wxDC& dc, const wxRect& rect, int flags)
1289 {
1290 if ( !(flags & wxTOPLEVEL_BORDER) )
1291 return;
1292
1293 wxRect r(rect);
1294
1295 DrawAntiSunkenBorder(dc, &r);
1296 DrawExtraBorder(dc, &r);
1297 if ( flags & wxTOPLEVEL_RESIZEABLE )
1298 DrawExtraBorder(dc, &r);
1299 }
1300
1301 void wxStdRenderer::DrawFrameBackground(wxDC& dc, const wxRect& rect, int flags)
1302 {
1303 if ( !(flags & wxTOPLEVEL_TITLEBAR) )
1304 return;
1305
1306 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1307 ? wxColourScheme::TITLEBAR_ACTIVE
1308 : wxColourScheme::TITLEBAR);
1309
1310 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1311 r.height = FRAME_TITLEBAR_HEIGHT;
1312
1313 DrawBackground(dc, col, r);
1314 }
1315
1316 void wxStdRenderer::DrawFrameTitle(wxDC& dc,
1317 const wxRect& rect,
1318 const wxString& title,
1319 int flags)
1320 {
1321 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1322 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1323 : wxColourScheme::TITLEBAR_TEXT);
1324 dc.SetTextForeground(col);
1325
1326 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1327 r.height = FRAME_TITLEBAR_HEIGHT;
1328 if ( flags & wxTOPLEVEL_ICON )
1329 {
1330 r.x += FRAME_TITLEBAR_HEIGHT;
1331 r.width -= FRAME_TITLEBAR_HEIGHT + 2;
1332 }
1333 else
1334 {
1335 r.x += 1;
1336 r.width -= 3;
1337 }
1338
1339 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1340 r.width -= FRAME_BUTTON_WIDTH + 2;
1341 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1342 r.width -= FRAME_BUTTON_WIDTH;
1343 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1344 r.width -= FRAME_BUTTON_WIDTH;
1345 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1346 r.width -= FRAME_BUTTON_WIDTH;
1347 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1348 r.width -= FRAME_BUTTON_WIDTH;
1349
1350 dc.SetFont(m_titlebarFont);
1351
1352 wxString s;
1353 wxCoord textW;
1354 dc.GetTextExtent(title, &textW, NULL);
1355 if ( textW > r.width )
1356 {
1357 // text is too big, let's shorten it and add "..." after it:
1358 size_t len = title.length();
1359 wxCoord WSoFar, letterW;
1360
1361 dc.GetTextExtent(wxT("..."), &WSoFar, NULL);
1362 if ( WSoFar > r.width )
1363 {
1364 // not enough space to draw anything
1365 return;
1366 }
1367
1368 s.Alloc(len);
1369 for (size_t i = 0; i < len; i++)
1370 {
1371 dc.GetTextExtent(title[i], &letterW, NULL);
1372 if ( letterW + WSoFar > r.width )
1373 break;
1374 WSoFar += letterW;
1375 s << title[i];
1376 }
1377 s << wxT("...");
1378 }
1379 else // no need to truncate the title
1380 {
1381 s = title;
1382 }
1383
1384 dc.DrawLabel(s, wxNullBitmap, r, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1385 }
1386
1387 void wxStdRenderer::DrawFrameIcon(wxDC& dc,
1388 const wxRect& rect,
1389 const wxIcon& icon,
1390 int flags)
1391 {
1392 if ( icon.Ok() )
1393 {
1394 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1395 dc.DrawIcon(icon, r.x, r.y);
1396 }
1397 }
1398
1399 void wxStdRenderer::DrawFrameButton(wxDC& dc,
1400 wxCoord x, wxCoord y,
1401 int button,
1402 int flags)
1403 {
1404 FrameButtonType idx;
1405 switch (button)
1406 {
1407 case wxTOPLEVEL_BUTTON_CLOSE: idx = FrameButton_Close; break;
1408 case wxTOPLEVEL_BUTTON_MAXIMIZE: idx = FrameButton_Maximize; break;
1409 case wxTOPLEVEL_BUTTON_ICONIZE: idx = FrameButton_Minimize; break;
1410 case wxTOPLEVEL_BUTTON_RESTORE: idx = FrameButton_Restore; break;
1411 case wxTOPLEVEL_BUTTON_HELP: idx = FrameButton_Help; break;
1412 default:
1413 wxFAIL_MSG(wxT("incorrect button specification"));
1414 return;
1415 }
1416
1417 wxBitmap bmp = GetFrameButtonBitmap(idx);
1418 if ( !bmp.Ok() )
1419 return;
1420
1421 wxRect rectBtn(x, y, FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
1422 if ( flags & wxCONTROL_PRESSED )
1423 {
1424 DrawSunkenBorder(dc, &rectBtn);
1425
1426 rectBtn.Offset(1, 1);
1427 }
1428 else
1429 {
1430 DrawRaisedBorder(dc, &rectBtn);
1431 }
1432
1433 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rectBtn);
1434
1435 wxRect rectBmp(0, 0, bmp.GetWidth(), bmp.GetHeight());
1436 dc.DrawBitmap(bmp, rectBmp.CentreIn(rectBtn).GetPosition(), true);
1437 }
1438
1439 int wxStdRenderer::GetFrameBorderWidth(int flags) const
1440 {
1441 return flags & wxTOPLEVEL_RESIZEABLE ? 4 : 3;
1442 }
1443
1444
1445 wxRect wxStdRenderer::GetFrameClientArea(const wxRect& rect, int flags) const
1446 {
1447 wxRect r(rect);
1448
1449 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1450 {
1451 r.Inflate(-GetFrameBorderWidth(flags));
1452 }
1453
1454 if ( flags & wxTOPLEVEL_TITLEBAR )
1455 {
1456 r.y += FRAME_TITLEBAR_HEIGHT;
1457 r.height -= FRAME_TITLEBAR_HEIGHT;
1458 }
1459
1460 return r;
1461 }
1462
1463 wxSize
1464 wxStdRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) const
1465 {
1466 wxSize s(clientSize);
1467
1468 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1469 {
1470 s.IncBy(2*GetFrameBorderWidth(flags));
1471 }
1472
1473 if ( flags & wxTOPLEVEL_TITLEBAR )
1474 s.y += FRAME_TITLEBAR_HEIGHT;
1475
1476 return s;
1477 }
1478
1479 wxSize wxStdRenderer::GetFrameMinSize(int flags) const
1480 {
1481 wxSize s;
1482
1483 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1484 {
1485 s.IncBy(2*GetFrameBorderWidth(flags));
1486 }
1487
1488 if ( flags & wxTOPLEVEL_TITLEBAR )
1489 {
1490 s.y += FRAME_TITLEBAR_HEIGHT;
1491
1492 if ( flags & wxTOPLEVEL_ICON )
1493 s.x += FRAME_TITLEBAR_HEIGHT + 2;
1494 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1495 s.x += FRAME_BUTTON_WIDTH + 2;
1496 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1497 s.x += FRAME_BUTTON_WIDTH;
1498 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1499 s.x += FRAME_BUTTON_WIDTH;
1500 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1501 s.x += FRAME_BUTTON_WIDTH;
1502 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1503 s.x += FRAME_BUTTON_WIDTH;
1504 }
1505
1506 return s;
1507 }
1508
1509 wxSize wxStdRenderer::GetFrameIconSize() const
1510 {
1511 return wxSize(16, 16);
1512 }