moved wxScrollBar geometry methods out of wxRenderer, they are common for all themes
[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(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 wxRect rectLabel = rect;
261 if ( !label.empty() && (flags & wxCONTROL_DISABLED) )
262 {
263 if ( flags & wxCONTROL_PRESSED )
264 {
265 // shift the label if a button is pressed
266 rectLabel.Offset(1, 1);
267 }
268
269 // draw shadow of the text
270 dc.SetTextForeground(m_penHighlight.GetColour());
271 wxRect rectShadow = rect;
272 rectShadow.Offset(1, 1);
273 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
274
275 // make the main label text grey
276 dc.SetTextForeground(m_penDarkGrey.GetColour());
277
278 if ( flags & wxCONTROL_FOCUSED )
279 {
280 // leave enough space for the focus rect
281 rectLabel.Inflate(-2);
282 }
283 }
284
285 dc.DrawLabel(label, image, rectLabel, alignment, indexAccel, rectBounds);
286
287 if ( !label.empty() && (flags & wxCONTROL_FOCUSED) )
288 {
289 rectLabel.Inflate(-1);
290
291 DrawFocusRect(dc, rectLabel);
292 }
293 }
294
295 // ----------------------------------------------------------------------------
296 // borders
297 // ----------------------------------------------------------------------------
298
299 /*
300 We implement standard-looking 3D borders which have the following appearance:
301
302 The raised border:
303
304 WWWWWWWWWWWWWWWWWWWWWWB
305 WHHHHHHHHHHHHHHHHHHHHGB
306 WH GB W = white (HILIGHT)
307 WH GB H = light grey (LIGHT)
308 WH GB G = dark grey (SHADOI)
309 WH GB B = black (DKSHADOI)
310 WH GB
311 WH GB
312 WGGGGGGGGGGGGGGGGGGGGGB
313 BBBBBBBBBBBBBBBBBBBBBBB
314
315 The sunken border looks like this:
316
317 GGGGGGGGGGGGGGGGGGGGGGW
318 GBBBBBBBBBBBBBBBBBBBBHW
319 GB HW
320 GB HW
321 GB HW
322 GB HW
323 GB HW
324 GB HW
325 GHHHHHHHHHHHHHHHHHHHHHW
326 WWWWWWWWWWWWWWWWWWWWWWW
327
328 The static border (used for the controls which don't get focus) is like
329 this:
330
331 GGGGGGGGGGGGGGGGGGGGGGW
332 G W
333 G W
334 G W
335 G W
336 G W
337 G W
338 G W
339 WWWWWWWWWWWWWWWWWWWWWWW
340
341 The most complicated is the double border which is a combination of special
342 "anti-sunken" border and an extra border inside it:
343
344 HHHHHHHHHHHHHHHHHHHHHHB
345 HWWWWWWWWWWWWWWWWWWWWGB
346 HWHHHHHHHHHHHHHHHHHHHGB
347 HWH HGB
348 HWH HGB
349 HWH HGB
350 HWH HGB
351 HWHHHHHHHHHHHHHHHHHHHGB
352 HGGGGGGGGGGGGGGGGGGGGGB
353 BBBBBBBBBBBBBBBBBBBBBBB
354
355 And the simple border is, well, simple:
356
357 BBBBBBBBBBBBBBBBBBBBBBB
358 B B
359 B B
360 B B
361 B B
362 B B
363 B B
364 B B
365 B B
366 BBBBBBBBBBBBBBBBBBBBBBB
367 */
368
369 void wxStdRenderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
370 {
371 DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
372 DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
373 }
374
375 void wxStdRenderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
376 {
377 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
378 DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
379 }
380
381 void wxStdRenderer::DrawAntiSunkenBorder(wxDC& dc, wxRect *rect)
382 {
383 DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
384 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
385 }
386
387 void wxStdRenderer::DrawBoxBorder(wxDC& dc, wxRect *rect)
388 {
389 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
390 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
391 }
392
393 void wxStdRenderer::DrawStaticBorder(wxDC& dc, wxRect *rect)
394 {
395 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
396 }
397
398 void wxStdRenderer::DrawExtraBorder(wxDC& dc, wxRect *rect)
399 {
400 DrawRect(dc, rect, m_penLightGrey);
401 }
402
403 void wxStdRenderer::DrawBorder(wxDC& dc,
404 wxBorder border,
405 const wxRect& rectTotal,
406 int WXUNUSED(flags),
407 wxRect *rectIn)
408 {
409 wxRect rect = rectTotal;
410
411 switch ( border )
412 {
413 case wxBORDER_SUNKEN:
414 DrawSunkenBorder(dc, &rect);
415 break;
416
417 case wxBORDER_DOUBLE:
418 DrawAntiSunkenBorder(dc, &rect);
419 DrawExtraBorder(dc, &rect);
420 break;
421
422 case wxBORDER_STATIC:
423 DrawStaticBorder(dc, &rect);
424 break;
425
426 case wxBORDER_RAISED:
427 DrawRaisedBorder(dc, &rect);
428 break;
429
430 case wxBORDER_SIMPLE:
431 DrawRect(dc, &rect, m_penBlack);
432 break;
433
434 default:
435 wxFAIL_MSG(_T("unknown border type"));
436 // fall through
437
438 case wxBORDER_DEFAULT:
439 case wxBORDER_NONE:
440 break;
441 }
442
443 if ( rectIn )
444 *rectIn = rect;
445 }
446
447 wxRect wxStdRenderer::GetBorderDimensions(wxBorder border) const
448 {
449 wxCoord width;
450 switch ( border )
451 {
452 case wxBORDER_SIMPLE:
453 case wxBORDER_STATIC:
454 width = 1;
455 break;
456
457 case wxBORDER_RAISED:
458 case wxBORDER_SUNKEN:
459 width = 2;
460 break;
461
462 case wxBORDER_DOUBLE:
463 width = 3;
464 break;
465
466 default:
467 wxFAIL_MSG(_T("unknown border type"));
468 // fall through
469
470 case wxBORDER_DEFAULT:
471 case wxBORDER_NONE:
472 width = 0;
473 break;
474 }
475
476 wxRect rect;
477 rect.x =
478 rect.y =
479 rect.width =
480 rect.height = width;
481
482 return rect;
483 }
484
485 void wxStdRenderer::AdjustSize(wxSize *size, const wxWindow *window)
486 {
487 // take into account the border width
488 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
489 size->x += rectBorder.x + rectBorder.width;
490 size->y += rectBorder.y + rectBorder.height;
491 }
492
493 bool wxStdRenderer::AreScrollbarsInsideBorder() const
494 {
495 return false;
496 }
497
498 wxCoord wxStdRenderer::GetListboxItemHeight(wxCoord fontHeight)
499 {
500 return fontHeight + 2*ITEM_MARGIN;
501 }
502
503 void wxStdRenderer::DrawTextBorder(wxDC& dc,
504 wxBorder border,
505 const wxRect& rect,
506 int flags,
507 wxRect *rectIn)
508 {
509 DrawBorder(dc, border, rect, flags, rectIn);
510 }
511
512 // ----------------------------------------------------------------------------
513 // lines and boxes
514 // ----------------------------------------------------------------------------
515
516 void
517 wxStdRenderer::DrawHorizontalLine(wxDC& dc, wxCoord y, wxCoord x1, wxCoord x2)
518 {
519 dc.SetPen(m_penDarkGrey);
520 dc.DrawLine(x1, y, x2 + 1, y);
521
522 dc.SetPen(m_penHighlight);
523 y++;
524 dc.DrawLine(x1, y, x2 + 1, y);
525 }
526
527 void
528 wxStdRenderer::DrawVerticalLine(wxDC& dc, wxCoord x, wxCoord y1, wxCoord y2)
529 {
530 dc.SetPen(m_penDarkGrey);
531 dc.DrawLine(x, y1, x, y2 + 1);
532
533 dc.SetPen(m_penHighlight);
534 x++;
535 dc.DrawLine(x, y1, x, y2 + 1);
536 }
537
538 void wxStdRenderer::DrawFrameWithoutLabel(wxDC& dc,
539 const wxRect& rectFrame,
540 const wxRect& rectLabel)
541 {
542 // draw left, bottom and right lines entirely
543 DrawVerticalLine(dc, rectFrame.GetLeft(),
544 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
545 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
546 rectFrame.GetLeft(), rectFrame.GetRight());
547 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
548 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
549
550 // and 2 parts of the top line
551 DrawHorizontalLine(dc, rectFrame.GetTop(),
552 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
553 DrawHorizontalLine(dc, rectFrame.GetTop(),
554 rectLabel.GetRight(), rectFrame.GetRight() - 2);
555 }
556
557 void wxStdRenderer::DrawFrameWithLabel(wxDC& dc,
558 const wxString& label,
559 const wxRect& rectFrame,
560 const wxRect& rectText,
561 int flags,
562 int alignment,
563 int indexAccel)
564 {
565 wxRect rectLabel;
566 DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
567
568 DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
569 }
570
571 void wxStdRenderer::DrawFrame(wxDC& dc,
572 const wxString& label,
573 const wxRect& rect,
574 int flags,
575 int alignment,
576 int indexAccel)
577 {
578 wxCoord height = 0; // of the label
579 wxRect rectFrame = rect;
580 if ( !label.empty() )
581 {
582 // the text should touch the top border of the rect, so the frame
583 // itself should be lower
584 dc.GetTextExtent(label, NULL, &height);
585 rectFrame.y += height / 2;
586 rectFrame.height -= height / 2;
587
588 // we have to draw each part of the frame individually as we can't
589 // erase the background beyond the label as it might contain some
590 // pixmap already, so drawing everything and then overwriting part of
591 // the frame with label doesn't work
592
593 // TODO: the +5 shouldn't be hard coded
594 wxRect rectText;
595 rectText.x = rectFrame.x + 5;
596 rectText.y = rect.y;
597 rectText.width = rectFrame.width - 7; // +2 border width
598 rectText.height = height;
599
600 DrawFrameWithLabel(dc, label, rectFrame, rectText, flags,
601 alignment, indexAccel);
602 }
603 else // no label
604 {
605 DrawBoxBorder(dc, &rectFrame);
606 }
607 }
608
609 void wxStdRenderer::DrawItem(wxDC& dc,
610 const wxString& label,
611 const wxRect& rect,
612 int flags)
613 {
614 wxDCTextColourChanger colChanger(dc);
615
616 if ( flags & wxCONTROL_SELECTED )
617 {
618 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
619
620 const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
621 dc.SetBrush(colBg);
622 dc.SetPen(colBg);
623 dc.DrawRectangle(rect);
624 }
625
626 // horizontal adjustment is arbitrary
627 wxRect rectText = rect;
628 rectText.Deflate(2, ITEM_MARGIN);
629 dc.DrawLabel(label, wxNullBitmap, rectText);
630
631 if ( flags & wxCONTROL_FOCUSED )
632 {
633 DrawFocusRect(dc, rect, flags);
634 }
635 }
636
637 void wxStdRenderer::DrawCheckItemBitmap(wxDC& dc,
638 const wxBitmap& bitmap,
639 const wxRect& rect,
640 int flags)
641 {
642 DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags);
643 }
644
645 void wxStdRenderer::DrawCheckItem(wxDC& dc,
646 const wxString& label,
647 const wxBitmap& bitmap,
648 const wxRect& rect,
649 int flags)
650 {
651 wxRect rectBitmap = rect;
652 rectBitmap.width = GetCheckBitmapSize().x;
653 DrawCheckItemBitmap(dc, bitmap, rectBitmap, flags);
654
655 wxRect rectLabel = rect;
656 wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin();
657 rectLabel.x += shift;
658 rectLabel.width -= shift;
659 DrawItem(dc, label, rectLabel, flags);
660 }
661
662 // ----------------------------------------------------------------------------
663 // check and radio bitmaps
664 // ----------------------------------------------------------------------------
665
666 void wxStdRenderer::DrawCheckButton(wxDC& dc,
667 const wxString& label,
668 const wxBitmap& bitmap,
669 const wxRect& rect,
670 int flags,
671 wxAlignment align,
672 int indexAccel)
673 {
674 wxBitmap bmp(bitmap.Ok() ? bitmap : GetCheckBitmap(flags));
675
676 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
677 }
678
679 void wxStdRenderer::DrawRadioButton(wxDC& dc,
680 const wxString& label,
681 const wxBitmap& bitmap,
682 const wxRect& rect,
683 int flags,
684 wxAlignment align,
685 int indexAccel)
686 {
687 wxBitmap bmp(bitmap.Ok() ? bitmap : GetRadioBitmap(flags));
688
689 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
690 }
691
692 void wxStdRenderer::DrawCheckOrRadioButton(wxDC& dc,
693 const wxString& label,
694 const wxBitmap& bitmap,
695 const wxRect& rect,
696 int flags,
697 wxAlignment align,
698 int indexAccel)
699 {
700 // calculate the position of the bitmap and of the label
701 wxCoord heightBmp = bitmap.GetHeight();
702 wxCoord xBmp,
703 yBmp = rect.y + (rect.height - heightBmp) / 2;
704
705 wxRect rectLabel;
706 dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
707 rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
708
709 // align label vertically with the bitmap - looks nicer like this
710 rectLabel.y -= (rectLabel.height - heightBmp) % 2;
711
712 // calc horz position
713 if ( align == wxALIGN_RIGHT )
714 {
715 xBmp = rect.GetRight() - bitmap.GetWidth();
716 rectLabel.x = rect.x + 3;
717 rectLabel.SetRight(xBmp);
718 }
719 else // normal (checkbox to the left of the text) case
720 {
721 xBmp = rect.x;
722 rectLabel.x = xBmp + bitmap.GetWidth() + 5;
723 rectLabel.SetRight(rect.GetRight());
724 }
725
726 dc.DrawBitmap(bitmap, xBmp, yBmp, true /* use mask */);
727
728 DrawLabel(dc, label, rectLabel, flags,
729 wxALIGN_LEFT | wxALIGN_TOP, indexAccel);
730 }
731
732 #if wxUSE_TEXTCTRL
733
734 void wxStdRenderer::DrawTextLine(wxDC& dc,
735 const wxString& text,
736 const wxRect& rect,
737 int selStart,
738 int selEnd,
739 int flags)
740 {
741 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
742 {
743 // just draw it as is
744 dc.DrawText(text, rect.x, rect.y);
745 }
746 else // we have selection
747 {
748 wxCoord width,
749 x = rect.x;
750
751 // draw the part before selection
752 wxString s(text, (size_t)selStart);
753 if ( !s.empty() )
754 {
755 dc.DrawText(s, x, rect.y);
756
757 dc.GetTextExtent(s, &width, NULL);
758 x += width;
759 }
760
761 // draw the selection itself
762 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
763 if ( !s.empty() )
764 {
765 wxColour colFg = dc.GetTextForeground(),
766 colBg = dc.GetTextBackground();
767 dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
768 dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT));
769 dc.SetBackgroundMode(wxSOLID);
770
771 dc.DrawText(s, x, rect.y);
772 dc.GetTextExtent(s, &width, NULL);
773 x += width;
774
775 dc.SetBackgroundMode(wxTRANSPARENT);
776 dc.SetTextBackground(colBg);
777 dc.SetTextForeground(colFg);
778 }
779
780 // draw the final part
781 s = text.c_str() + selEnd;
782 if ( !s.empty() )
783 {
784 dc.DrawText(s, x, rect.y);
785 }
786 }
787 }
788
789 void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
790 const wxRect& WXUNUSED(rect))
791 {
792 // nothing by default
793 }
794
795 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
796 {
797 return 1;
798 }
799
800 wxRect
801 wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
802 {
803 wxRect rectTotal = rect;
804 rectTotal.Inflate(GetTextBorderWidth(text));
805 return rectTotal;
806 }
807
808 wxRect wxStdRenderer::GetTextClientArea(const wxTextCtrl *text,
809 const wxRect& rect,
810 wxCoord *extraSpaceBeyond) const
811 {
812 wxRect rectText = rect;
813 rectText.Deflate(GetTextBorderWidth(text));
814
815 if ( extraSpaceBeyond )
816 *extraSpaceBeyond = 0;
817
818 return rectText;
819 }
820
821 #endif // wxUSE_TEXTCTRL
822
823 // ----------------------------------------------------------------------------
824 // scrollbars drawing
825 // ----------------------------------------------------------------------------
826
827 void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
828 wxDirection dir,
829 const wxRect& rect,
830 int flags)
831 {
832 DrawArrow(dc, dir, rect, flags);
833 }
834
835 void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
836 {
837 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
838 }
839
840 // ----------------------------------------------------------------------------
841 // status bar
842 // ----------------------------------------------------------------------------
843
844 #if wxUSE_STATUSBAR
845
846 wxSize wxStdRenderer::GetStatusBarBorders() const
847 {
848 // Rendered border may be different depending on field's style, we use
849 // the largest value so that any field certainly fits into the borders
850 // we return:
851 wxRect raised = GetBorderDimensions(wxBORDER_RAISED);
852 wxRect flat = GetBorderDimensions(wxBORDER_STATIC);
853 wxASSERT_MSG( raised.x == raised.width && raised.y == raised.height &&
854 flat.x == flat.width && flat.y == flat.height,
855 _T("this code expects uniform borders, you must override GetStatusBarBorders") );
856
857 // take the larger of flat/raised values:
858 wxSize border(wxMax(raised.x, flat.x), wxMax(raised.y, flat.y));
859
860 return border;
861 }
862
863 wxCoord wxStdRenderer::GetStatusBarBorderBetweenFields() const
864 {
865 return 2;
866 }
867
868 wxSize wxStdRenderer::GetStatusBarFieldMargins() const
869 {
870 return wxSize(2, 2);
871 }
872
873 void wxStdRenderer::DrawStatusField(wxDC& dc,
874 const wxRect& rect,
875 const wxString& label,
876 int flags,
877 int style)
878 {
879 wxRect rectIn;
880
881 if ( style == wxSB_RAISED )
882 DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
883 else if ( style != wxSB_FLAT )
884 DrawBorder(dc, wxBORDER_STATIC, rect, flags, &rectIn);
885
886 rectIn.Deflate(GetStatusBarFieldMargins());
887
888 wxDCClipper clipper(dc, rectIn);
889 DrawLabel(dc, label, rectIn, flags, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
890 }
891
892 #endif // wxUSE_STATUSBAR
893
894 // ----------------------------------------------------------------------------
895 // top level windows
896 // ----------------------------------------------------------------------------
897
898 int wxStdRenderer::HitTestFrame(const wxRect& rect, const wxPoint& pt, int flags) const
899 {
900 wxRect client = GetFrameClientArea(rect, flags);
901
902 if ( client.Contains(pt) )
903 return wxHT_TOPLEVEL_CLIENT_AREA;
904
905 if ( flags & wxTOPLEVEL_TITLEBAR )
906 {
907 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
908
909 if ( flags & wxTOPLEVEL_ICON )
910 {
911 if ( wxRect(client.GetPosition(), GetFrameIconSize()).Contains(pt) )
912 return wxHT_TOPLEVEL_ICON;
913 }
914
915 wxRect btnRect(client.GetRight() - 2 - FRAME_BUTTON_WIDTH,
916 client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2,
917 FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
918
919 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
920 {
921 if ( btnRect.Contains(pt) )
922 return wxHT_TOPLEVEL_BUTTON_CLOSE;
923 btnRect.x -= FRAME_BUTTON_WIDTH + 2;
924 }
925 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
926 {
927 if ( btnRect.Contains(pt) )
928 return wxHT_TOPLEVEL_BUTTON_MAXIMIZE;
929 btnRect.x -= FRAME_BUTTON_WIDTH;
930 }
931 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
932 {
933 if ( btnRect.Contains(pt) )
934 return wxHT_TOPLEVEL_BUTTON_RESTORE;
935 btnRect.x -= FRAME_BUTTON_WIDTH;
936 }
937 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
938 {
939 if ( btnRect.Contains(pt) )
940 return wxHT_TOPLEVEL_BUTTON_ICONIZE;
941 btnRect.x -= FRAME_BUTTON_WIDTH;
942 }
943 if ( flags & wxTOPLEVEL_BUTTON_HELP )
944 {
945 if ( btnRect.Contains(pt) )
946 return wxHT_TOPLEVEL_BUTTON_HELP;
947 btnRect.x -= FRAME_BUTTON_WIDTH;
948 }
949
950 if ( pt.y >= client.y && pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
951 return wxHT_TOPLEVEL_TITLEBAR;
952 }
953
954 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
955 {
956 // we are certainly at one of borders, let's decide which one:
957
958 int border = 0;
959 // dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
960 if ( pt.x < client.x )
961 border |= wxHT_TOPLEVEL_BORDER_W;
962 else if ( pt.x >= client.width + client.x )
963 border |= wxHT_TOPLEVEL_BORDER_E;
964 if ( pt.y < client.y )
965 border |= wxHT_TOPLEVEL_BORDER_N;
966 else if ( pt.y >= client.height + client.y )
967 border |= wxHT_TOPLEVEL_BORDER_S;
968 return border;
969 }
970
971 return wxHT_NOWHERE;
972 }
973
974 void wxStdRenderer::DrawFrameTitleBar(wxDC& dc,
975 const wxRect& rect,
976 const wxString& title,
977 const wxIcon& icon,
978 int flags,
979 int specialButton,
980 int specialButtonFlags)
981 {
982 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
983 {
984 DrawFrameBorder(dc, rect, flags);
985 }
986 if ( flags & wxTOPLEVEL_TITLEBAR )
987 {
988 DrawFrameBackground(dc, rect, flags);
989 if ( flags & wxTOPLEVEL_ICON )
990 DrawFrameIcon(dc, rect, icon, flags);
991 DrawFrameTitle(dc, rect, title, flags);
992
993 wxRect client = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
994 wxCoord x,y;
995 x = client.GetRight() - 2 - FRAME_BUTTON_WIDTH;
996 y = client.GetTop() + (FRAME_TITLEBAR_HEIGHT-FRAME_BUTTON_HEIGHT)/2;
997
998 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
999 {
1000 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_CLOSE,
1001 (specialButton == wxTOPLEVEL_BUTTON_CLOSE) ?
1002 specialButtonFlags : 0);
1003 x -= FRAME_BUTTON_WIDTH + 2;
1004 }
1005 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1006 {
1007 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_MAXIMIZE,
1008 (specialButton == wxTOPLEVEL_BUTTON_MAXIMIZE) ?
1009 specialButtonFlags : 0);
1010 x -= FRAME_BUTTON_WIDTH;
1011 }
1012 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1013 {
1014 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_RESTORE,
1015 (specialButton == wxTOPLEVEL_BUTTON_RESTORE) ?
1016 specialButtonFlags : 0);
1017 x -= FRAME_BUTTON_WIDTH;
1018 }
1019 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1020 {
1021 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_ICONIZE,
1022 (specialButton == wxTOPLEVEL_BUTTON_ICONIZE) ?
1023 specialButtonFlags : 0);
1024 x -= FRAME_BUTTON_WIDTH;
1025 }
1026 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1027 {
1028 DrawFrameButton(dc, x, y, wxTOPLEVEL_BUTTON_HELP,
1029 (specialButton == wxTOPLEVEL_BUTTON_HELP) ?
1030 specialButtonFlags : 0);
1031 }
1032 }
1033 }
1034
1035 void wxStdRenderer::DrawFrameBorder(wxDC& dc, const wxRect& rect, int flags)
1036 {
1037 if ( !(flags & wxTOPLEVEL_BORDER) )
1038 return;
1039
1040 wxRect r(rect);
1041
1042 DrawAntiSunkenBorder(dc, &r);
1043 DrawExtraBorder(dc, &r);
1044 if ( flags & wxTOPLEVEL_RESIZEABLE )
1045 DrawExtraBorder(dc, &r);
1046 }
1047
1048 void wxStdRenderer::DrawFrameBackground(wxDC& dc, const wxRect& rect, int flags)
1049 {
1050 if ( !(flags & wxTOPLEVEL_TITLEBAR) )
1051 return;
1052
1053 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1054 ? wxColourScheme::TITLEBAR_ACTIVE
1055 : wxColourScheme::TITLEBAR);
1056
1057 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1058 r.height = FRAME_TITLEBAR_HEIGHT;
1059
1060 DrawBackground(dc, col, r);
1061 }
1062
1063 void wxStdRenderer::DrawFrameTitle(wxDC& dc,
1064 const wxRect& rect,
1065 const wxString& title,
1066 int flags)
1067 {
1068 wxColour col = m_scheme->Get(flags & wxTOPLEVEL_ACTIVE
1069 ? wxColourScheme::TITLEBAR_ACTIVE_TEXT
1070 : wxColourScheme::TITLEBAR_TEXT);
1071 dc.SetTextForeground(col);
1072
1073 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1074 r.height = FRAME_TITLEBAR_HEIGHT;
1075 if ( flags & wxTOPLEVEL_ICON )
1076 {
1077 r.x += FRAME_TITLEBAR_HEIGHT;
1078 r.width -= FRAME_TITLEBAR_HEIGHT + 2;
1079 }
1080 else
1081 {
1082 r.x += 1;
1083 r.width -= 3;
1084 }
1085
1086 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1087 r.width -= FRAME_BUTTON_WIDTH + 2;
1088 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1089 r.width -= FRAME_BUTTON_WIDTH;
1090 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1091 r.width -= FRAME_BUTTON_WIDTH;
1092 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1093 r.width -= FRAME_BUTTON_WIDTH;
1094 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1095 r.width -= FRAME_BUTTON_WIDTH;
1096
1097 dc.SetFont(m_titlebarFont);
1098
1099 wxString s;
1100 wxCoord textW;
1101 dc.GetTextExtent(title, &textW, NULL);
1102 if ( textW > r.width )
1103 {
1104 // text is too big, let's shorten it and add "..." after it:
1105 size_t len = title.length();
1106 wxCoord WSoFar, letterW;
1107
1108 dc.GetTextExtent(wxT("..."), &WSoFar, NULL);
1109 if ( WSoFar > r.width )
1110 {
1111 // not enough space to draw anything
1112 return;
1113 }
1114
1115 s.Alloc(len);
1116 for (size_t i = 0; i < len; i++)
1117 {
1118 dc.GetTextExtent(title[i], &letterW, NULL);
1119 if ( letterW + WSoFar > r.width )
1120 break;
1121 WSoFar += letterW;
1122 s << title[i];
1123 }
1124 s << wxT("...");
1125 }
1126 else // no need to truncate the title
1127 {
1128 s = title;
1129 }
1130
1131 dc.DrawLabel(s, wxNullBitmap, r, wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL);
1132 }
1133
1134 void wxStdRenderer::DrawFrameIcon(wxDC& dc,
1135 const wxRect& rect,
1136 const wxIcon& icon,
1137 int flags)
1138 {
1139 if ( icon.Ok() )
1140 {
1141 wxRect r = GetFrameClientArea(rect, flags & ~wxTOPLEVEL_TITLEBAR);
1142 dc.DrawIcon(icon, r.x, r.y);
1143 }
1144 }
1145
1146 void wxStdRenderer::DrawFrameButton(wxDC& dc,
1147 wxCoord x, wxCoord y,
1148 int button,
1149 int flags)
1150 {
1151 FrameButtonType idx;
1152 switch (button)
1153 {
1154 case wxTOPLEVEL_BUTTON_CLOSE: idx = FrameButton_Close; break;
1155 case wxTOPLEVEL_BUTTON_MAXIMIZE: idx = FrameButton_Maximize; break;
1156 case wxTOPLEVEL_BUTTON_ICONIZE: idx = FrameButton_Minimize; break;
1157 case wxTOPLEVEL_BUTTON_RESTORE: idx = FrameButton_Restore; break;
1158 case wxTOPLEVEL_BUTTON_HELP: idx = FrameButton_Help; break;
1159 default:
1160 wxFAIL_MSG(wxT("incorrect button specification"));
1161 return;
1162 }
1163
1164 wxBitmap bmp = GetFrameButtonBitmap(idx);
1165 if ( !bmp.Ok() )
1166 return;
1167
1168 wxRect rectBtn(x, y, FRAME_BUTTON_WIDTH, FRAME_BUTTON_HEIGHT);
1169 if ( flags & wxCONTROL_PRESSED )
1170 {
1171 DrawSunkenBorder(dc, &rectBtn);
1172
1173 rectBtn.Offset(1, 1);
1174 }
1175 else
1176 {
1177 DrawRaisedBorder(dc, &rectBtn);
1178 }
1179
1180 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rectBtn);
1181
1182 wxRect rectBmp(0, 0, bmp.GetWidth(), bmp.GetHeight());
1183 dc.DrawBitmap(bmp, rectBmp.CentreIn(rectBtn).GetPosition(), true);
1184 }
1185
1186 int wxStdRenderer::GetFrameBorderWidth(int flags) const
1187 {
1188 return flags & wxTOPLEVEL_RESIZEABLE ? 4 : 3;
1189 }
1190
1191
1192 wxRect wxStdRenderer::GetFrameClientArea(const wxRect& rect, int flags) const
1193 {
1194 wxRect r(rect);
1195
1196 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1197 {
1198 r.Inflate(-GetFrameBorderWidth(flags));
1199 }
1200
1201 if ( flags & wxTOPLEVEL_TITLEBAR )
1202 {
1203 r.y += FRAME_TITLEBAR_HEIGHT;
1204 r.height -= FRAME_TITLEBAR_HEIGHT;
1205 }
1206
1207 return r;
1208 }
1209
1210 wxSize
1211 wxStdRenderer::GetFrameTotalSize(const wxSize& clientSize, int flags) const
1212 {
1213 wxSize s(clientSize);
1214
1215 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1216 {
1217 s.IncBy(2*GetFrameBorderWidth(flags));
1218 }
1219
1220 if ( flags & wxTOPLEVEL_TITLEBAR )
1221 s.y += FRAME_TITLEBAR_HEIGHT;
1222
1223 return s;
1224 }
1225
1226 wxSize wxStdRenderer::GetFrameMinSize(int flags) const
1227 {
1228 wxSize s;
1229
1230 if ( (flags & wxTOPLEVEL_BORDER) && !(flags & wxTOPLEVEL_MAXIMIZED) )
1231 {
1232 s.IncBy(2*GetFrameBorderWidth(flags));
1233 }
1234
1235 if ( flags & wxTOPLEVEL_TITLEBAR )
1236 {
1237 s.y += FRAME_TITLEBAR_HEIGHT;
1238
1239 if ( flags & wxTOPLEVEL_ICON )
1240 s.x += FRAME_TITLEBAR_HEIGHT + 2;
1241 if ( flags & wxTOPLEVEL_BUTTON_CLOSE )
1242 s.x += FRAME_BUTTON_WIDTH + 2;
1243 if ( flags & wxTOPLEVEL_BUTTON_MAXIMIZE )
1244 s.x += FRAME_BUTTON_WIDTH;
1245 if ( flags & wxTOPLEVEL_BUTTON_RESTORE )
1246 s.x += FRAME_BUTTON_WIDTH;
1247 if ( flags & wxTOPLEVEL_BUTTON_ICONIZE )
1248 s.x += FRAME_BUTTON_WIDTH;
1249 if ( flags & wxTOPLEVEL_BUTTON_HELP )
1250 s.x += FRAME_BUTTON_WIDTH;
1251 }
1252
1253 return s;
1254 }
1255
1256 wxSize wxStdRenderer::GetFrameIconSize() const
1257 {
1258 return wxSize(16, 16);
1259 }