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