]> git.saurik.com Git - wxWidgets.git/blob - src/univ/stdrend.cpp
define wxCONTROL_SIZEGRIP as another possible interpretation of wxCONTROL_SPECIAL bit
[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 #endif //WX_PRECOMP
28
29 #include "wx/univ/stdrend.h"
30 #include "wx/univ/colschem.h"
31
32 // ============================================================================
33 // wxStdRenderer implementation
34 // ============================================================================
35
36 // ----------------------------------------------------------------------------
37 // ctor
38 // ----------------------------------------------------------------------------
39
40 wxStdRenderer::wxStdRenderer(const wxColourScheme *scheme)
41 : m_scheme(scheme)
42 {
43 m_penBlack = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_DARK));
44 m_penDarkGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_OUT));
45 m_penLightGrey = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_IN));
46 m_penHighlight = wxPen(wxSCHEME_COLOUR(scheme, SHADOW_HIGHLIGHT));
47 }
48
49 // ----------------------------------------------------------------------------
50 // helper functions
51 // ----------------------------------------------------------------------------
52
53 void
54 wxStdRenderer::DrawSolidRect(wxDC& dc, const wxColour& col, const wxRect& rect)
55 {
56 wxBrush brush(col, wxSOLID);
57 dc.SetBrush(brush);
58 dc.SetPen(*wxTRANSPARENT_PEN);
59 dc.DrawRectangle(rect);
60 }
61
62 void wxStdRenderer::DrawRect(wxDC& dc, wxRect *rect, const wxPen& pen)
63 {
64 // draw
65 dc.SetPen(pen);
66 dc.SetBrush(*wxTRANSPARENT_BRUSH);
67 dc.DrawRectangle(*rect);
68
69 // adjust the rect
70 rect->Inflate(-1);
71 }
72
73 void wxStdRenderer::DrawShadedRect(wxDC& dc, wxRect *rect,
74 const wxPen& pen1, const wxPen& pen2)
75 {
76 // draw the rectangle
77 dc.SetPen(pen1);
78 dc.DrawLine(rect->GetLeft(), rect->GetTop(),
79 rect->GetLeft(), rect->GetBottom());
80 dc.DrawLine(rect->GetLeft() + 1, rect->GetTop(),
81 rect->GetRight(), rect->GetTop());
82 dc.SetPen(pen2);
83 dc.DrawLine(rect->GetRight(), rect->GetTop(),
84 rect->GetRight(), rect->GetBottom());
85 dc.DrawLine(rect->GetLeft(), rect->GetBottom(),
86 rect->GetRight() + 1, rect->GetBottom());
87
88 // adjust the rect
89 rect->Inflate(-1);
90 }
91
92 // ----------------------------------------------------------------------------
93 // translate various flags into corresponding renderer constants
94 // ----------------------------------------------------------------------------
95
96 /* static */
97 void wxStdRenderer::GetIndicatorsFromFlags(int flags,
98 IndicatorState& state,
99 IndicatorStatus& status)
100 {
101 if ( flags & wxCONTROL_SELECTED )
102 state = flags & wxCONTROL_DISABLED ? IndicatorState_SelectedDisabled
103 : IndicatorState_Selected;
104 else if ( flags & wxCONTROL_DISABLED )
105 state = IndicatorState_Disabled;
106 else if ( flags & wxCONTROL_PRESSED )
107 state = IndicatorState_Pressed;
108 else
109 state = IndicatorState_Normal;
110
111 status = flags & wxCONTROL_CHECKED ? IndicatorStatus_Checked
112 : flags & wxCONTROL_UNDETERMINED
113 ? IndicatorStatus_Undetermined
114 : IndicatorStatus_Unchecked;
115 }
116
117 /* static */
118 wxStdRenderer::ArrowDirection wxStdRenderer::GetArrowDirection(wxDirection dir)
119 {
120 switch ( dir )
121 {
122 case wxLEFT:
123 return Arrow_Left;
124
125 case wxRIGHT:
126 return Arrow_Right;
127
128 case wxUP:
129 return Arrow_Up;
130
131 case wxDOWN:
132 return Arrow_Down;
133
134 default:
135 wxFAIL_MSG(_T("unknown arrow direction"));
136 }
137
138 return Arrow_Max;
139 }
140
141 // ----------------------------------------------------------------------------
142 // background
143 // ----------------------------------------------------------------------------
144
145 void wxStdRenderer::DrawBackground(wxDC& dc,
146 const wxColour& col,
147 const wxRect& rect,
148 int WXUNUSED(flags),
149 wxWindow *window)
150 {
151 wxColour colBg = col.Ok() ? col
152 : window ? m_scheme->GetBackground(window)
153 : wxSCHEME_COLOUR(m_scheme, CONTROL);
154
155 DrawSolidRect(dc, colBg, rect);
156 }
157
158
159 void wxStdRenderer::DrawButtonSurface(wxDC& dc,
160 const wxColour& col,
161 const wxRect& rect,
162 int flags)
163 {
164 DrawBackground(dc, col, rect, flags);
165 }
166
167 // ----------------------------------------------------------------------------
168 // text
169 // ----------------------------------------------------------------------------
170
171 void wxStdRenderer::DrawFocusRect(wxDC& dc, const wxRect& rect)
172 {
173 // draw the pixels manually because the "dots" in wxPen with wxDOT style
174 // may be short traits and not really dots
175 //
176 // note that to behave in the same manner as DrawRect(), we must exclude
177 // the bottom and right borders from the rectangle
178 wxCoord x1 = rect.GetLeft(),
179 y1 = rect.GetTop(),
180 x2 = rect.GetRight(),
181 y2 = rect.GetBottom();
182
183 dc.SetPen(m_penBlack);
184
185 // this seems to be closer than what Windows does than wxINVERT although
186 // I'm still not sure if it's correct
187 dc.SetLogicalFunction(wxAND_REVERSE);
188
189 wxCoord z;
190 for ( z = x1 + 1; z < x2; z += 2 )
191 dc.DrawPoint(z, rect.GetTop());
192
193 wxCoord shift = z == x2 ? 0 : 1;
194 for ( z = y1 + shift; z < y2; z += 2 )
195 dc.DrawPoint(x2, z);
196
197 shift = z == y2 ? 0 : 1;
198 for ( z = x2 - shift; z > x1; z -= 2 )
199 dc.DrawPoint(z, y2);
200
201 shift = z == x1 ? 0 : 1;
202 for ( z = y2 - shift; z > y1; z -= 2 )
203 dc.DrawPoint(x1, z);
204
205 dc.SetLogicalFunction(wxCOPY);
206 }
207
208 void wxStdRenderer::DrawLabel(wxDC& dc,
209 const wxString& label,
210 const wxRect& rect,
211 int flags,
212 int alignment,
213 int indexAccel,
214 wxRect *rectBounds)
215 {
216 DrawButtonLabel(dc, label, wxNullBitmap, rect, flags,
217 alignment, indexAccel, rectBounds);
218 }
219
220 void wxStdRenderer::DrawButtonLabel(wxDC& dc,
221 const wxString& label,
222 const wxBitmap& image,
223 const wxRect& rect,
224 int flags,
225 int alignment,
226 int indexAccel,
227 wxRect *rectBounds)
228 {
229 wxRect rectLabel = rect;
230 if ( !label.empty() && (flags & wxCONTROL_DISABLED) )
231 {
232 if ( flags & wxCONTROL_PRESSED )
233 {
234 // shift the label if a button is pressed
235 rectLabel.Offset(1, 1);
236 }
237
238 // draw shadow of the text
239 dc.SetTextForeground(m_penHighlight.GetColour());
240 wxRect rectShadow = rect;
241 rectShadow.Offset(1, 1);
242 dc.DrawLabel(label, rectShadow, alignment, indexAccel);
243
244 // make the main label text grey
245 dc.SetTextForeground(m_penDarkGrey.GetColour());
246
247 if ( flags & wxCONTROL_FOCUSED )
248 {
249 // leave enough space for the focus rect
250 rectLabel.Inflate(-2);
251 }
252 }
253
254 dc.DrawLabel(label, image, rectLabel, alignment, indexAccel, rectBounds);
255
256 if ( !label.empty() && (flags & wxCONTROL_FOCUSED) )
257 {
258 rectLabel.Inflate(-1);
259
260 DrawFocusRect(dc, rectLabel);
261 }
262 }
263
264 // ----------------------------------------------------------------------------
265 // borders
266 // ----------------------------------------------------------------------------
267
268 /*
269 We implement standard-looking 3D borders which have the following appearance:
270
271 The raised border:
272
273 WWWWWWWWWWWWWWWWWWWWWWB
274 WHHHHHHHHHHHHHHHHHHHHGB
275 WH GB W = white (HILIGHT)
276 WH GB H = light grey (LIGHT)
277 WH GB G = dark grey (SHADOI)
278 WH GB B = black (DKSHADOI)
279 WH GB
280 WH GB
281 WGGGGGGGGGGGGGGGGGGGGGB
282 BBBBBBBBBBBBBBBBBBBBBBB
283
284 The sunken border looks like this:
285
286 GGGGGGGGGGGGGGGGGGGGGGW
287 GBBBBBBBBBBBBBBBBBBBBHW
288 GB HW
289 GB HW
290 GB HW
291 GB HW
292 GB HW
293 GB HW
294 GHHHHHHHHHHHHHHHHHHHHHW
295 WWWWWWWWWWWWWWWWWWWWWWW
296
297 The static border (used for the controls which don't get focus) is like
298 this:
299
300 GGGGGGGGGGGGGGGGGGGGGGW
301 G W
302 G W
303 G W
304 G W
305 G W
306 G W
307 G W
308 WWWWWWWWWWWWWWWWWWWWWWW
309
310 The most complicated is the double border which is a combination of special
311 "anti-sunken" border and an extra border inside it:
312
313 HHHHHHHHHHHHHHHHHHHHHHB
314 HWWWWWWWWWWWWWWWWWWWWGB
315 HWHHHHHHHHHHHHHHHHHHHGB
316 HWH HGB
317 HWH HGB
318 HWH HGB
319 HWH HGB
320 HWHHHHHHHHHHHHHHHHHHHGB
321 HGGGGGGGGGGGGGGGGGGGGGB
322 BBBBBBBBBBBBBBBBBBBBBBB
323
324 And the simple border is, well, simple:
325
326 BBBBBBBBBBBBBBBBBBBBBBB
327 B B
328 B B
329 B B
330 B B
331 B B
332 B B
333 B B
334 B B
335 BBBBBBBBBBBBBBBBBBBBBBB
336 */
337
338 void wxStdRenderer::DrawRaisedBorder(wxDC& dc, wxRect *rect)
339 {
340 DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
341 DrawShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
342 }
343
344 void wxStdRenderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
345 {
346 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
347 DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
348 }
349
350 void wxStdRenderer::DrawAntiSunkenBorder(wxDC& dc, wxRect *rect)
351 {
352 DrawShadedRect(dc, rect, m_penLightGrey, m_penBlack);
353 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
354 }
355
356 void wxStdRenderer::DrawFrameBorder(wxDC& dc, wxRect *rect)
357 {
358 DrawShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
359 DrawShadedRect(dc, rect, m_penHighlight, m_penDarkGrey);
360 }
361
362 void wxStdRenderer::DrawBorder(wxDC& dc,
363 wxBorder border,
364 const wxRect& rectTotal,
365 int WXUNUSED(flags),
366 wxRect *rectIn)
367 {
368 wxRect rect = rectTotal;
369
370 switch ( border )
371 {
372 case wxBORDER_SUNKEN:
373 DrawSunkenBorder(dc, &rect);
374 break;
375
376 case wxBORDER_DOUBLE:
377 DrawAntiSunkenBorder(dc, &rect);
378 DrawRect(dc, &rect, m_penLightGrey);
379 break;
380
381 case wxBORDER_STATIC:
382 DrawShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
383 break;
384
385 case wxBORDER_RAISED:
386 DrawRaisedBorder(dc, &rect);
387 break;
388
389 case wxBORDER_SIMPLE:
390 DrawRect(dc, &rect, m_penBlack);
391 break;
392
393 default:
394 wxFAIL_MSG(_T("unknown border type"));
395 // fall through
396
397 case wxBORDER_DEFAULT:
398 case wxBORDER_NONE:
399 break;
400 }
401
402 if ( rectIn )
403 *rectIn = rect;
404 }
405
406 wxRect wxStdRenderer::GetBorderDimensions(wxBorder border) const
407 {
408 wxCoord width;
409 switch ( border )
410 {
411 case wxBORDER_SIMPLE:
412 case wxBORDER_STATIC:
413 width = 1;
414 break;
415
416 case wxBORDER_RAISED:
417 case wxBORDER_SUNKEN:
418 width = 2;
419 break;
420
421 case wxBORDER_DOUBLE:
422 width = 3;
423 break;
424
425 default:
426 wxFAIL_MSG(_T("unknown border type"));
427 // fall through
428
429 case wxBORDER_DEFAULT:
430 case wxBORDER_NONE:
431 width = 0;
432 break;
433 }
434
435 wxRect rect;
436 rect.x =
437 rect.y =
438 rect.width =
439 rect.height = width;
440
441 return rect;
442 }
443
444 bool wxStdRenderer::AreScrollbarsInsideBorder() const
445 {
446 return false;
447 }
448
449 void wxStdRenderer::DrawTextBorder(wxDC& dc,
450 wxBorder border,
451 const wxRect& rect,
452 int flags,
453 wxRect *rectIn)
454 {
455 DrawBorder(dc, border, rect, flags, rectIn);
456 }
457
458 // ----------------------------------------------------------------------------
459 // lines and boxes
460 // ----------------------------------------------------------------------------
461
462 void
463 wxStdRenderer::DrawHorizontalLine(wxDC& dc, wxCoord y, wxCoord x1, wxCoord x2)
464 {
465 dc.SetPen(m_penDarkGrey);
466 dc.DrawLine(x1, y, x2 + 1, y);
467
468 dc.SetPen(m_penHighlight);
469 y++;
470 dc.DrawLine(x1, y, x2 + 1, y);
471 }
472
473 void
474 wxStdRenderer::DrawVerticalLine(wxDC& dc, wxCoord x, wxCoord y1, wxCoord y2)
475 {
476 dc.SetPen(m_penDarkGrey);
477 dc.DrawLine(x, y1, x, y2 + 1);
478
479 dc.SetPen(m_penHighlight);
480 x++;
481 dc.DrawLine(x, y1, x, y2 + 1);
482 }
483
484 void wxStdRenderer::DrawFrameWithoutLabel(wxDC& dc,
485 const wxRect& rectFrame,
486 const wxRect& rectLabel)
487 {
488 // draw left, bottom and right lines entirely
489 DrawVerticalLine(dc, rectFrame.GetLeft(),
490 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
491 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
492 rectFrame.GetLeft(), rectFrame.GetRight());
493 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
494 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
495
496 // and 2 parts of the top line
497 DrawHorizontalLine(dc, rectFrame.GetTop(),
498 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
499 DrawHorizontalLine(dc, rectFrame.GetTop(),
500 rectLabel.GetRight(), rectFrame.GetRight() - 2);
501 }
502
503 void wxStdRenderer::DrawFrameWithLabel(wxDC& dc,
504 const wxString& label,
505 const wxRect& rectFrame,
506 const wxRect& rectText,
507 int flags,
508 int alignment,
509 int indexAccel)
510 {
511 wxRect rectLabel;
512 DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
513
514 DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
515 }
516
517 void wxStdRenderer::DrawFrame(wxDC& dc,
518 const wxString& label,
519 const wxRect& rect,
520 int flags,
521 int alignment,
522 int indexAccel)
523 {
524 wxCoord height = 0; // of the label
525 wxRect rectFrame = rect;
526 if ( !label.empty() )
527 {
528 // the text should touch the top border of the rect, so the frame
529 // itself should be lower
530 dc.GetTextExtent(label, NULL, &height);
531 rectFrame.y += height / 2;
532 rectFrame.height -= height / 2;
533
534 // we have to draw each part of the frame individually as we can't
535 // erase the background beyond the label as it might contain some
536 // pixmap already, so drawing everything and then overwriting part of
537 // the frame with label doesn't work
538
539 // TODO: the +5 shouldn't be hard coded
540 wxRect rectText;
541 rectText.x = rectFrame.x + 5;
542 rectText.y = rect.y;
543 rectText.width = rectFrame.width - 7; // +2 border width
544 rectText.height = height;
545
546 DrawFrameWithLabel(dc, label, rectFrame, rectText, flags,
547 alignment, indexAccel);
548 }
549 else // no label
550 {
551 DrawFrameBorder(dc, &rectFrame);
552 }
553 }
554
555 void wxStdRenderer::DrawItem(wxDC& dc,
556 const wxString& label,
557 const wxRect& rect,
558 int flags)
559 {
560 wxDCTextColourChanger colChanger(dc);
561
562 if ( flags & wxCONTROL_SELECTED )
563 {
564 colChanger.Set(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
565
566 const wxColour colBg = wxSCHEME_COLOUR(m_scheme, HIGHLIGHT);
567 dc.SetBrush(colBg);
568 dc.SetPen(colBg);
569 dc.DrawRectangle(rect);
570 }
571
572 wxRect rectText = rect;
573 rectText.x += 2;
574 rectText.width -= 2;
575 dc.DrawLabel(label, wxNullBitmap, rectText);
576
577 if ( flags & wxCONTROL_FOCUSED )
578 {
579 DrawFocusRect(dc, rect);
580 }
581 }
582
583 void wxStdRenderer::DrawCheckItemBitmap(wxDC& dc,
584 const wxBitmap& bitmap,
585 const wxRect& rect,
586 int flags)
587 {
588 DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags);
589 }
590
591 void wxStdRenderer::DrawCheckItem(wxDC& dc,
592 const wxString& label,
593 const wxBitmap& bitmap,
594 const wxRect& rect,
595 int flags)
596 {
597 wxRect rectBitmap = rect;
598 rectBitmap.width = GetCheckBitmapSize().x;
599 DrawCheckItemBitmap(dc, bitmap, rectBitmap, flags);
600
601 wxRect rectLabel = rect;
602 wxCoord shift = rectBitmap.width + 2*GetCheckItemMargin();
603 rectLabel.x += shift;
604 rectLabel.width -= shift;
605 DrawItem(dc, label, rectLabel, flags);
606 }
607
608 // ----------------------------------------------------------------------------
609 // check and radio bitmaps
610 // ----------------------------------------------------------------------------
611
612 void wxStdRenderer::DrawCheckButton(wxDC& dc,
613 const wxString& label,
614 const wxBitmap& bitmap,
615 const wxRect& rect,
616 int flags,
617 wxAlignment align,
618 int indexAccel)
619 {
620 wxBitmap bmp(bitmap.Ok() ? bitmap : GetCheckBitmap(flags));
621
622 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
623 }
624
625 void wxStdRenderer::DrawRadioButton(wxDC& dc,
626 const wxString& label,
627 const wxBitmap& bitmap,
628 const wxRect& rect,
629 int flags,
630 wxAlignment align,
631 int indexAccel)
632 {
633 wxBitmap bmp(bitmap.Ok() ? bitmap : GetRadioBitmap(flags));
634
635 DrawCheckOrRadioButton(dc, label, bmp, rect, flags, align, indexAccel);
636 }
637
638 void wxStdRenderer::DrawCheckOrRadioButton(wxDC& dc,
639 const wxString& label,
640 const wxBitmap& bitmap,
641 const wxRect& rect,
642 int flags,
643 wxAlignment align,
644 int indexAccel)
645 {
646 // calculate the position of the bitmap and of the label
647 wxCoord heightBmp = bitmap.GetHeight();
648 wxCoord xBmp,
649 yBmp = rect.y + (rect.height - heightBmp) / 2;
650
651 wxRect rectLabel;
652 dc.GetMultiLineTextExtent(label, NULL, &rectLabel.height);
653 rectLabel.y = rect.y + (rect.height - rectLabel.height) / 2;
654
655 // align label vertically with the bitmap - looks nicer like this
656 rectLabel.y -= (rectLabel.height - heightBmp) % 2;
657
658 // calc horz position
659 if ( align == wxALIGN_RIGHT )
660 {
661 xBmp = rect.GetRight() - bitmap.GetWidth();
662 rectLabel.x = rect.x + 3;
663 rectLabel.SetRight(xBmp);
664 }
665 else // normal (checkbox to the left of the text) case
666 {
667 xBmp = rect.x;
668 rectLabel.x = xBmp + bitmap.GetWidth() + 5;
669 rectLabel.SetRight(rect.GetRight());
670 }
671
672 dc.DrawBitmap(bitmap, xBmp, yBmp, true /* use mask */);
673
674 DrawLabel(dc, label, rectLabel, flags,
675 wxALIGN_LEFT | wxALIGN_TOP, indexAccel);
676 }
677
678 #if wxUSE_TEXTCTRL
679
680 void wxStdRenderer::DrawTextLine(wxDC& dc,
681 const wxString& text,
682 const wxRect& rect,
683 int selStart,
684 int selEnd,
685 int flags)
686 {
687 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
688 {
689 // just draw it as is
690 dc.DrawText(text, rect.x, rect.y);
691 }
692 else // we have selection
693 {
694 wxCoord width,
695 x = rect.x;
696
697 // draw the part before selection
698 wxString s(text, (size_t)selStart);
699 if ( !s.empty() )
700 {
701 dc.DrawText(s, x, rect.y);
702
703 dc.GetTextExtent(s, &width, NULL);
704 x += width;
705 }
706
707 // draw the selection itself
708 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
709 if ( !s.empty() )
710 {
711 wxColour colFg = dc.GetTextForeground(),
712 colBg = dc.GetTextBackground();
713 dc.SetTextForeground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT_TEXT));
714 dc.SetTextBackground(wxSCHEME_COLOUR(m_scheme, HIGHLIGHT));
715 dc.SetBackgroundMode(wxSOLID);
716
717 dc.DrawText(s, x, rect.y);
718 dc.GetTextExtent(s, &width, NULL);
719 x += width;
720
721 dc.SetBackgroundMode(wxTRANSPARENT);
722 dc.SetTextBackground(colBg);
723 dc.SetTextForeground(colFg);
724 }
725
726 // draw the final part
727 s = text.c_str() + selEnd;
728 if ( !s.empty() )
729 {
730 dc.DrawText(s, x, rect.y);
731 }
732 }
733 }
734
735 void wxStdRenderer::DrawLineWrapMark(wxDC& WXUNUSED(dc),
736 const wxRect& WXUNUSED(rect))
737 {
738 // nothing by default
739 }
740
741 int wxStdRenderer::GetTextBorderWidth(const wxTextCtrl * WXUNUSED(text)) const
742 {
743 return 1;
744 }
745
746 wxRect
747 wxStdRenderer::GetTextTotalArea(const wxTextCtrl *text, const wxRect& rect) const
748 {
749 wxRect rectTotal = rect;
750 rectTotal.Inflate(GetTextBorderWidth(text));
751 return rectTotal;
752 }
753
754 wxRect wxStdRenderer::GetTextClientArea(const wxTextCtrl *text,
755 const wxRect& rect,
756 wxCoord *extraSpaceBeyond) const
757 {
758 wxRect rectText = rect;
759 rectText.Deflate(GetTextBorderWidth(text));
760
761 if ( extraSpaceBeyond )
762 *extraSpaceBeyond = 0;
763
764 return rectText;
765 }
766
767 #endif // wxUSE_TEXTCTRL
768
769 // ----------------------------------------------------------------------------
770 // scrollbars drawing
771 // ----------------------------------------------------------------------------
772
773 void wxStdRenderer::DrawScrollbarArrow(wxDC& dc,
774 wxDirection dir,
775 const wxRect& rect,
776 int flags)
777 {
778 DrawArrow(dc, dir, rect, flags);
779 }
780
781 void wxStdRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
782 {
783 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
784 }
785
786 // ----------------------------------------------------------------------------
787 // scrollbars geometry
788 // ----------------------------------------------------------------------------
789
790 #if wxUSE_SCROLLBAR
791
792 /* static */
793 void wxStdRenderer::GetScrollBarThumbSize(wxCoord length,
794 int thumbPos,
795 int thumbSize,
796 int range,
797 wxCoord *thumbStart,
798 wxCoord *thumbEnd)
799 {
800 // the thumb can't be made less than this number of pixels
801 static const wxCoord thumbMinWidth = 8; // FIXME: should be configurable
802
803 *thumbStart = (length*thumbPos) / range;
804 *thumbEnd = (length*(thumbPos + thumbSize)) / range;
805
806 if ( *thumbEnd - *thumbStart < thumbMinWidth )
807 {
808 // adjust the end if possible
809 if ( *thumbStart <= length - thumbMinWidth )
810 {
811 // yes, just make it wider
812 *thumbEnd = *thumbStart + thumbMinWidth;
813 }
814 else // it is at the bottom of the scrollbar
815 {
816 // so move it a bit up
817 *thumbStart = length - thumbMinWidth;
818 *thumbEnd = length;
819 }
820 }
821 }
822
823 wxRect wxStdRenderer::GetScrollbarRect(const wxScrollBar *scrollbar,
824 wxScrollBar::Element elem,
825 int thumbPos) const
826 {
827 if ( thumbPos == -1 )
828 {
829 thumbPos = scrollbar->GetThumbPosition();
830 }
831
832 const wxSize sizeArrow = GetScrollbarArrowSize();
833
834 wxSize sizeTotal = scrollbar->GetClientSize();
835 wxCoord *start, *width;
836 wxCoord length, arrow;
837 wxRect rect;
838 if ( scrollbar->IsVertical() )
839 {
840 rect.x = 0;
841 rect.width = sizeTotal.x;
842 length = sizeTotal.y;
843 start = &rect.y;
844 width = &rect.height;
845 arrow = sizeArrow.y;
846 }
847 else // horizontal
848 {
849 rect.y = 0;
850 rect.height = sizeTotal.y;
851 length = sizeTotal.x;
852 start = &rect.x;
853 width = &rect.width;
854 arrow = sizeArrow.x;
855 }
856
857 switch ( elem )
858 {
859 case wxScrollBar::Element_Arrow_Line_1:
860 *start = 0;
861 *width = arrow;
862 break;
863
864 case wxScrollBar::Element_Arrow_Line_2:
865 *start = length - arrow;
866 *width = arrow;
867 break;
868
869 case wxScrollBar::Element_Arrow_Page_1:
870 case wxScrollBar::Element_Arrow_Page_2:
871 // we don't have them at all
872 break;
873
874 case wxScrollBar::Element_Thumb:
875 case wxScrollBar::Element_Bar_1:
876 case wxScrollBar::Element_Bar_2:
877 // we need to calculate the thumb position - do it
878 {
879 length -= 2*arrow;
880 wxCoord thumbStart, thumbEnd;
881 int range = scrollbar->GetRange();
882 if ( !range )
883 {
884 thumbStart =
885 thumbEnd = 0;
886 }
887 else
888 {
889 GetScrollBarThumbSize(length,
890 thumbPos,
891 scrollbar->GetThumbSize(),
892 range,
893 &thumbStart,
894 &thumbEnd);
895 }
896
897 if ( elem == wxScrollBar::Element_Thumb )
898 {
899 *start = thumbStart;
900 *width = thumbEnd - thumbStart;
901 }
902 else if ( elem == wxScrollBar::Element_Bar_1 )
903 {
904 *start = 0;
905 *width = thumbStart;
906 }
907 else // elem == wxScrollBar::Element_Bar_2
908 {
909 *start = thumbEnd;
910 *width = length - thumbEnd;
911 }
912
913 // everything is relative to the start of the shaft so far
914 *start += arrow;
915 }
916 break;
917
918 case wxScrollBar::Element_Max:
919 default:
920 wxFAIL_MSG( _T("unknown scrollbar element") );
921 }
922
923 return rect;
924 }
925
926 wxCoord wxStdRenderer::GetScrollbarSize(const wxScrollBar *scrollbar)
927 {
928 const wxSize sizeArrowSB = GetScrollbarArrowSize();
929
930 wxCoord sizeArrow, sizeTotal;
931 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
932 {
933 sizeArrow = sizeArrowSB.y;
934 sizeTotal = scrollbar->GetSize().y;
935 }
936 else // horizontal
937 {
938 sizeArrow = sizeArrowSB.x;
939 sizeTotal = scrollbar->GetSize().x;
940 }
941
942 return sizeTotal - 2*sizeArrow;
943 }
944
945 wxHitTest
946 wxStdRenderer::HitTestScrollbar(const wxScrollBar *scrollbar, const wxPoint& pt) const
947 {
948 // we only need to work with either x or y coord depending on the
949 // orientation, choose one (but still check the other one to verify if the
950 // mouse is in the window at all)
951 const wxSize sizeArrowSB = GetScrollbarArrowSize();
952
953 wxCoord coord, sizeArrow, sizeTotal;
954 wxSize size = scrollbar->GetSize();
955 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
956 {
957 if ( pt.x < 0 || pt.x > size.x )
958 return wxHT_NOWHERE;
959
960 coord = pt.y;
961 sizeArrow = sizeArrowSB.y;
962 sizeTotal = size.y;
963 }
964 else // horizontal
965 {
966 if ( pt.y < 0 || pt.y > size.y )
967 return wxHT_NOWHERE;
968
969 coord = pt.x;
970 sizeArrow = sizeArrowSB.x;
971 sizeTotal = size.x;
972 }
973
974 // test for the arrows first as it's faster
975 if ( coord < 0 || coord > sizeTotal )
976 {
977 return wxHT_NOWHERE;
978 }
979 else if ( coord < sizeArrow )
980 {
981 return wxHT_SCROLLBAR_ARROW_LINE_1;
982 }
983 else if ( coord > sizeTotal - sizeArrow )
984 {
985 return wxHT_SCROLLBAR_ARROW_LINE_2;
986 }
987 else
988 {
989 // calculate the thumb position in pixels
990 sizeTotal -= 2*sizeArrow;
991 wxCoord thumbStart, thumbEnd;
992 int range = scrollbar->GetRange();
993 if ( !range )
994 {
995 // clicking the scrollbar without range has no effect
996 return wxHT_NOWHERE;
997 }
998 else
999 {
1000 GetScrollBarThumbSize(sizeTotal,
1001 scrollbar->GetThumbPosition(),
1002 scrollbar->GetThumbSize(),
1003 range,
1004 &thumbStart,
1005 &thumbEnd);
1006 }
1007
1008 // now compare with the thumb position
1009 coord -= sizeArrow;
1010 if ( coord < thumbStart )
1011 return wxHT_SCROLLBAR_BAR_1;
1012 else if ( coord > thumbEnd )
1013 return wxHT_SCROLLBAR_BAR_2;
1014 else
1015 return wxHT_SCROLLBAR_THUMB;
1016 }
1017 }
1018
1019
1020 wxCoord
1021 wxStdRenderer::ScrollbarToPixel(const wxScrollBar *scrollbar, int thumbPos)
1022 {
1023 int range = scrollbar->GetRange();
1024 if ( !range )
1025 {
1026 // the only valid position anyhow
1027 return 0;
1028 }
1029
1030 if ( thumbPos == -1 )
1031 {
1032 // by default use the current thumb position
1033 thumbPos = scrollbar->GetThumbPosition();
1034 }
1035
1036 const wxSize sizeArrow = GetScrollbarArrowSize();
1037 return (thumbPos*GetScrollbarSize(scrollbar)) / range
1038 + (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x);
1039 }
1040
1041 int wxStdRenderer::PixelToScrollbar(const wxScrollBar *scrollbar, wxCoord coord)
1042 {
1043 const wxSize sizeArrow = GetScrollbarArrowSize();
1044 return ((coord - (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x)) *
1045 scrollbar->GetRange() ) / GetScrollbarSize(scrollbar);
1046 }
1047
1048 #endif // wxUSE_SCROLLBAR
1049