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