]> git.saurik.com Git - wxWidgets.git/blob - src/univ/renderer.cpp
You can crash GTK with scrolled windows being
[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     // Why do this here?
472     // m_renderer->DrawButtonSurface(m_dc, wxTHEME_BG_COLOUR(m_window), m_rect, flags );
473 }
474
475 void wxControlRenderer::DrawBitmap(const wxBitmap& bitmap)
476 {
477     int style = m_window->GetWindowStyle();
478     DrawBitmap(m_dc, bitmap, m_rect,
479                style & wxALIGN_MASK,
480                style & wxBI_EXPAND ? wxEXPAND : wxSTRETCH_NOT);
481 }
482
483 /* static */
484 void wxControlRenderer::DrawBitmap(wxDC &dc,
485                                    const wxBitmap& bitmap,
486                                    const wxRect& rect,
487                                    int alignment,
488                                    wxStretch stretch)
489 {
490     // we may change the bitmap if we stretch it
491     wxBitmap bmp = bitmap;
492     if ( !bmp.Ok() )
493         return;
494
495     int width = bmp.GetWidth(),
496         height = bmp.GetHeight();
497
498     wxCoord x = 0,
499             y = 0;
500     if ( stretch & wxTILE )
501     {
502         // tile the bitmap
503         for ( ; x < rect.width; x += width )
504         {
505             for ( y = 0; y < rect.height; y += height )
506             {
507                 // no need to use mask here as we cover the entire window area
508                 dc.DrawBitmap(bmp, x, y);
509             }
510         }
511     }
512     else if ( stretch & wxEXPAND )
513     {
514         // stretch bitmap to fill the entire control
515         bmp = wxBitmap(wxImage(bmp.ConvertToImage()).Scale(rect.width, rect.height));
516     }
517     else // not stretched, not tiled
518     {
519         if ( alignment & wxALIGN_RIGHT )
520         {
521             x = rect.GetRight() - width;
522         }
523         else if ( alignment & wxALIGN_CENTRE )
524         {
525             x = (rect.GetLeft() + rect.GetRight() - width + 1) / 2;
526         }
527         else // alignment & wxALIGN_LEFT
528         {
529             x = rect.GetLeft();
530         }
531
532         if ( alignment & wxALIGN_BOTTOM )
533         {
534             y = rect.GetBottom() - height;
535         }
536         else if ( alignment & wxALIGN_CENTRE_VERTICAL )
537         {
538             y = (rect.GetTop() + rect.GetBottom() - height + 1) / 2;
539         }
540         else // alignment & wxALIGN_TOP
541         {
542             y = rect.GetTop();
543         }
544     }
545
546     // do draw it
547     dc.DrawBitmap(bmp, x, y, TRUE /* use mask */);
548 }
549
550 void wxControlRenderer::DrawScrollbar(const wxScrollBar *scrollbar,
551                                       int thumbPosOld)
552 {
553     // we will only redraw the parts which must be redrawn and not everything
554     wxRegion rgnUpdate = scrollbar->GetUpdateRegion();
555
556     {
557         wxRect rectUpdate = rgnUpdate.GetBox();
558         wxLogTrace(_T("scrollbar"),
559                    _T("%s redraw: update box is (%d, %d)-(%d, %d)"),
560                    scrollbar->IsVertical() ? _T("vert") : _T("horz"),
561                    rectUpdate.GetLeft(),
562                    rectUpdate.GetTop(),
563                    rectUpdate.GetRight(),
564                    rectUpdate.GetBottom());
565
566 #if 0 //def WXDEBUG_SCROLLBAR
567         static bool s_refreshDebug = FALSE;
568         if ( s_refreshDebug )
569         {
570             wxClientDC dc(wxConstCast(scrollbar, wxScrollBar));
571             dc.SetBrush(*wxRED_BRUSH);
572             dc.SetPen(*wxTRANSPARENT_PEN);
573             dc.DrawRectangle(rectUpdate);
574
575             // under Unix we use "--sync" X option for this
576             #ifdef __WXMSW__
577                 ::GdiFlush();
578                 ::Sleep(200);
579             #endif // __WXMSW__
580         }
581 #endif // WXDEBUG_SCROLLBAR
582     }
583
584     wxOrientation orient = scrollbar->IsVertical() ? wxVERTICAL
585                                                    : wxHORIZONTAL;
586
587     // the shaft
588     for ( int nBar = 0; nBar < 2; nBar++ )
589     {
590         wxScrollBar::Element elem =
591             (wxScrollBar::Element)(wxScrollBar::Element_Bar_1 + nBar);
592
593         wxRect rectBar = m_renderer->GetScrollbarRect(scrollbar, elem);
594
595         if ( rgnUpdate.Contains(rectBar) )
596         {
597             wxLogTrace(_T("scrollbar"),
598                        _T("drawing bar part %d at (%d, %d)-(%d, %d)"),
599                        nBar + 1,
600                        rectBar.GetLeft(),
601                        rectBar.GetTop(),
602                        rectBar.GetRight(),
603                        rectBar.GetBottom());
604
605             m_renderer->DrawScrollbarShaft(m_dc,
606                                            orient,
607                                            rectBar,
608                                            scrollbar->GetState(elem));
609         }
610     }
611
612     // arrows
613     for ( int nArrow = 0; nArrow < 2; nArrow++ )
614     {
615         wxScrollBar::Element elem =
616             (wxScrollBar::Element)(wxScrollBar::Element_Arrow_Line_1 + nArrow);
617
618         wxRect rectArrow = m_renderer->GetScrollbarRect(scrollbar, elem);
619         if ( rgnUpdate.Contains(rectArrow) )
620         {
621             wxLogTrace(_T("scrollbar"),
622                        _T("drawing arrow %d at (%d, %d)-(%d, %d)"),
623                        nArrow + 1,
624                        rectArrow.GetLeft(),
625                        rectArrow.GetTop(),
626                        rectArrow.GetRight(),
627                        rectArrow.GetBottom());
628
629             scrollbar->GetArrows().DrawArrow
630             (
631                 (wxScrollArrows::Arrow)nArrow,
632                 m_dc,
633                 rectArrow,
634                 TRUE // draw a scrollbar arrow, not just an arrow
635             );
636         }
637     }
638
639     // TODO: support for page arrows
640
641     // and the thumb
642     wxScrollBar::Element elem = wxScrollBar::Element_Thumb;
643     wxRect rectThumb = m_renderer->GetScrollbarRect(scrollbar, elem);
644     if ( rectThumb.width && rectThumb.height && rgnUpdate.Contains(rectThumb) )
645     {
646         wxLogTrace(_T("scrollbar"),
647                    _T("drawing thumb at (%d, %d)-(%d, %d)"),
648                    rectThumb.GetLeft(),
649                    rectThumb.GetTop(),
650                    rectThumb.GetRight(),
651                    rectThumb.GetBottom());
652
653         m_renderer->DrawScrollbarThumb(m_dc,
654                                        orient,
655                                        rectThumb,
656                                        scrollbar->GetState(elem));
657     }
658 }
659
660 void wxControlRenderer::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
661 {
662     wxASSERT_MSG( x1 == x2 || y1 == y2,
663                   _T("line must be either horizontal or vertical") );
664
665     if ( x1 == x2 )
666         m_renderer->DrawVerticalLine(m_dc, x1, y1, y2);
667     else // horizontal
668         m_renderer->DrawHorizontalLine(m_dc, y1, x1, x2);
669 }
670
671 #if wxUSE_LISTBOX
672
673 void wxControlRenderer::DrawItems(const wxListBox *lbox,
674                                   size_t itemFirst, size_t itemLast)
675 {
676     DoDrawItems(lbox, itemFirst, itemLast);
677 }
678
679 void wxControlRenderer::DoDrawItems(const wxListBox *lbox,
680                                     size_t itemFirst, size_t itemLast,
681                                     bool isCheckLbox)
682 {
683     // prepare for the drawing: calc the initial position
684     wxCoord lineHeight = lbox->GetLineHeight();
685
686     // note that SetClippingRegion() needs the physical (unscrolled)
687     // coordinates while we use the logical (scrolled) ones for the drawing
688     // itself
689     wxRect rect;
690     wxSize size = lbox->GetClientSize();
691     rect.width = size.x;
692     rect.height = size.y;
693
694     // keep the text inside the client rect or we will overwrite the vertical
695     // scrollbar for the long strings
696     m_dc.SetClippingRegion(rect.x, rect.y, rect.width + 1, rect.height + 1);
697
698     // adjust the rect position now
699     lbox->CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
700     rect.y += itemFirst*lineHeight;
701     rect.height = lineHeight;
702
703     // the rect should go to the right visible border so adjust the width if x
704     // is shifted (rightmost point should stay the same)
705     rect.width -= rect.x;
706
707     // we'll keep the text colour unchanged
708     m_dc.SetTextForeground(lbox->GetForegroundColour());
709
710     // an item should have the focused rect only when the lbox has focus, so
711     // make sure that we never set wxCONTROL_FOCUSED flag if it doesn't
712     int itemCurrent = wxWindow::FindFocus() == (wxWindow *)lbox // cast needed
713                         ? lbox->GetCurrentItem()
714                         : -1;
715     for ( size_t n = itemFirst; n < itemLast; n++ )
716     {
717         int flags = 0;
718         if ( (int)n == itemCurrent )
719             flags |= wxCONTROL_FOCUSED;
720         if ( lbox->IsSelected(n) )
721             flags |= wxCONTROL_SELECTED;
722
723 #if wxUSE_CHECKLISTBOX
724         if ( isCheckLbox )
725         {
726             wxCheckListBox *checklstbox = wxStaticCast(lbox, wxCheckListBox);
727             if ( checklstbox->IsChecked(n) )
728                 flags |= wxCONTROL_CHECKED;
729
730             m_renderer->DrawCheckItem(m_dc, lbox->GetString(n),
731                                       wxNullBitmap,
732                                       rect,
733                                       flags);
734         }
735         else
736 #endif // wxUSE_CHECKLISTBOX
737         {
738             m_renderer->DrawItem(m_dc, lbox->GetString(n), rect, flags);
739         }
740
741         rect.y += lineHeight;
742     }
743 }
744
745 #endif // wxUSE_LISTBOX
746
747 #if wxUSE_CHECKLISTBOX
748
749 void wxControlRenderer::DrawCheckItems(const wxCheckListBox *lbox,
750                                        size_t itemFirst, size_t itemLast)
751 {
752     DoDrawItems(lbox, itemFirst, itemLast, TRUE);
753 }
754
755 #endif // wxUSE_CHECKLISTBOX
756
757 #if wxUSE_GAUGE
758
759 void wxControlRenderer::DrawProgressBar(const wxGauge *gauge)
760 {
761     // draw background
762     m_dc.SetBrush(wxBrush(m_window->GetBackgroundColour(), wxSOLID));
763     m_dc.SetPen(*wxTRANSPARENT_PEN);
764     m_dc.DrawRectangle(m_rect);
765
766     int max = gauge->GetRange();
767     if ( !max )
768     {
769         // nothing to draw
770         return;
771     }
772
773     // calc the filled rect
774     int pos = gauge->GetValue();
775     int left = max - pos;
776
777     wxRect rect = m_rect;
778     rect.Deflate(1); // FIXME this depends on the border width
779
780     wxColour col = m_window->UseFgCol() ? m_window->GetForegroundColour()
781                                         : wxTHEME_COLOUR(GAUGE);
782     m_dc.SetBrush(wxBrush(col, wxSOLID));
783
784     if ( gauge->IsSmooth() )
785     {
786         // just draw the rectangle in one go
787         if ( gauge->IsVertical() )
788         {
789             // vert bars grow from bottom to top
790             wxCoord dy = ((rect.height - 1) * left) / max;
791             rect.y += dy;
792             rect.height -= dy;
793         }
794         else // horizontal
795         {
796             // grow from left to right
797             rect.width -= ((rect.width - 1) * left) / max;
798         }
799
800         m_dc.DrawRectangle(rect);
801     }
802     else // discrete
803     {
804         wxSize sizeStep = m_renderer->GetProgressBarStep();
805         int step = gauge->IsVertical() ? sizeStep.y : sizeStep.x;
806
807         // we divide by it below!
808         wxCHECK_RET( step, _T("invalid wxGauge step") );
809
810         // round up to make the progress appear to start faster
811         int lenTotal = gauge->IsVertical() ? rect.height : rect.width;
812         int steps = ((lenTotal + step - 1) * pos) / (max * step);
813
814         // calc the coords of one small rect
815         wxCoord *px, dx, dy;
816         if ( gauge->IsVertical() )
817         {
818             // draw from bottom to top: so first set y to the bottom
819             rect.y += rect.height - 1;
820
821             // then adjust the height
822             rect.height = step;
823
824             // and then adjust y again to be what it should for the first rect
825             rect.y -= rect.height;
826
827             // we are going up
828             step = -step;
829
830             // remember that this will be the coord which will change
831             px = &rect.y;
832
833             dy = 1;
834             dx = 0;
835         }
836         else // horizontal
837         {
838             // don't leave 2 empty pixels in the beginning
839             rect.x--;
840
841             px = &rect.x;
842             rect.width = step;
843
844             dy = 0;
845             dx = 1;
846         }
847
848         for ( int n = 0; n < steps; n++ )
849         {
850             wxRect rectSegment = rect;
851             rectSegment.Deflate(dx, dy);
852
853             m_dc.DrawRectangle(rectSegment);
854
855             *px += step;
856             if ( *px < 1 )
857             {
858                 // this can only happen for the last step of vertical gauge
859                 rect.height = *px - step - 1;
860                 *px = 1;
861             }
862             else if ( *px > lenTotal - step )
863             {
864                 // this can only happen for the last step of horizontal gauge
865                 rect.width = lenTotal - *px - 1;
866             }
867         }
868     }
869 }
870
871 #endif // wxUSE_GAUGE
872