]> git.saurik.com Git - wxWidgets.git/blob - src/univ/stdrend.cpp
allow using wxBG_STYLE_CUSTOM even with the native controls and use it in wxTreeCtrl...
[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;
171
172 if (col.Ok())
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(_T("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(_T("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.Ok())
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.Ok())
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 _T("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
896 rectIn.Deflate(GetStatusBarFieldMargins());
897
898 wxDCClipper clipper(dc, rectIn);
899 DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
900 }
901
902 #endif // wxUSE_STATUSBAR
903
904 // ----------------------------------------------------------------------------
905 // top level windows
906 // ----------------------------------------------------------------------------
907
908 int wxStdRenderer::HitTestFrame(const wxRect& rect, const wxPoint& pt, int flags) const
909 {
910 wxRect client = GetFrameClientArea(rect, flags);
911
912 if ( client.Contains(pt) )
913 return wxHT_TOPLEVEL_CLIENT_AREA;
914
915 if ( flags & wxTOPLEVEL_TITLEBAR )
916 {
917 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
918
919 if ( flags & wxTOPLEVEL_ICON )
920 {
921 if ( wxRect(client.GetPosition(), GetFrameIconSize()).Contains(pt) )
922 return wxHT_TOPLEVEL_ICON;
923 }
924
925 wxRect btnRect(client.GetRight() - 2 - FRAME_BUTTON_WIDTH,
926 client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2,
927 FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
928
929 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
930 {
931 if ( btnRect.Contains(pt) )
932 return wxHT_TOPLEVEL_BUTTON_CLOSE;
933 btnRect.x -= FRAME_BUTTON_WIDTH + 2;
934 }
935 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
936 {
937 if ( btnRect.Contains(pt) )
938 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE;
939 btnRect.x -= FRAME_BUTTON_WIDTH;
940 }
941 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
942 {
943 if ( btnRect.Contains(pt) )
944 return wxHT_TOPLEVEL_BUTTON_RESTORE;
945 btnRect.x -= FRAME_BUTTON_WIDTH;
946 }
947 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
948 {
949 if ( btnRect.Contains(pt) )
950 return wxHT_TOPLEVEL_BUTTON_ICONIZE;
951 btnRect.x -= FRAME_BUTTON_WIDTH;
952 }
953 if ( flags & wxTOPLEVEL_BUTTON_HELP )
954 {
955 if ( btnRect.Contains(pt) )
956 return wxHT_TOPLEVEL_BUTTON_HELP;
957 btnRect.x -= FRAME_BUTTON_WIDTH;
958 }
959
960 if ( pt.y >= client.y && pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
961 return wxHT_TOPLEVEL_TITLEBAR;
962 }
963
964 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
965 {
966 // we are certainly at one of borders, let's decide which one:
967
968 int border = 0;
969 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
970 if ( pt.x < client.x )
971 border |= wxHT_TOPLEVEL_BORDER_W;
972 else if ( pt.x >= client.width + client.x )
973 border |= wxHT_TOPLEVEL_BORDER_E;
974 if ( pt.y < client.y )
975 border |= wxHT_TOPLEVEL_BORDER_N;
976 else if ( pt.y >= client.height + client.y )
977 border |= wxHT_TOPLEVEL_BORDER_S;
978 return border;
979 }
980
981 return wxHT_NOWHERE;
982 }
983
984 void wxStdRenderer::DrawFrameTitleBar(wxDC& dc,
985 const wxRect& rect,
986 const wxString& title,
987 const wxIcon& icon,
988 int flags,
989 int specialButton,
990 int specialButtonFlags)
991 {
992 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
993 {
994 DrawFrameBorder(dc, rect, flags);
995 }
996 if ( flags & wxTOPLEVEL_TITLEBAR )
997 {
998 DrawFrameBackground(dc, rect, flags);
999 if ( flags & wxTOPLEVEL_ICON )
1000 DrawFrameIcon(dc, rect, icon, flags);
1001 DrawFrameTitle(dc, rect, title, flags);
1002
1003 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1004 wxCoord x,y;
1005 x = client.GetRight() - 2 - FRAME_BUTTON_WIDTH;
1006 y = client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2;
1007
1008 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1009 {
1010 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_CLOSE,
1011 (specialButton == wxTOPLEVEL_BUTTON_CLOSE) ?
1012 specialButtonFlags : 0);
1013 x -= FRAME_BUTTON_WIDTH + 2;
1014 }
1015 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1016 {
1017 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_MAXIMIZE,
1018 (specialButton == wxTOPLEVEL_BUTTON_MAXIMIZE) ?
1019 specialButtonFlags : 0);
1020 x -= FRAME_BUTTON_WIDTH;
1021 }
1022 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1023 {
1024 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_RESTORE,
1025 (specialButton == wxTOPLEVEL_BUTTON_RESTORE) ?
1026 specialButtonFlags : 0);
1027 x -= FRAME_BUTTON_WIDTH;
1028 }
1029 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1030 {
1031 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_ICONIZE,
1032 (specialButton == wxTOPLEVEL_BUTTON_ICONIZE) ?
1033 specialButtonFlags : 0);
1034 x -= FRAME_BUTTON_WIDTH;
1035 }
1036 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1037 {
1038 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_HELP,
1039 (specialButton == wxTOPLEVEL_BUTTON_HELP) ?
1040 specialButtonFlags : 0);
1041 }
1042 }
1043 }
1044
1045 void wxStdRenderer::DrawFrameBorder(wxDC& dc, const wxRect& rect, int flags)
1046 {
1047 if ( !(flags & wxTOPLEVEL_BORDER) )
1048 return;
1049
1050 wxRect r(rect);
1051
1052 DrawAntiSunkenBorder(dc, &r);
1053 DrawExtraBorder(dc, &r);
1054 if ( flags & wxTOPLEVEL_RESIZEABLE )
1055 DrawExtraBorder(dc, &r);
1056 }
1057
1058 void wxStdRenderer::DrawFrameBackground(wxDC& dc, const wxRect& rect, int flags)
1059 {
1060 if ( !(flags & wxTOPLEVEL_TITLEBAR) )
1061 return;
1062
1063 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1064 ? wxColourScheme::TITLEBAR_ACTIVE
1065 : wxColourScheme::TITLEBAR);
1066
1067 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1068 r.height = FRAME_TITLEBAR_HEIGHT;
1069
1070 DrawBackground(dc, col, r);
1071 }
1072
1073 void wxStdRenderer::DrawFrameTitle(wxDC& dc,
1074 const wxRect& rect,
1075 const wxString& title,
1076 int flags)
1077 {
1078 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1079 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1080 : wxColourScheme::TITLEBAR_TEXT);
1081 dc.SetTextForeground(col);
1082
1083 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1084 r.height = FRAME_TITLEBAR_HEIGHT;
1085 if ( flags & wxTOPLEVEL_ICON )
1086 {
1087 r.x += FRAME_TITLEBAR_HEIGHT;
1088 r.width -= FRAME_TITLEBAR_HEIGHT + 2;
1089 }
1090 else
1091 {
1092 r.x += 1;
1093 r.width -= 3;
1094 }
1095
1096 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1097 r.width -= FRAME_BUTTON_WIDTH + 2;
1098 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1099 r.width -= FRAME_BUTTON_WIDTH;
1100 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1101 r.width -= FRAME_BUTTON_WIDTH;
1102 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1103 r.width -= FRAME_BUTTON_WIDTH;
1104 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1105 r.width -= FRAME_BUTTON_WIDTH;
1106
1107 dc.SetFont(m_titlebarFont);
1108
1109 wxString s;
1110 wxCoord textW;
1111 dc.GetTextExtent(title, &textW, NULL);
1112 if ( textW > r.width )
1113 {
1114 // text is too big, let's shorten it and add "..." after it:
1115 size_t len = title.length();
1116 wxCoord WSoFar, letterW;
1117
1118 dc.GetTextExtent(wxT("..."), &WSoFar, NULL);
1119 if ( WSoFar > r.width )
1120 {
1121 // not enough space to draw anything
1122 return;
1123 }
1124
1125 s.Alloc(len);
1126 for (size_t i = 0; i < len; i++)
1127 {
1128 dc.GetTextExtent(title[i], &letterW, NULL);
1129 if ( letterW + WSoFar > r.width )
1130 break;
1131 WSoFar += letterW;
1132 s << title[i];
1133 }
1134 s << wxT("...");
1135 }
1136 else // no need to truncate the title
1137 {
1138 s = title;
1139 }
1140
1141 dc.DrawLabel(s, wxNullBitmap, r, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1142 }
1143
1144 void wxStdRenderer::DrawFrameIcon(wxDC& dc,
1145 const wxRect& rect,
1146 const wxIcon& icon,
1147 int flags)
1148 {
1149 if ( icon.Ok() )
1150 {
1151 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1152 dc.DrawIcon(icon, r.x, r.y);
1153 }
1154 }
1155
1156 void wxStdRenderer::DrawFrameButton(wxDC& dc,
1157 wxCoord x, wxCoord y,
1158 int button,
1159 int flags)
1160 {
1161 FrameButtonType idx;
1162 switch (button)
1163 {
1164 case wxTOPLEVEL_BUTTON_CLOSE: idx = FrameButton_Close; break;
1165 case wxTOPLEVEL_BUTTON_MAXIMIZE: idx = FrameButton_Maximize; break;
1166 case wxTOPLEVEL_BUTTON_ICONIZE: idx = FrameButton_Minimize; break;
1167 case wxTOPLEVEL_BUTTON_RESTORE: idx = FrameButton_Restore; break;
1168 case wxTOPLEVEL_BUTTON_HELP: idx = FrameButton_Help; break;
1169 default:
1170 wxFAIL_MSG(wxT("incorrect button specification"));
1171 return;
1172 }
1173
1174 wxBitmap bmp = GetFrameButtonBitmap(idx);
1175 if ( !bmp.Ok() )
1176 return;
1177
1178 wxRect rectBtn(x, y, FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
1179 if ( flags & wxCONTROL_PRESSED )
1180 {
1181 DrawSunkenBorder(dc, &rectBtn);
1182
1183 rectBtn.Offset(1, 1);
1184 }
1185 else
1186 {
1187 DrawRaisedBorder(dc, &rectBtn);
1188 }
1189
1190 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rectBtn);
1191
1192 wxRect rectBmp(0, 0, bmp.GetWidth(), bmp.GetHeight());
1193 dc.DrawBitmap(bmp, rectBmp.CentreIn(rectBtn).GetPosition(), true);
1194 }
1195
1196 int wxStdRenderer::GetFrameBorderWidth(int flags) const
1197 {
1198 return flags & wxTOPLEVEL_RESIZEABLE ? 4 : 3;
1199 }
1200
1201
1202 wxRect wxStdRenderer::GetFrameClientArea(const wxRect& rect, int flags) const
1203 {
1204 wxRect r(rect);
1205
1206 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1207 {
1208 r.Inflate(-GetFrameBorderWidth(flags));
1209 }
1210
1211 if ( flags & wxTOPLEVEL_TITLEBAR )
1212 {
1213 r.y += FRAME_TITLEBAR_HEIGHT;
1214 r.height -= FRAME_TITLEBAR_HEIGHT;
1215 }
1216
1217 return r;
1218 }
1219
1220 wxSize
1221 wxStdRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) const
1222 {
1223 wxSize s(clientSize);
1224
1225 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1226 {
1227 s.IncBy(2*GetFrameBorderWidth(flags));
1228 }
1229
1230 if ( flags & wxTOPLEVEL_TITLEBAR )
1231 s.y += FRAME_TITLEBAR_HEIGHT;
1232
1233 return s;
1234 }
1235
1236 wxSize wxStdRenderer::GetFrameMinSize(int flags) const
1237 {
1238 wxSize s;
1239
1240 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1241 {
1242 s.IncBy(2*GetFrameBorderWidth(flags));
1243 }
1244
1245 if ( flags & wxTOPLEVEL_TITLEBAR )
1246 {
1247 s.y += FRAME_TITLEBAR_HEIGHT;
1248
1249 if ( flags & wxTOPLEVEL_ICON )
1250 s.x += FRAME_TITLEBAR_HEIGHT + 2;
1251 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1252 s.x += FRAME_BUTTON_WIDTH + 2;
1253 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1254 s.x += FRAME_BUTTON_WIDTH;
1255 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1256 s.x += FRAME_BUTTON_WIDTH;
1257 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1258 s.x += FRAME_BUTTON_WIDTH;
1259 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1260 s.x += FRAME_BUTTON_WIDTH;
1261 }
1262
1263 return s;
1264 }
1265
1266 wxSize wxStdRenderer::GetFrameIconSize() const
1267 {
1268 return wxSize(16, 16);
1269 }