]> git.saurik.com Git - wxWidgets.git/blob - src/univ/renderer.cpp
Added "metal" theme.
[wxWidgets.git] / src / univ / renderer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: univ/renderer.cpp
3 // Purpose: wxControlRenderer implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 15.08.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "renderer.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/app.h"
33 #include "wx/control.h"
34 #include "wx/checklst.h"
35 #include "wx/listbox.h"
36 #include "wx/scrolbar.h"
37 #include "wx/dc.h"
38 #endif // WX_PRECOMP
39
40 #include "wx/image.h"
41
42 #include "wx/univ/theme.h"
43 #include "wx/univ/renderer.h"
44 #include "wx/univ/colschem.h"
45
46 #if wxUSE_GAUGE
47 #include "wx/gauge.h"
48 #endif
49
50 // ============================================================================
51 // implementation
52 // ============================================================================
53
54 // ----------------------------------------------------------------------------
55 // wxRenderer: drawing helpers
56 // ----------------------------------------------------------------------------
57
58 void wxRenderer::StandardDrawFrame(wxDC& dc,
59 const wxRect& rectFrame,
60 const wxRect& rectLabel)
61 {
62 // draw left, bottom and right lines entirely
63 DrawVerticalLine(dc, rectFrame.GetLeft(),
64 rectFrame.GetTop(), rectFrame.GetBottom() - 2);
65 DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
66 rectFrame.GetLeft(), rectFrame.GetRight());
67 DrawVerticalLine(dc, rectFrame.GetRight() - 1,
68 rectFrame.GetTop(), rectFrame.GetBottom() - 1);
69
70 // and 2 parts of the top line
71 DrawHorizontalLine(dc, rectFrame.GetTop(),
72 rectFrame.GetLeft() + 1, rectLabel.GetLeft());
73 DrawHorizontalLine(dc, rectFrame.GetTop(),
74 rectLabel.GetRight(), rectFrame.GetRight() - 2);
75 }
76
77 /* static */
78 void wxRenderer::StandardDrawTextLine(wxDC& dc,
79 const wxString& text,
80 const wxRect& rect,
81 int selStart, int selEnd,
82 int flags)
83 {
84 if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
85 {
86 // just draw it as is
87 dc.DrawText(text, rect.x, rect.y);
88 }
89 else // we have selection
90 {
91 wxCoord width,
92 x = rect.x;
93
94 // draw the part before selection
95 wxString s(text, (size_t)selStart);
96 if ( !s.empty() )
97 {
98 dc.DrawText(s, x, rect.y);
99
100 dc.GetTextExtent(s, &width, NULL);
101 x += width;
102 }
103
104 // draw the selection itself
105 s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
106 if ( !s.empty() )
107 {
108 wxColour colFg = dc.GetTextForeground(),
109 colBg = dc.GetTextBackground();
110 dc.SetTextForeground(wxTHEME_COLOUR(HIGHLIGHT_TEXT));
111 dc.SetTextBackground(wxTHEME_COLOUR(HIGHLIGHT));
112 dc.SetBackgroundMode(wxSOLID);
113
114 dc.DrawText(s, x, rect.y);
115 dc.GetTextExtent(s, &width, NULL);
116 x += width;
117
118 dc.SetBackgroundMode(wxTRANSPARENT);
119 dc.SetTextBackground(colBg);
120 dc.SetTextForeground(colFg);
121 }
122
123 // draw the final part
124 s = text.c_str() + selEnd;
125 if ( !s.empty() )
126 {
127 dc.DrawText(s, x, rect.y);
128 }
129 }
130 }
131
132 // ----------------------------------------------------------------------------
133 // wxRenderer: scrollbar geometry
134 // ----------------------------------------------------------------------------
135
136 /* static */
137 void wxRenderer::StandardScrollBarThumbSize(wxCoord length,
138 int thumbPos,
139 int thumbSize,
140 int range,
141 wxCoord *thumbStart,
142 wxCoord *thumbEnd)
143 {
144 // the thumb can't be made less than this number of pixels
145 static const wxCoord thumbMinWidth = 8; // FIXME: should be configurable
146
147 *thumbStart = (length*thumbPos) / range;
148 *thumbEnd = (length*(thumbPos + thumbSize)) / range;
149
150 if ( *thumbEnd - *thumbStart < thumbMinWidth )
151 {
152 // adjust the end if possible
153 if ( *thumbStart <= length - thumbMinWidth )
154 {
155 // yes, just make it wider
156 *thumbEnd = *thumbStart + thumbMinWidth;
157 }
158 else // it is at the bottom of the scrollbar
159 {
160 // so move it a bit up
161 *thumbStart = length - thumbMinWidth;
162 *thumbEnd = length;
163 }
164 }
165 }
166
167 /* static */
168 wxRect wxRenderer::StandardGetScrollbarRect(const wxScrollBar *scrollbar,
169 wxScrollBar::Element elem,
170 int thumbPos,
171 const wxSize& sizeArrow)
172 {
173 if ( thumbPos == -1 )
174 {
175 thumbPos = scrollbar->GetThumbPosition();
176 }
177
178 wxSize sizeTotal = scrollbar->GetClientSize();
179 wxCoord *start, *width, length, arrow;
180 wxRect rect;
181 if ( scrollbar->IsVertical() )
182 {
183 rect.x = 0;
184 rect.width = sizeTotal.x;
185 length = sizeTotal.y;
186 start = &rect.y;
187 width = &rect.height;
188 arrow = sizeArrow.y;
189 }
190 else // horizontal
191 {
192 rect.y = 0;
193 rect.height = sizeTotal.y;
194 length = sizeTotal.x;
195 start = &rect.x;
196 width = &rect.width;
197 arrow = sizeArrow.x;
198 }
199
200 switch ( elem )
201 {
202 case wxScrollBar::Element_Arrow_Line_1:
203 *start = 0;
204 *width = arrow;
205 break;
206
207 case wxScrollBar::Element_Arrow_Line_2:
208 *start = length - arrow;
209 *width = arrow;
210 break;
211
212 case wxScrollBar::Element_Arrow_Page_1:
213 case wxScrollBar::Element_Arrow_Page_2:
214 // we don't have them at all
215 break;
216
217 case wxScrollBar::Element_Thumb:
218 case wxScrollBar::Element_Bar_1:
219 case wxScrollBar::Element_Bar_2:
220 // we need to calculate the thumb position - do it
221 {
222 length -= 2*arrow;
223 wxCoord thumbStart, thumbEnd;
224 int range = scrollbar->GetRange();
225 if ( !range )
226 {
227 thumbStart =
228 thumbEnd = 0;
229 }
230 else
231 {
232 StandardScrollBarThumbSize(length,
233 thumbPos,
234 scrollbar->GetThumbSize(),
235 range,
236 &thumbStart,
237 &thumbEnd);
238 }
239
240 if ( elem == wxScrollBar::Element_Thumb )
241 {
242 *start = thumbStart;
243 *width = thumbEnd - thumbStart;
244 }
245 else if ( elem == wxScrollBar::Element_Bar_1 )
246 {
247 *start = 0;
248 *width = thumbStart;
249 }
250 else // elem == wxScrollBar::Element_Bar_2
251 {
252 *start = thumbEnd;
253 *width = length - thumbEnd;
254 }
255
256 // everything is relative to the start of the shaft so far
257 *start += arrow;
258 }
259 break;
260
261 case wxScrollBar::Element_Max:
262 default:
263 wxFAIL_MSG( _T("unknown scrollbar element") );
264 }
265
266 return rect;
267 }
268
269 /* static */
270 wxCoord wxRenderer::StandardScrollBarSize(const wxScrollBar *scrollbar,
271 const wxSize& sizeArrowSB)
272 {
273 wxCoord sizeArrow, sizeTotal;
274 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
275 {
276 sizeArrow = sizeArrowSB.y;
277 sizeTotal = scrollbar->GetSize().y;
278 }
279 else // horizontal
280 {
281 sizeArrow = sizeArrowSB.x;
282 sizeTotal = scrollbar->GetSize().x;
283 }
284
285 return sizeTotal - 2*sizeArrow;
286 }
287
288 /* static */
289 wxCoord wxRenderer::StandardScrollbarToPixel(const wxScrollBar *scrollbar,
290 int thumbPos,
291 const wxSize& sizeArrow)
292 {
293 int range = scrollbar->GetRange();
294 if ( !range )
295 {
296 // the only valid position anyhow
297 return 0;
298 }
299
300 if ( thumbPos == -1 )
301 {
302 // by default use the current thumb position
303 thumbPos = scrollbar->GetThumbPosition();
304 }
305
306 return ( thumbPos*StandardScrollBarSize(scrollbar, sizeArrow) ) / range
307 + (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x);
308 }
309
310 /* static */
311 int wxRenderer::StandardPixelToScrollbar(const wxScrollBar *scrollbar,
312 wxCoord coord,
313 const wxSize& sizeArrow)
314 {
315 return ( (coord - (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x)) *
316 scrollbar->GetRange() ) /
317 StandardScrollBarSize(scrollbar, sizeArrow);
318 }
319
320 /* static */
321 wxHitTest wxRenderer::StandardHitTestScrollbar(const wxScrollBar *scrollbar,
322 const wxPoint& pt,
323 const wxSize& sizeArrowSB)
324 {
325 // we only need to work with either x or y coord depending on the
326 // orientation, choose one (but still check the other one to verify if the
327 // mouse is in the window at all)
328 wxCoord coord, sizeArrow, sizeTotal;
329 wxSize size = scrollbar->GetSize();
330 if ( scrollbar->GetWindowStyle() & wxVERTICAL )
331 {
332 if ( pt.x < 0 || pt.x > size.x )
333 return wxHT_NOWHERE;
334
335 coord = pt.y;
336 sizeArrow = sizeArrowSB.y;
337 sizeTotal = size.y;
338 }
339 else // horizontal
340 {
341 if ( pt.y < 0 || pt.y > size.y )
342 return wxHT_NOWHERE;
343
344 coord = pt.x;
345 sizeArrow = sizeArrowSB.x;
346 sizeTotal = size.x;
347 }
348
349 // test for the arrows first as it's faster
350 if ( coord < 0 || coord > sizeTotal )
351 {
352 return wxHT_NOWHERE;
353 }
354 else if ( coord < sizeArrow )
355 {
356 return wxHT_SCROLLBAR_ARROW_LINE_1;
357 }
358 else if ( coord > sizeTotal - sizeArrow )
359 {
360 return wxHT_SCROLLBAR_ARROW_LINE_2;
361 }
362 else
363 {
364 // calculate the thumb position in pixels
365 sizeTotal -= 2*sizeArrow;
366 wxCoord thumbStart, thumbEnd;
367 int range = scrollbar->GetRange();
368 if ( !range )
369 {
370 // clicking the scrollbar without range has no effect
371 return wxHT_NOWHERE;
372 }
373 else
374 {
375 StandardScrollBarThumbSize(sizeTotal,
376 scrollbar->GetThumbPosition(),
377 scrollbar->GetThumbSize(),
378 range,
379 &thumbStart,
380 &thumbEnd);
381 }
382
383 // now compare with the thumb position
384 coord -= sizeArrow;
385 if ( coord < thumbStart )
386 return wxHT_SCROLLBAR_BAR_1;
387 else if ( coord > thumbEnd )
388 return wxHT_SCROLLBAR_BAR_2;
389 else
390 return wxHT_SCROLLBAR_THUMB;
391 }
392 }
393
394 wxRenderer::~wxRenderer()
395 {
396 }
397
398 // ----------------------------------------------------------------------------
399 // wxControlRenderer
400 // ----------------------------------------------------------------------------
401
402 wxControlRenderer::wxControlRenderer(wxWindow *window,
403 wxDC& dc,
404 wxRenderer *renderer)
405 : m_dc(dc)
406 {
407 m_window = window;
408 m_renderer = renderer;
409
410 wxSize size = m_window->GetClientSize();
411 m_rect.x =
412 m_rect.y = 0;
413 m_rect.width = size.x;
414 m_rect.height = size.y;
415 }
416
417 void wxControlRenderer::DrawLabel(const wxBitmap& bitmap,
418 wxCoord marginX, wxCoord marginY)
419 {
420 m_dc.SetBackgroundMode(wxTRANSPARENT);
421 m_dc.SetFont(m_window->GetFont());
422 m_dc.SetTextForeground(m_window->GetForegroundColour());
423
424 wxString label = m_window->GetLabel();
425 if ( !label.empty() || bitmap.Ok() )
426 {
427 wxRect rectLabel = m_rect;
428 if ( bitmap.Ok() )
429 {
430 rectLabel.Inflate(-marginX, -marginY);
431
432 // I don't know why this is necessary. RR.
433 rectLabel.x ++;
434 rectLabel.y ++;
435 }
436
437 wxControl *ctrl = wxStaticCast(m_window, wxControl);
438
439 m_renderer->DrawButtonLabel(m_dc,
440 label,
441 bitmap,
442 rectLabel,
443 m_window->GetStateFlags(),
444 ctrl->GetAlignment(),
445 ctrl->GetAccelIndex());
446 }
447 }
448
449 void wxControlRenderer::DrawFrame()
450 {
451 m_dc.SetFont(m_window->GetFont());
452 m_dc.SetTextForeground(m_window->GetForegroundColour());
453 m_dc.SetTextBackground(m_window->GetBackgroundColour());
454
455 wxControl *ctrl = wxStaticCast(m_window, wxControl);
456
457 m_renderer->DrawFrame(m_dc,
458 m_window->GetLabel(),
459 m_rect,
460 m_window->GetStateFlags(),
461 ctrl->GetAlignment(),
462 ctrl->GetAccelIndex());
463 }
464
465 void wxControlRenderer::DrawButtonBorder()
466 {
467 int flags = m_window->GetStateFlags();
468
469 m_renderer->DrawButtonBorder(m_dc, m_rect, flags, &m_rect);
470
471 m_renderer->DrawBackground(m_dc, wxTHEME_BG_COLOUR(m_window), m_rect, flags);
472 }
473
474 void wxControlRenderer::DrawBitmap(const wxBitmap& bitmap)
475 {
476 int style = m_window->GetWindowStyle();
477 DrawBitmap(m_dc, bitmap, m_rect,
478 style & wxALIGN_MASK,
479 style & wxBI_EXPAND ? wxEXPAND : wxSTRETCH_NOT);
480 }
481
482 /* static */
483 void wxControlRenderer::DrawBitmap(wxDC &dc,
484 const wxBitmap& bitmap,
485 const wxRect& rect,
486 int alignment,
487 wxStretch stretch)
488 {
489 // we may change the bitmap if we stretch it
490 wxBitmap bmp = bitmap;
491 if ( !bmp.Ok() )
492 return;
493
494 int width = bmp.GetWidth(),
495 height = bmp.GetHeight();
496
497 wxCoord x = 0,
498 y = 0;
499 if ( stretch & wxTILE )
500 {
501 // tile the bitmap
502 for ( ; x < rect.width; x += width )
503 {
504 for ( y = 0; y < rect.height; y += height )
505 {
506 // no need to use mask here as we cover the entire window area
507 dc.DrawBitmap(bmp, x, y);
508 }
509 }
510 }
511 else if ( stretch & wxEXPAND )
512 {
513 // stretch bitmap to fill the entire control
514 bmp = wxImage(bmp.ConvertToImage()).Scale(rect.width, rect.height);
515 }
516 else // not stretched, not tiled
517 {
518 if ( alignment & wxALIGN_RIGHT )
519 {
520 x = rect.GetRight() - width;
521 }
522 else if ( alignment & wxALIGN_CENTRE )
523 {
524 x = (rect.GetLeft() + rect.GetRight() - width + 1) / 2;
525 }
526 else // alignment & wxALIGN_LEFT
527 {
528 x = rect.GetLeft();
529 }
530
531 if ( alignment & wxALIGN_BOTTOM )
532 {
533 y = rect.GetBottom() - height;
534 }
535 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
536 {
537 y = (rect.GetTop() + rect.GetBottom() - height + 1) / 2;
538 }
539 else // alignment & wxALIGN_TOP
540 {
541 y = rect.GetTop();
542 }
543 }
544
545 // do draw it
546 dc.DrawBitmap(bmp, x, y, TRUE /* use mask */);
547 }
548
549 void wxControlRenderer::DrawScrollbar(const wxScrollBar *scrollbar,
550 int thumbPosOld)
551 {
552 // we will only redraw the parts which must be redrawn and not everything
553 wxRegion rgnUpdate = scrollbar->GetUpdateRegion();
554
555 {
556 wxRect rectUpdate = rgnUpdate.GetBox();
557 wxLogTrace(_T("scrollbar"),
558 _T("%s redraw: update box is (%d, %d)-(%d, %d)"),
559 scrollbar->IsVertical() ? _T("vert") : _T("horz"),
560 rectUpdate.GetLeft(),
561 rectUpdate.GetTop(),
562 rectUpdate.GetRight(),
563 rectUpdate.GetBottom());
564
565 #if 0 //def WXDEBUG_SCROLLBAR
566 static bool s_refreshDebug = FALSE;
567 if ( s_refreshDebug )
568 {
569 wxClientDC dc(wxConstCast(scrollbar, wxScrollBar));
570 dc.SetBrush(*wxRED_BRUSH);
571 dc.SetPen(*wxTRANSPARENT_PEN);
572 dc.DrawRectangle(rectUpdate);
573
574 // under Unix we use "--sync" X option for this
575 #ifdef __WXMSW__
576 ::GdiFlush();
577 ::Sleep(200);
578 #endif // __WXMSW__
579 }
580 #endif // WXDEBUG_SCROLLBAR
581 }
582
583 wxOrientation orient = scrollbar->IsVertical() ? wxVERTICAL
584 : wxHORIZONTAL;
585
586 // the shaft
587 for ( int nBar = 0; nBar < 2; nBar++ )
588 {
589 wxScrollBar::Element elem =
590 (wxScrollBar::Element)(wxScrollBar::Element_Bar_1 + nBar);
591
592 wxRect rectBar = m_renderer->GetScrollbarRect(scrollbar, elem);
593
594 if ( rgnUpdate.Contains(rectBar) )
595 {
596 wxLogTrace(_T("scrollbar"),
597 _T("drawing bar part %d at (%d, %d)-(%d, %d)"),
598 nBar + 1,
599 rectBar.GetLeft(),
600 rectBar.GetTop(),
601 rectBar.GetRight(),
602 rectBar.GetBottom());
603
604 m_renderer->DrawScrollbarShaft(m_dc,
605 orient,
606 rectBar,
607 scrollbar->GetState(elem));
608 }
609 }
610
611 // arrows
612 for ( int nArrow = 0; nArrow < 2; nArrow++ )
613 {
614 wxScrollBar::Element elem =
615 (wxScrollBar::Element)(wxScrollBar::Element_Arrow_Line_1 + nArrow);
616
617 wxRect rectArrow = m_renderer->GetScrollbarRect(scrollbar, elem);
618 if ( rgnUpdate.Contains(rectArrow) )
619 {
620 wxLogTrace(_T("scrollbar"),
621 _T("drawing arrow %d at (%d, %d)-(%d, %d)"),
622 nArrow + 1,
623 rectArrow.GetLeft(),
624 rectArrow.GetTop(),
625 rectArrow.GetRight(),
626 rectArrow.GetBottom());
627
628 scrollbar->GetArrows().DrawArrow
629 (
630 (wxScrollArrows::Arrow)nArrow,
631 m_dc,
632 rectArrow,
633 TRUE // draw a scrollbar arrow, not just an arrow
634 );
635 }
636 }
637
638 // TODO: support for page arrows
639
640 // and the thumb
641 wxScrollBar::Element elem = wxScrollBar::Element_Thumb;
642 wxRect rectThumb = m_renderer->GetScrollbarRect(scrollbar, elem);
643 if ( rectThumb.width && rectThumb.height && rgnUpdate.Contains(rectThumb) )
644 {
645 wxLogTrace(_T("scrollbar"),
646 _T("drawing thumb at (%d, %d)-(%d, %d)"),
647 rectThumb.GetLeft(),
648 rectThumb.GetTop(),
649 rectThumb.GetRight(),
650 rectThumb.GetBottom());
651
652 m_renderer->DrawScrollbarThumb(m_dc,
653 orient,
654 rectThumb,
655 scrollbar->GetState(elem));
656 }
657 }
658
659 void wxControlRenderer::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
660 {
661 wxASSERT_MSG( x1 == x2 || y1 == y2,
662 _T("line must be either horizontal or vertical") );
663
664 if ( x1 == x2 )
665 m_renderer->DrawVerticalLine(m_dc, x1, y1, y2);
666 else // horizontal
667 m_renderer->DrawHorizontalLine(m_dc, y1, x1, x2);
668 }
669
670 #if wxUSE_LISTBOX
671
672 void wxControlRenderer::DrawItems(const wxListBox *lbox,
673 size_t itemFirst, size_t itemLast)
674 {
675 DoDrawItems(lbox, itemFirst, itemLast);
676 }
677
678 void wxControlRenderer::DoDrawItems(const wxListBox *lbox,
679 size_t itemFirst, size_t itemLast,
680 bool isCheckLbox)
681 {
682 // prepare for the drawing: calc the initial position
683 wxCoord lineHeight = lbox->GetLineHeight();
684
685 // note that SetClippingRegion() needs the physical (unscrolled)
686 // coordinates while we use the logical (scrolled) ones for the drawing
687 // itself
688 wxRect rect;
689 wxSize size = lbox->GetClientSize();
690 rect.width = size.x;
691 rect.height = size.y;
692
693 // keep the text inside the client rect or we will overwrite the vertical
694 // scrollbar for the long strings
695 m_dc.SetClippingRegion(rect.x, rect.y, rect.width + 1, rect.height + 1);
696
697 // adjust the rect position now
698 lbox->CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
699 rect.y += itemFirst*lineHeight;
700 rect.height = lineHeight;
701
702 // the rect should go to the right visible border so adjust the width if x
703 // is shifted (rightmost point should stay the same)
704 rect.width -= rect.x;
705
706 // we'll keep the text colour unchanged
707 m_dc.SetTextForeground(lbox->GetForegroundColour());
708
709 // an item should have the focused rect only when the lbox has focus, so
710 // make sure that we never set wxCONTROL_FOCUSED flag if it doesn't
711 int itemCurrent = wxWindow::FindFocus() == (wxWindow *)lbox // cast needed
712 ? lbox->GetCurrentItem()
713 : -1;
714 for ( size_t n = itemFirst; n < itemLast; n++ )
715 {
716 int flags = 0;
717 if ( (int)n == itemCurrent )
718 flags |= wxCONTROL_FOCUSED;
719 if ( lbox->IsSelected(n) )
720 flags |= wxCONTROL_SELECTED;
721
722 #if wxUSE_CHECKLISTBOX
723 if ( isCheckLbox )
724 {
725 wxCheckListBox *checklstbox = wxStaticCast(lbox, wxCheckListBox);
726 if ( checklstbox->IsChecked(n) )
727 flags |= wxCONTROL_CHECKED;
728
729 m_renderer->DrawCheckItem(m_dc, lbox->GetString(n),
730 wxNullBitmap,
731 rect,
732 flags);
733 }
734 else
735 #endif // wxUSE_CHECKLISTBOX
736 {
737 m_renderer->DrawItem(m_dc, lbox->GetString(n), rect, flags);
738 }
739
740 rect.y += lineHeight;
741 }
742 }
743
744 #endif // wxUSE_LISTBOX
745
746 #if wxUSE_CHECKLISTBOX
747
748 void wxControlRenderer::DrawCheckItems(const wxCheckListBox *lbox,
749 size_t itemFirst, size_t itemLast)
750 {
751 DoDrawItems(lbox, itemFirst, itemLast, TRUE);
752 }
753
754 #endif // wxUSE_CHECKLISTBOX
755
756 #if wxUSE_GAUGE
757
758 void wxControlRenderer::DrawProgressBar(const wxGauge *gauge)
759 {
760 // draw background
761 m_dc.SetBrush(wxBrush(m_window->GetBackgroundColour(), wxSOLID));
762 m_dc.SetPen(*wxTRANSPARENT_PEN);
763 m_dc.DrawRectangle(m_rect);
764
765 int max = gauge->GetRange();
766 if ( !max )
767 {
768 // nothing to draw
769 return;
770 }
771
772 // calc the filled rect
773 int pos = gauge->GetValue();
774 int left = max - pos;
775
776 wxRect rect = m_rect;
777 rect.Deflate(1); // FIXME this depends on the border width
778
779 wxColour col = m_window->UseFgCol() ? m_window->GetForegroundColour()
780 : wxTHEME_COLOUR(GAUGE);
781 m_dc.SetBrush(wxBrush(col, wxSOLID));
782
783 if ( gauge->IsSmooth() )
784 {
785 // just draw the rectangle in one go
786 if ( gauge->IsVertical() )
787 {
788 // vert bars grow from bottom to top
789 wxCoord dy = ((rect.height - 1) * left) / max;
790 rect.y += dy;
791 rect.height -= dy;
792 }
793 else // horizontal
794 {
795 // grow from left to right
796 rect.width -= ((rect.width - 1) * left) / max;
797 }
798
799 m_dc.DrawRectangle(rect);
800 }
801 else // discrete
802 {
803 wxSize sizeStep = m_renderer->GetProgressBarStep();
804 int step = gauge->IsVertical() ? sizeStep.y : sizeStep.x;
805
806 // we divide by it below!
807 wxCHECK_RET( step, _T("invalid wxGauge step") );
808
809 // round up to make the progress appear to start faster
810 int lenTotal = gauge->IsVertical() ? rect.height : rect.width;
811 int steps = ((lenTotal + step - 1) * pos) / (max * step);
812
813 // calc the coords of one small rect
814 wxCoord *px, dx, dy;
815 if ( gauge->IsVertical() )
816 {
817 // draw from bottom to top: so first set y to the bottom
818 rect.y += rect.height - 1;
819
820 // then adjust the height
821 rect.height = step;
822
823 // and then adjust y again to be what it should for the first rect
824 rect.y -= rect.height;
825
826 // we are going up
827 step = -step;
828
829 // remember that this will be the coord which will change
830 px = &rect.y;
831
832 dy = 1;
833 dx = 0;
834 }
835 else // horizontal
836 {
837 // don't leave 2 empty pixels in the beginning
838 rect.x--;
839
840 px = &rect.x;
841 rect.width = step;
842
843 dy = 0;
844 dx = 1;
845 }
846
847 for ( int n = 0; n < steps; n++ )
848 {
849 wxRect rectSegment = rect;
850 rectSegment.Deflate(dx, dy);
851
852 m_dc.DrawRectangle(rectSegment);
853
854 *px += step;
855 if ( *px < 1 )
856 {
857 // this can only happen for the last step of vertical gauge
858 rect.height = *px - step - 1;
859 *px = 1;
860 }
861 else if ( *px > lenTotal - step )
862 {
863 // this can only happen for the last step of horizontal gauge
864 rect.width = lenTotal - *px - 1;
865 }
866 }
867 }
868 }
869
870 #endif // wxUSE_GAUGE
871