]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/univ/themes/gtk.cpp
Add default constructor to wxGraphicsGradientStop.
[wxWidgets.git] / src / univ / themes / gtk.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/univ/themes/gtk.cpp
3// Purpose: wxUniversal theme implementing GTK-like LNF
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 06.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// for compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#include "wx/univ/theme.h"
28
29#if wxUSE_THEME_GTK
30
31#ifndef WX_PRECOMP
32 #include "wx/intl.h"
33 #include "wx/log.h"
34 #include "wx/dcmemory.h"
35 #include "wx/dcclient.h"
36 #include "wx/window.h"
37
38 #include "wx/menu.h"
39
40 #include "wx/bmpbuttn.h"
41 #include "wx/button.h"
42 #include "wx/checkbox.h"
43 #include "wx/listbox.h"
44 #include "wx/checklst.h"
45 #include "wx/combobox.h"
46 #include "wx/scrolbar.h"
47 #include "wx/slider.h"
48 #include "wx/textctrl.h"
49 #include "wx/toolbar.h"
50 #include "wx/statusbr.h"
51
52 #include "wx/settings.h"
53 #include "wx/toplevel.h"
54 #include "wx/image.h"
55#endif // WX_PRECOMP
56
57#include "wx/notebook.h"
58#include "wx/spinbutt.h"
59#include "wx/artprov.h"
60#ifdef wxUSE_TOGGLEBTN
61#include "wx/tglbtn.h"
62#endif // wxUSE_TOGGLEBTN
63
64#include "wx/univ/stdrend.h"
65#include "wx/univ/inpcons.h"
66#include "wx/univ/inphand.h"
67#include "wx/univ/colschem.h"
68
69class wxGTKMenuGeometryInfo;
70
71// ----------------------------------------------------------------------------
72// constants
73// ----------------------------------------------------------------------------
74
75// standard border size
76static const int BORDER_THICKNESS = 2;
77
78// ----------------------------------------------------------------------------
79// wxGTKRenderer: draw the GUI elements in GTK style
80// ----------------------------------------------------------------------------
81
82class wxGTKRenderer : public wxStdRenderer
83{
84public:
85 wxGTKRenderer(const wxColourScheme *scheme);
86
87 // wxRenderer methods
88 virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
89 virtual void DrawTextBorder(wxDC& dc,
90 wxBorder border,
91 const wxRect& rect,
92 int flags = 0,
93 wxRect *rectIn = NULL);
94 virtual void DrawButtonLabel(wxDC& dc,
95 const wxString& label,
96 const wxBitmap& image,
97 const wxRect& rect,
98 int flags,
99 int alignment,
100 int indexAccel,
101 wxRect *rectBounds);
102 virtual void DrawButtonBorder(wxDC& dc,
103 const wxRect& rect,
104 int flags = 0,
105 wxRect *rectIn = NULL);
106 virtual void DrawArrow(wxDC& dc,
107 wxDirection dir,
108 const wxRect& rect,
109 int flags = 0);
110 virtual void DrawScrollbarArrow(wxDC& dc,
111 wxDirection dir,
112 const wxRect& rect,
113 int flags = 0);
114 virtual void DrawScrollbarThumb(wxDC& dc,
115 wxOrientation orient,
116 const wxRect& rect,
117 int flags = 0);
118 virtual void DrawScrollbarShaft(wxDC& dc,
119 wxOrientation orient,
120 const wxRect& rect,
121 int flags = 0);
122
123#if wxUSE_TOOLBAR
124 virtual void DrawToolBarButton(wxDC& dc,
125 const wxString& label,
126 const wxBitmap& bitmap,
127 const wxRect& rect,
128 int flags = 0,
129 long style = 0,
130 int tbarStyle = 0);
131#endif // wxUSE_TOOLBAR
132
133#if wxUSE_TEXTCTRL
134 virtual void DrawLineWrapMark(wxDC& dc, const wxRect& rect);
135#endif // wxUSE_TEXTCTRL
136
137#if wxUSE_NOTEBOOK
138 virtual void DrawTab(wxDC& dc,
139 const wxRect& rect,
140 wxDirection dir,
141 const wxString& label,
142 const wxBitmap& bitmap = wxNullBitmap,
143 int flags = 0,
144 int indexAccel = -1);
145#endif // wxUSE_NOTEBOOK
146
147#if wxUSE_SLIDER
148 virtual void DrawSliderShaft(wxDC& dc,
149 const wxRect& rect,
150 int lenThumb,
151 wxOrientation orient,
152 int flags = 0,
153 long style = 0,
154 wxRect *rectShaft = NULL);
155 virtual void DrawSliderThumb(wxDC& dc,
156 const wxRect& rect,
157 wxOrientation orient,
158 int flags = 0,
159 long style = 0);
160 virtual void DrawSliderTicks(wxDC& WXUNUSED(dc),
161 const wxRect& WXUNUSED(rect),
162 int WXUNUSED(lenThumb),
163 wxOrientation WXUNUSED(orient),
164 int WXUNUSED(start),
165 int WXUNUSED(end),
166 int WXUNUSED(step) = 1,
167 int WXUNUSED(flags) = 0,
168 long WXUNUSED(style) = 0)
169 {
170 // we don't have the ticks in GTK version
171 }
172#endif // wxUSE_SLIDER
173
174#if wxUSE_MENUS
175 virtual void DrawMenuBarItem(wxDC& dc,
176 const wxRect& rect,
177 const wxString& label,
178 int flags = 0,
179 int indexAccel = -1);
180 virtual void DrawMenuItem(wxDC& dc,
181 wxCoord y,
182 const wxMenuGeometryInfo& geometryInfo,
183 const wxString& label,
184 const wxString& accel,
185 const wxBitmap& bitmap = wxNullBitmap,
186 int flags = 0,
187 int indexAccel = -1);
188 virtual void DrawMenuSeparator(wxDC& dc,
189 wxCoord y,
190 const wxMenuGeometryInfo& geomInfo);
191#endif // wxUSE_MENUS
192
193 virtual void GetComboBitmaps(wxBitmap *bmpNormal,
194 wxBitmap *bmpFocus,
195 wxBitmap *bmpPressed,
196 wxBitmap *bmpDisabled);
197
198 virtual void AdjustSize(wxSize *size, const wxWindow *window);
199
200 // geometry and hit testing
201#if wxUSE_SCROLLBAR
202 virtual wxSize GetScrollbarArrowSize() const
203 { return m_sizeScrollbarArrow; }
204#endif // wxUSE_SCROLLBAR
205
206 virtual wxSize GetCheckBitmapSize() const
207 { return wxSize(10, 10); }
208 virtual wxSize GetRadioBitmapSize() const
209 { return wxSize(11, 11); }
210 virtual wxCoord GetCheckItemMargin() const
211 { return 2; }
212
213#if wxUSE_TOOLBAR
214 virtual wxSize GetToolBarButtonSize(wxCoord *separator) const
215 { if ( separator ) *separator = 5; return wxSize(16, 15); }
216 virtual wxSize GetToolBarMargin() const
217 { return wxSize(6, 6); }
218#endif // wxUSE_TOOLBAR
219
220#if wxUSE_TEXTCTRL
221 virtual wxRect GetTextClientArea(const wxTextCtrl *text,
222 const wxRect& rect,
223 wxCoord *extraSpaceBeyond) const;
224#endif // wxUSE_TEXTCTRL
225
226#if wxUSE_NOTEBOOK
227 virtual wxSize GetTabIndent() const { return wxSize(2, 2); }
228 virtual wxSize GetTabPadding() const { return wxSize(6, 6); }
229#endif // wxUSE_NOTEBOOK
230
231#if wxUSE_SLIDER
232 virtual wxCoord GetSliderDim() const { return 15; }
233 virtual wxCoord GetSliderTickLen() const { return 0; }
234 virtual wxRect GetSliderShaftRect(const wxRect& rect,
235 int lenThumb,
236 wxOrientation orient,
237 long style = 0) const;
238 virtual wxSize GetSliderThumbSize(const wxRect& rect,
239 int lenThumb,
240 wxOrientation orient) const;
241#endif // wxUSE_SLIDER
242
243 virtual wxSize GetProgressBarStep() const { return wxSize(16, 32); }
244
245#if wxUSE_MENUS
246 virtual wxSize GetMenuBarItemSize(const wxSize& sizeText) const;
247 virtual wxMenuGeometryInfo *GetMenuGeometry(wxWindow *win,
248 const wxMenu& menu) const;
249#endif // wxUSE_MENUS
250
251 // helpers for "wxBitmap wxColourScheme::Get()"
252 void DrawCheckBitmap(wxDC& dc, const wxRect& rect);
253 void DrawUncheckBitmap(wxDC& dc, const wxRect& rect, bool isPressed);
254 void DrawUndeterminedBitmap(wxDC& dc, const wxRect& rect, bool isPressed);
255
256protected:
257 // overridden wxStdRenderer methods
258 virtual void DrawSunkenBorder(wxDC& dc, wxRect *rect);
259
260 virtual void DrawFrameWithLabel(wxDC& dc,
261 const wxString& label,
262 const wxRect& rectFrame,
263 const wxRect& rectText,
264 int flags,
265 int alignment,
266 int indexAccel);
267
268 virtual void DrawCheckItemBitmap(wxDC& dc,
269 const wxBitmap& bitmap,
270 const wxRect& rect,
271 int flags);
272
273 // get the colour to use for background
274 wxColour GetBackgroundColour(int flags) const
275 {
276 if ( flags & wxCONTROL_PRESSED )
277 return wxSCHEME_COLOUR(m_scheme, CONTROL_PRESSED);
278 else if ( flags & wxCONTROL_CURRENT )
279 return wxSCHEME_COLOUR(m_scheme, CONTROL_CURRENT);
280 else
281 return wxSCHEME_COLOUR(m_scheme, CONTROL);
282 }
283
284 // as DrawShadedRect() but the pixels in the bottom left and upper right
285 // border are drawn with the pen1, not pen2
286 void DrawAntiShadedRect(wxDC& dc, wxRect *rect,
287 const wxPen& pen1, const wxPen& pen2);
288
289 // used for drawing opened rectangles - draws only one side of it at once
290 // (and doesn't adjust the rect)
291 void DrawAntiShadedRectSide(wxDC& dc,
292 const wxRect& rect,
293 const wxPen& pen1,
294 const wxPen& pen2,
295 wxDirection dir);
296
297 // draw an opened rect for the arrow in given direction
298 void DrawArrowBorder(wxDC& dc,
299 wxRect *rect,
300 wxDirection dir);
301
302 // draw two sides of the rectangle
303 void DrawThumbBorder(wxDC& dc,
304 wxRect *rect,
305 wxOrientation orient);
306
307 // just as DrawRaisedBorder() except that the bottom left and up right
308 // pixels of the interior rect are drawn in another colour (i.e. the inner
309 // rect is drawn with DrawAntiShadedRect() and not DrawShadedRect())
310 void DrawAntiRaisedBorder(wxDC& dc, wxRect *rect);
311
312 // draw inner GTK shadow
313 void DrawInnerShadedRect(wxDC& dc, wxRect *rect);
314
315 // get the line wrap indicator bitmap
316 wxBitmap GetLineWrapBitmap() const;
317
318 virtual wxBitmap GetCheckBitmap(int flags);
319 virtual wxBitmap GetRadioBitmap(int flags);
320
321 // draw a /\ or \/ line from (x1, y1) to (x2, y1) passing by the point
322 // ((x1 + x2)/2, y2)
323 void DrawUpZag(wxDC& dc,
324 wxCoord x1, wxCoord x2,
325 wxCoord y1, wxCoord y2);
326 void DrawDownZag(wxDC& dc,
327 wxCoord x1, wxCoord x2,
328 wxCoord y1, wxCoord y2);
329
330 // draw the radio button bitmap for the given state
331 void DrawRadioButtonBitmap(wxDC& dc, const wxRect& rect, int flags);
332
333 // common part of DrawMenuItem() and DrawMenuBarItem()
334 void DoDrawMenuItem(wxDC& dc,
335 const wxRect& rect,
336 const wxString& label,
337 int flags,
338 int indexAccel,
339 const wxString& accel = wxEmptyString,
340 const wxBitmap& bitmap = wxNullBitmap,
341 const wxGTKMenuGeometryInfo *geometryInfo = NULL);
342
343 // initialize the combo bitmaps
344 void InitComboBitmaps();
345
346 virtual wxBitmap GetFrameButtonBitmap(FrameButtonType WXUNUSED(type))
347 {
348 return wxNullBitmap;
349 }
350
351private:
352 // data
353 wxSize m_sizeScrollbarArrow;
354
355 // GDI objects
356 wxPen m_penGrey;
357
358 // the checkbox and radio button bitmaps: first row is for the normal,
359 // second for the pressed state and the columns are for checked, unchecked
360 // and undeterminated respectively
361 wxBitmap m_bitmapsCheckbox[IndicatorState_MaxCtrl][IndicatorStatus_Max],
362 m_bitmapsRadiobtn[IndicatorState_MaxCtrl][IndicatorStatus_Max];
363
364 // the line wrap bitmap (drawn at the end of wrapped lines)
365 wxBitmap m_bmpLineWrap;
366
367 // the combobox bitmaps
368 enum
369 {
370 ComboState_Normal,
371 ComboState_Focus,
372 ComboState_Pressed,
373 ComboState_Disabled,
374 ComboState_Max
375 };
376
377 wxBitmap m_bitmapsCombo[ComboState_Max];
378};
379
380// ----------------------------------------------------------------------------
381// wxGTKInputHandler and derived classes: process the keyboard and mouse
382// messages according to GTK standards
383// ----------------------------------------------------------------------------
384
385class wxGTKInputHandler : public wxInputHandler
386{
387public:
388 wxGTKInputHandler() { }
389
390 virtual bool HandleKey(wxInputConsumer *control,
391 const wxKeyEvent& event,
392 bool pressed);
393 virtual bool HandleMouse(wxInputConsumer *control,
394 const wxMouseEvent& event);
395 virtual bool HandleMouseMove(wxInputConsumer *control,
396 const wxMouseEvent& event);
397};
398
399#if wxUSE_SCROLLBAR
400
401class wxGTKScrollBarInputHandler : public wxStdScrollBarInputHandler
402{
403public:
404 wxGTKScrollBarInputHandler(wxRenderer *renderer, wxInputHandler *handler)
405 : wxStdScrollBarInputHandler(renderer, handler) { }
406
407protected:
408 virtual void Highlight(wxScrollBar *scrollbar, bool doIt)
409 {
410 // only arrows and the thumb can be highlighted
411 if ( !IsArrow() && m_htLast != wxHT_SCROLLBAR_THUMB )
412 return;
413
414 wxStdScrollBarInputHandler::Highlight(scrollbar, doIt);
415 }
416
417 virtual void Press(wxScrollBar *scrollbar, bool doIt)
418 {
419 // only arrows can be pressed
420 if ( !IsArrow() )
421 return;
422
423 wxStdScrollBarInputHandler::Press(scrollbar, doIt);
424 }
425
426 // any button can be used to drag the scrollbar under GTK+
427 virtual bool IsAllowedButton(int WXUNUSED(button)) const { return true; }
428
429 bool IsArrow() const
430 {
431 return m_htLast == wxHT_SCROLLBAR_ARROW_LINE_1 ||
432 m_htLast == wxHT_SCROLLBAR_ARROW_LINE_2;
433 }
434};
435
436#endif // wxUSE_SCROLLBAR
437
438#if wxUSE_CHECKBOX
439
440class wxGTKCheckboxInputHandler : public wxStdInputHandler
441{
442public:
443 wxGTKCheckboxInputHandler(wxInputHandler *handler)
444 : wxStdInputHandler(handler) { }
445
446 virtual bool HandleKey(wxInputConsumer *control,
447 const wxKeyEvent& event,
448 bool pressed);
449};
450
451#endif // wxUSE_CHECKBOX
452
453#if wxUSE_TEXTCTRL
454
455class wxGTKTextCtrlInputHandler : public wxStdInputHandler
456{
457public:
458 wxGTKTextCtrlInputHandler(wxInputHandler *handler)
459 : wxStdInputHandler(handler) { }
460
461 virtual bool HandleKey(wxInputConsumer *control,
462 const wxKeyEvent& event,
463 bool pressed);
464};
465
466#endif // wxUSE_TEXTCTRL
467
468// ----------------------------------------------------------------------------
469// wxGTKColourScheme: uses the standard GTK colours
470// ----------------------------------------------------------------------------
471
472class wxGTKColourScheme : public wxColourScheme
473{
474public:
475 virtual wxColour Get(StdColour col) const;
476 virtual wxColour GetBackground(wxWindow *win) const;
477};
478
479// ----------------------------------------------------------------------------
480// wxGTKArtProvider
481// ----------------------------------------------------------------------------
482
483class wxGTKArtProvider : public wxArtProvider
484{
485protected:
486 virtual wxBitmap CreateBitmap(const wxArtID& id,
487 const wxArtClient& client,
488 const wxSize& size);
489};
490
491// ----------------------------------------------------------------------------
492// wxGTKTheme
493// ----------------------------------------------------------------------------
494
495WX_DEFINE_ARRAY_PTR(wxInputHandler *, wxArrayHandlers);
496
497class wxGTKTheme : public wxTheme
498{
499public:
500 wxGTKTheme();
501 virtual ~wxGTKTheme();
502
503 virtual wxRenderer *GetRenderer();
504 virtual wxArtProvider *GetArtProvider();
505 virtual wxInputHandler *GetInputHandler(const wxString& control,
506 wxInputConsumer *consumer);
507 virtual wxColourScheme *GetColourScheme();
508
509private:
510 wxGTKRenderer *m_renderer;
511
512 wxGTKArtProvider *m_artProvider;
513
514 // the names of the already created handlers and the handlers themselves
515 // (these arrays are synchronized)
516 wxSortedArrayString m_handlerNames;
517 wxArrayHandlers m_handlers;
518
519 wxGTKColourScheme *m_scheme;
520
521 WX_DECLARE_THEME(gtk)
522};
523
524// ============================================================================
525// implementation
526// ============================================================================
527
528WX_IMPLEMENT_THEME(wxGTKTheme, gtk, wxTRANSLATE("GTK+ theme"));
529
530// ----------------------------------------------------------------------------
531// wxGTKTheme
532// ----------------------------------------------------------------------------
533
534wxGTKTheme::wxGTKTheme()
535{
536 m_scheme = NULL;
537 m_renderer = NULL;
538 m_artProvider = NULL;
539}
540
541wxGTKTheme::~wxGTKTheme()
542{
543 delete m_renderer;
544 delete m_scheme;
545 delete m_artProvider;
546}
547
548wxRenderer *wxGTKTheme::GetRenderer()
549{
550 if ( !m_renderer )
551 {
552 m_renderer = new wxGTKRenderer(GetColourScheme());
553 }
554
555 return m_renderer;
556}
557
558wxArtProvider *wxGTKTheme::GetArtProvider()
559{
560 if ( !m_artProvider )
561 {
562 m_artProvider = new wxGTKArtProvider;
563 }
564
565 return m_artProvider;
566}
567
568wxColourScheme *wxGTKTheme::GetColourScheme()
569{
570 if ( !m_scheme )
571 {
572 m_scheme = new wxGTKColourScheme;
573 }
574 return m_scheme;
575}
576
577wxInputHandler *wxGTKTheme::GetInputHandler(const wxString& control,
578 wxInputConsumer *consumer)
579{
580 wxInputHandler *handler = NULL;
581 int n = m_handlerNames.Index(control);
582 if ( n == wxNOT_FOUND )
583 {
584 static wxGTKInputHandler s_handlerDef;
585
586 wxInputHandler * const
587 handlerStd = consumer->DoGetStdInputHandler(&s_handlerDef);
588
589 // create a new handler
590#if wxUSE_CHECKBOX
591 if ( control == wxINP_HANDLER_CHECKBOX )
592 {
593 static wxGTKCheckboxInputHandler s_handler(handlerStd);
594
595 handler = &s_handler;
596 }
597 else
598#endif // wxUSE_CHECKBOX
599#if wxUSE_SCROLLBAR
600 if ( control == wxINP_HANDLER_SCROLLBAR )
601 {
602 static wxGTKScrollBarInputHandler s_handler(m_renderer, handlerStd);
603
604 handler = &s_handler;
605 }
606 else
607#endif // wxUSE_SCROLLBAR
608#if wxUSE_TEXTCTRL
609 if ( control == wxINP_HANDLER_TEXTCTRL )
610 {
611 static wxGTKTextCtrlInputHandler s_handler(handlerStd);
612
613 handler = &s_handler;
614 }
615 else
616#endif // wxUSE_TEXTCTRL
617 {
618 // no special handler for this control
619 handler = handlerStd;
620 }
621
622 n = m_handlerNames.Add(control);
623 m_handlers.Insert(handler, n);
624 }
625 else // we already have it
626 {
627 handler = m_handlers[n];
628 }
629
630 return handler;
631}
632
633// ============================================================================
634// wxGTKColourScheme
635// ============================================================================
636
637wxColour wxGTKColourScheme::GetBackground(wxWindow *win) const
638{
639 wxColour col;
640 if ( win->UseBgCol() )
641 {
642 // use the user specified colour
643 col = win->GetBackgroundColour();
644 }
645
646 if ( !win->ShouldInheritColours() )
647 {
648 // doesn't depend on the state
649 if ( !col.Ok() )
650 {
651 col = Get(WINDOW);
652 }
653 }
654 else
655 {
656 int flags = win->GetStateFlags();
657
658 // the colour set by the user should be used for the normal state
659 // and for the states for which we don't have any specific colours
660 if ( !col.Ok() || (flags != 0) )
661 {
662#if wxUSE_SCROLLBAR
663 if ( wxDynamicCast(win, wxScrollBar) )
664 col = Get(SCROLLBAR);
665 else
666#endif //wxUSE_SCROLLBAR
667 if ( (flags & wxCONTROL_CURRENT) && win->CanBeHighlighted() )
668 col = Get(CONTROL_CURRENT);
669 else if ( flags & wxCONTROL_PRESSED )
670 col = Get(CONTROL_PRESSED);
671 else
672 col = Get(CONTROL);
673 }
674 }
675
676 return col;
677}
678
679wxColour wxGTKColourScheme::Get(wxGTKColourScheme::StdColour col) const
680{
681 switch ( col )
682 {
683 case FRAME:
684 case WINDOW: return *wxWHITE;
685
686 case SHADOW_DARK: return *wxBLACK;
687 case SHADOW_HIGHLIGHT: return *wxWHITE;
688 case SHADOW_IN: return wxColour(0xd6d6d6);
689 case SHADOW_OUT: return wxColour(0x969696);
690
691 case CONTROL: return wxColour(0xd6d6d6);
692 case CONTROL_PRESSED: return wxColour(0xc3c3c3);
693 case CONTROL_CURRENT: return wxColour(0xeaeaea);
694
695 case CONTROL_TEXT: return *wxBLACK;
696 case CONTROL_TEXT_DISABLED:
697 return wxColour(0x757575);
698 case CONTROL_TEXT_DISABLED_SHADOW:
699 return *wxWHITE;
700
701 case SCROLLBAR:
702 case SCROLLBAR_PRESSED: return wxColour(0xc3c3c3);
703
704 case HIGHLIGHT: return wxColour(0x9c0000);
705 case HIGHLIGHT_TEXT: return wxColour(0xffffff);
706
707 case GAUGE: return Get(CONTROL_CURRENT);
708
709 case TITLEBAR: return wxColour(0xaeaaae);
710 case TITLEBAR_ACTIVE: return wxColour(0x820300);
711 case TITLEBAR_TEXT: return wxColour(0xc0c0c0);
712 case TITLEBAR_ACTIVE_TEXT:
713 return *wxWHITE;
714
715 case DESKTOP: return *wxBLACK;
716
717 case MAX:
718 default:
719 wxFAIL_MSG(wxT("invalid standard colour"));
720 return *wxBLACK;
721 }
722}
723
724// ============================================================================
725// wxGTKRenderer
726// ============================================================================
727
728// ----------------------------------------------------------------------------
729// construction
730// ----------------------------------------------------------------------------
731
732wxGTKRenderer::wxGTKRenderer(const wxColourScheme *scheme)
733 : wxStdRenderer(scheme)
734{
735 m_sizeScrollbarArrow = wxSize(15, 14);
736
737 m_penGrey = wxPen(wxSCHEME_COLOUR(scheme, SCROLLBAR));
738}
739
740// ----------------------------------------------------------------------------
741// border stuff
742// ----------------------------------------------------------------------------
743
744void wxGTKRenderer::DrawAntiShadedRectSide(wxDC& dc,
745 const wxRect& rect,
746 const wxPen& pen1,
747 const wxPen& pen2,
748 wxDirection dir)
749{
750 dc.SetPen(dir == wxLEFT || dir == wxUP ? pen1 : pen2);
751
752 switch ( dir )
753 {
754 case wxLEFT:
755 dc.DrawLine(rect.GetLeft(), rect.GetTop(),
756 rect.GetLeft(), rect.GetBottom() + 1);
757 break;
758
759 case wxUP:
760 dc.DrawLine(rect.GetLeft(), rect.GetTop(),
761 rect.GetRight() + 1, rect.GetTop());
762 break;
763
764 case wxRIGHT:
765 dc.DrawLine(rect.GetRight(), rect.GetTop(),
766 rect.GetRight(), rect.GetBottom() + 1);
767 break;
768
769 case wxDOWN:
770 dc.DrawLine(rect.GetLeft(), rect.GetBottom(),
771 rect.GetRight() + 1, rect.GetBottom());
772 break;
773
774 default:
775 wxFAIL_MSG(wxT("unknown rectangle side"));
776 }
777}
778
779void wxGTKRenderer::DrawAntiShadedRect(wxDC& dc, wxRect *rect,
780 const wxPen& pen1, const wxPen& pen2)
781{
782 // draw the rectangle
783 dc.SetPen(pen1);
784 dc.DrawLine(rect->GetLeft(), rect->GetTop(),
785 rect->GetLeft(), rect->GetBottom() + 1);
786 dc.DrawLine(rect->GetLeft() + 1, rect->GetTop(),
787 rect->GetRight() + 1, rect->GetTop());
788 dc.SetPen(pen2);
789 dc.DrawLine(rect->GetRight(), rect->GetTop() + 1,
790 rect->GetRight(), rect->GetBottom());
791 dc.DrawLine(rect->GetLeft() + 1, rect->GetBottom(),
792 rect->GetRight() + 1, rect->GetBottom());
793
794 // adjust the rect
795 rect->Inflate(-1);
796}
797
798void wxGTKRenderer::DrawInnerShadedRect(wxDC& dc, wxRect *rect)
799{
800 DrawAntiShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
801 DrawAntiShadedRect(dc, rect, m_penBlack, m_penHighlight);
802}
803
804void wxGTKRenderer::DrawAntiRaisedBorder(wxDC& dc, wxRect *rect)
805{
806 DrawShadedRect(dc, rect, m_penHighlight, m_penBlack);
807 DrawAntiShadedRect(dc, rect, m_penLightGrey, m_penDarkGrey);
808}
809
810void wxGTKRenderer::DrawSunkenBorder(wxDC& dc, wxRect *rect)
811{
812 DrawAntiShadedRect(dc, rect, m_penDarkGrey, m_penHighlight);
813 DrawShadedRect(dc, rect, m_penBlack, m_penLightGrey);
814}
815
816void
817wxGTKRenderer::DrawFocusRect(wxWindow* WXUNUSED(win), wxDC& dc, const wxRect& rect, int WXUNUSED(flags))
818{
819 dc.SetBrush(*wxTRANSPARENT_BRUSH);
820 wxRect rectFocus = rect;
821 DrawRect(dc, &rectFocus, m_penBlack);
822}
823
824void wxGTKRenderer::DrawTextBorder(wxDC& dc,
825 wxBorder border,
826 const wxRect& rectOrig,
827 int flags,
828 wxRect *rectIn)
829{
830 wxRect rect = rectOrig;
831
832 if ( border != wxBORDER_NONE )
833 {
834 if ( flags & wxCONTROL_FOCUSED )
835 {
836 DrawRect(dc, &rect, m_penBlack);
837 DrawAntiShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
838 }
839 else // !focused
840 {
841 DrawInnerShadedRect(dc, &rect);
842 }
843 }
844
845 if ( rectIn )
846 *rectIn = rect;
847}
848
849void wxGTKRenderer::DrawButtonLabel(wxDC& dc,
850 const wxString& label,
851 const wxBitmap& image,
852 const wxRect& rect,
853 int flags,
854 int alignment,
855 int indexAccel,
856 wxRect *rectBounds)
857{
858 // no focus rect around buttons label in GTK+
859 wxStdRenderer::DrawButtonLabel(dc, label, image, rect, flags,
860 alignment, indexAccel, rectBounds);
861}
862
863void wxGTKRenderer::DrawButtonBorder(wxDC& dc,
864 const wxRect& rectTotal,
865 int flags,
866 wxRect *rectIn)
867{
868 wxRect rect = rectTotal;
869
870 if ( flags & wxCONTROL_PRESSED )
871 {
872 // button pressed: draw a black border around it and an inward shade
873 DrawRect(dc, &rect, m_penBlack);
874
875 DrawInnerShadedRect(dc, &rect);
876 }
877 else // button not pressed
878 {
879 if ( flags & wxCONTROL_ISDEFAULT )
880 {
881 // TODO
882 }
883
884 if ( flags & wxCONTROL_FOCUSED )
885 {
886 // button is currently default: add an extra border around it
887 DrawRect(dc, &rect, m_penBlack);
888 }
889
890 // now draw a normal button
891 DrawShadedRect(dc, &rect, m_penHighlight, m_penBlack);
892 DrawAntiShadedRect(dc, &rect, GetBackgroundColour(flags), m_penDarkGrey);
893 }
894
895 if ( rectIn )
896 *rectIn = rect;
897}
898
899// ----------------------------------------------------------------------------
900// lines and frames
901// ----------------------------------------------------------------------------
902
903void wxGTKRenderer::DrawFrameWithLabel(wxDC& dc,
904 const wxString& label,
905 const wxRect& rectFrame,
906 const wxRect& rectTextOrig,
907 int flags,
908 int alignment,
909 int indexAccel)
910{
911 wxRect rectText(rectTextOrig);
912 rectText.Inflate(1, 0);
913
914 wxRect rectLabel;
915 DrawLabel(dc, label, rectText, flags, alignment, indexAccel, &rectLabel);
916 rectLabel.x -= 1;
917 rectLabel.width += 2;
918
919 DrawFrameWithoutLabel(dc, rectFrame, rectLabel);
920
921 // GTK+ does it like this
922 dc.SetPen(m_penHighlight);
923 dc.DrawPoint(rectText.x, rectFrame.y);
924 dc.DrawPoint(rectText.x + rectLabel.width - 3, rectFrame.y);
925}
926
927// ----------------------------------------------------------------------------
928// check/radio buttons
929// ----------------------------------------------------------------------------
930
931void wxGTKRenderer::DrawCheckItemBitmap(wxDC& dc,
932 const wxBitmap& bitmap,
933 const wxRect& rect,
934 int flags)
935{
936 // never draw the focus rect around the check indicators here
937 DrawCheckButton(dc, wxEmptyString, bitmap, rect, flags & ~wxCONTROL_FOCUSED);
938}
939
940void wxGTKRenderer::DrawUndeterminedBitmap(wxDC& dc,
941 const wxRect& rectTotal,
942 bool isPressed)
943{
944 // FIXME: For sure it is not GTK look but it is better than nothing.
945 // Show me correct look and I will immediatelly make it better (ABX)
946 wxRect rect = rectTotal;
947
948 wxColour col1, col2;
949
950 if ( isPressed )
951 {
952 col1 = wxSCHEME_COLOUR(m_scheme, SHADOW_DARK);
953 col2 = wxSCHEME_COLOUR(m_scheme, CONTROL_PRESSED);
954 }
955 else
956 {
957 col1 = wxSCHEME_COLOUR(m_scheme, SHADOW_DARK);
958 col2 = wxSCHEME_COLOUR(m_scheme, SHADOW_IN);
959 }
960
961 dc.SetPen(*wxTRANSPARENT_PEN);
962 dc.SetBrush(col1);
963 dc.DrawRectangle(rect);
964 rect.Deflate(1);
965 dc.SetBrush(col2);
966 dc.DrawRectangle(rect);
967}
968
969void wxGTKRenderer::DrawUncheckBitmap(wxDC& dc,
970 const wxRect& rectTotal,
971 bool isPressed)
972{
973 wxRect rect = rectTotal;
974 DrawAntiRaisedBorder(dc, &rect);
975
976 wxColour col = wxSCHEME_COLOUR(m_scheme, SHADOW_IN);
977 dc.SetPen(wxPen(col));
978 dc.DrawPoint(rect.GetRight() - 1, rect.GetBottom() - 1);
979
980 if ( isPressed )
981 col = wxSCHEME_COLOUR(m_scheme, CONTROL_PRESSED);
982 //else: it is SHADOW_IN, leave as is
983
984 dc.SetPen(*wxTRANSPARENT_PEN);
985 dc.SetBrush(col);
986 dc.DrawRectangle(rect);
987}
988
989void wxGTKRenderer::DrawCheckBitmap(wxDC& dc, const wxRect& rectTotal)
990{
991 wxRect rect = rectTotal;
992 DrawAntiShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
993 DrawShadedRect(dc, &rect, m_penBlack, m_penLightGrey);
994
995 dc.SetPen(*wxTRANSPARENT_PEN);
996 dc.SetBrush(wxSCHEME_COLOUR(m_scheme, CONTROL_PRESSED));
997 dc.DrawRectangle(rect);
998}
999
1000void wxGTKRenderer::DrawRadioButtonBitmap(wxDC& dc,
1001 const wxRect& rect,
1002 int flags)
1003{
1004 wxCoord x = rect.x,
1005 y = rect.y,
1006 xRight = rect.GetRight(),
1007 yBottom = rect.GetBottom();
1008
1009 wxCoord yMid = (y + yBottom) / 2;
1010
1011 // then draw the upper half
1012 dc.SetPen(flags & wxCONTROL_CHECKED ? m_penDarkGrey : m_penHighlight);
1013 DrawUpZag(dc, x, xRight, yMid, y);
1014 DrawUpZag(dc, x + 1, xRight - 1, yMid, y + 1);
1015
1016 bool drawIt = true;
1017 if ( flags & wxCONTROL_CHECKED )
1018 dc.SetPen(m_penBlack);
1019 else if ( flags & wxCONTROL_PRESSED )
1020 dc.SetPen(wxPen(wxSCHEME_COLOUR(m_scheme, CONTROL_PRESSED)));
1021 else // unchecked and unpressed
1022 drawIt = false;
1023
1024 if ( drawIt )
1025 DrawUpZag(dc, x + 2, xRight - 2, yMid, y + 2);
1026
1027 // and then the lower one
1028 dc.SetPen(flags & wxCONTROL_CHECKED ? m_penHighlight : m_penBlack);
1029 DrawDownZag(dc, x, xRight, yMid, yBottom);
1030 if ( !(flags & wxCONTROL_CHECKED) )
1031 dc.SetPen(m_penDarkGrey);
1032 DrawDownZag(dc, x + 1, xRight - 1, yMid, yBottom - 1);
1033
1034 if ( !(flags & wxCONTROL_CHECKED) )
1035 drawIt = true; // with the same pen
1036 else if ( flags & wxCONTROL_PRESSED )
1037 {
1038 dc.SetPen(wxPen(wxSCHEME_COLOUR(m_scheme, CONTROL_PRESSED)));
1039 drawIt = true;
1040 }
1041 else // checked and unpressed
1042 drawIt = false;
1043
1044 if ( drawIt )
1045 DrawDownZag(dc, x + 2, xRight - 2, yMid, yBottom - 2);
1046}
1047
1048void wxGTKRenderer::DrawUpZag(wxDC& dc,
1049 wxCoord x1,
1050 wxCoord x2,
1051 wxCoord y1,
1052 wxCoord y2)
1053{
1054 wxCoord xMid = (x1 + x2) / 2;
1055 dc.DrawLine(x1, y1, xMid, y2);
1056 dc.DrawLine(xMid, y2, x2 + 1, y1 + 1);
1057}
1058
1059void wxGTKRenderer::DrawDownZag(wxDC& dc,
1060 wxCoord x1,
1061 wxCoord x2,
1062 wxCoord y1,
1063 wxCoord y2)
1064{
1065 wxCoord xMid = (x1 + x2) / 2;
1066 dc.DrawLine(x1 + 1, y1 + 1, xMid, y2);
1067 dc.DrawLine(xMid, y2, x2, y1);
1068}
1069
1070wxBitmap wxGTKRenderer::GetCheckBitmap(int flags)
1071{
1072 if ( !m_bitmapsCheckbox[0][0].Ok() )
1073 {
1074 // init the bitmaps once only
1075 wxRect rect;
1076 wxSize size = GetCheckBitmapSize();
1077 rect.width = size.x;
1078 rect.height = size.y;
1079 for ( int i = 0; i < 2; i++ )
1080 {
1081 for ( int j = 0; j < 3; j++ )
1082 m_bitmapsCheckbox[i][j].Create(rect.width, rect.height);
1083 }
1084
1085 wxMemoryDC dc;
1086
1087 // normal checked
1088 dc.SelectObject(m_bitmapsCheckbox[0][0]);
1089 DrawCheckBitmap(dc, rect);
1090
1091 // normal unchecked
1092 dc.SelectObject(m_bitmapsCheckbox[0][1]);
1093 DrawUncheckBitmap(dc, rect, false);
1094
1095 // normal undeterminated
1096 dc.SelectObject(m_bitmapsCheckbox[0][2]);
1097 DrawUndeterminedBitmap(dc, rect, false);
1098
1099 // pressed checked
1100 m_bitmapsCheckbox[1][0] = m_bitmapsCheckbox[0][0];
1101
1102 // pressed unchecked
1103 dc.SelectObject(m_bitmapsCheckbox[1][1]);
1104 DrawUncheckBitmap(dc, rect, true);
1105
1106 // pressed undeterminated
1107 dc.SelectObject(m_bitmapsCheckbox[1][2]);
1108 DrawUndeterminedBitmap(dc, rect, true);
1109 }
1110
1111 IndicatorState state;
1112 IndicatorStatus status;
1113 GetIndicatorsFromFlags(flags, state, status);
1114
1115 // disabled looks the same as normal
1116 if ( state == IndicatorState_Disabled )
1117 state = IndicatorState_Normal;
1118
1119 return m_bitmapsCheckbox[state][status];
1120}
1121
1122wxBitmap wxGTKRenderer::GetRadioBitmap(int flags)
1123{
1124 IndicatorState state;
1125 IndicatorStatus status;
1126 GetIndicatorsFromFlags(flags, state, status);
1127
1128 wxBitmap& bmp = m_bitmapsRadiobtn[state][status];
1129 if ( !bmp.Ok() )
1130 {
1131 const wxSize size = GetRadioBitmapSize();
1132
1133 wxMemoryDC dc;
1134 bmp.Create(size.x, size.y);
1135 dc.SelectObject(bmp);
1136
1137 DrawRadioButtonBitmap(dc, size, flags);
1138 }
1139
1140 return bmp;
1141}
1142
1143wxBitmap wxGTKRenderer::GetLineWrapBitmap() const
1144{
1145 if ( !m_bmpLineWrap.Ok() )
1146 {
1147 // the line wrap bitmap as used by GTK+
1148 #define line_wrap_width 6
1149 #define line_wrap_height 9
1150 static const char line_wrap_bits[] =
1151 {
1152 0x1e, 0x3e, 0x30, 0x30, 0x39, 0x1f, 0x0f, 0x0f, 0x1f,
1153 };
1154
1155 wxBitmap bmpLineWrap(line_wrap_bits, line_wrap_width, line_wrap_height);
1156 if ( !bmpLineWrap.Ok() )
1157 {
1158 wxFAIL_MSG( wxT("Failed to create line wrap XBM") );
1159 }
1160 else
1161 {
1162 wxConstCast(this, wxGTKRenderer)->m_bmpLineWrap = bmpLineWrap;
1163 }
1164 }
1165
1166 return m_bmpLineWrap;
1167}
1168
1169#if wxUSE_TOOLBAR
1170void wxGTKRenderer::DrawToolBarButton(wxDC& dc,
1171 const wxString& label,
1172 const wxBitmap& bitmap,
1173 const wxRect& rectOrig,
1174 int flags,
1175 long WXUNUSED(style),
1176 int tbarStyle)
1177{
1178 // we don't draw the separators at all
1179 if ( !label.empty() || bitmap.Ok() )
1180 {
1181 wxRect rect = rectOrig;
1182 rect.Deflate(BORDER_THICKNESS);
1183
1184 if ( flags & wxCONTROL_PRESSED )
1185 {
1186 DrawBorder(dc, wxBORDER_SUNKEN, rect, flags, &rect);
1187
1188 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL_PRESSED), rect);
1189 }
1190 else if ( flags & wxCONTROL_CURRENT )
1191 {
1192 DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rect);
1193
1194 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL_CURRENT), rect);
1195 }
1196
1197 if(tbarStyle & wxTB_TEXT)
1198 {
1199 if(tbarStyle & wxTB_HORIZONTAL)
1200 {
1201 dc.DrawLabel(label, bitmap, rect, wxALIGN_CENTRE);
1202 }
1203 else
1204 {
1205 dc.DrawLabel(label, bitmap, rect, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL);
1206 }
1207 }
1208 else
1209 {
1210 int xpoint = (rect.GetLeft() + rect.GetRight() + 1 - bitmap.GetWidth()) / 2;
1211 int ypoint = (rect.GetTop() + rect.GetBottom() + 1 - bitmap.GetHeight()) / 2;
1212 dc.DrawBitmap(bitmap, xpoint, ypoint);
1213 }
1214 }
1215}
1216#endif // wxUSE_TOOLBAR
1217
1218// ----------------------------------------------------------------------------
1219// text control
1220// ----------------------------------------------------------------------------
1221
1222#if wxUSE_TEXTCTRL
1223
1224wxRect wxGTKRenderer::GetTextClientArea(const wxTextCtrl *text,
1225 const wxRect& rect,
1226 wxCoord *extraSpaceBeyond) const
1227{
1228 wxRect
1229 rectText = wxStdRenderer::GetTextClientArea(text, rect, extraSpaceBeyond);
1230
1231 if ( text->WrapLines() )
1232 {
1233 // leave enough for the line wrap bitmap indicator
1234 wxCoord widthMark = GetLineWrapBitmap().GetWidth() + 2;
1235
1236 rectText.width -= widthMark;
1237
1238 if ( extraSpaceBeyond )
1239 *extraSpaceBeyond = widthMark;
1240 }
1241
1242 return rectText;
1243}
1244
1245void wxGTKRenderer::DrawLineWrapMark(wxDC& dc, const wxRect& rect)
1246{
1247 wxBitmap bmpLineWrap = GetLineWrapBitmap();
1248
1249 // for a mono bitmap he colours it appears in depends on the current text
1250 // colours, so set them correctly
1251 wxColour colFgOld;
1252 if ( bmpLineWrap.GetDepth() == 1 )
1253 {
1254 colFgOld = dc.GetTextForeground();
1255
1256 // FIXME: I wonder what should we do if the background is black too?
1257 dc.SetTextForeground(*wxBLACK);
1258 }
1259
1260 dc.DrawBitmap(bmpLineWrap,
1261 rect.x, rect.y + (rect.height - bmpLineWrap.GetHeight())/2);
1262
1263 if ( colFgOld.Ok() )
1264 {
1265 // restore old colour
1266 dc.SetTextForeground(colFgOld);
1267 }
1268}
1269
1270#endif // wxUSE_TEXTCTRL
1271
1272// ----------------------------------------------------------------------------
1273// notebook
1274// ----------------------------------------------------------------------------
1275
1276#if wxUSE_NOTEBOOK
1277
1278void wxGTKRenderer::DrawTab(wxDC& dc,
1279 const wxRect& rectOrig,
1280 wxDirection dir,
1281 const wxString& label,
1282 const wxBitmap& bitmap,
1283 int flags,
1284 int indexAccel)
1285{
1286 #define SELECT_FOR_VERTICAL(X,Y) ( isVertical ? Y : X )
1287 #define REVERSE_FOR_VERTICAL(X,Y) \
1288 SELECT_FOR_VERTICAL(X,Y) \
1289 , \
1290 SELECT_FOR_VERTICAL(Y,X)
1291
1292 wxRect rect = rectOrig;
1293
1294 bool isVertical = ( dir == wxLEFT ) || ( dir == wxRIGHT );
1295
1296 // the current tab is drawn indented (to the top for default case) and
1297 // bigger than the other ones
1298 const wxSize indent = GetTabIndent();
1299 if ( flags & wxCONTROL_SELECTED )
1300 {
1301 rect.Inflate( SELECT_FOR_VERTICAL( indent.x , 0),
1302 SELECT_FOR_VERTICAL( 0, indent.y ));
1303 switch ( dir )
1304 {
1305 default:
1306 wxFAIL_MSG(wxT("invaild notebook tab orientation"));
1307 // fall through
1308
1309 case wxTOP:
1310 rect.y -= indent.y;
1311 // fall through
1312 case wxBOTTOM:
1313 rect.height += indent.y;
1314 break;
1315
1316 case wxLEFT:
1317 rect.x -= indent.x;
1318 // fall through
1319 case wxRIGHT:
1320 rect.width += indent.x;
1321 break;
1322 }
1323 }
1324
1325 // selected tab has different colour
1326 wxColour col = flags & wxCONTROL_SELECTED
1327 ? wxSCHEME_COLOUR(m_scheme, SHADOW_IN)
1328 : wxSCHEME_COLOUR(m_scheme, SCROLLBAR);
1329 DrawSolidRect(dc, col, rect);
1330
1331 if ( flags & wxCONTROL_FOCUSED )
1332 {
1333 // draw the focus rect
1334 wxRect rectBorder = rect;
1335 rectBorder.Deflate(4, 3);
1336 if ( dir == wxBOTTOM )
1337 rectBorder.Offset(0, -1);
1338 if ( dir == wxRIGHT )
1339 rectBorder.Offset(-1, 0);
1340
1341 DrawRect(dc, &rectBorder, m_penBlack);
1342 }
1343
1344 // draw the text, image and the focus around them (if necessary)
1345 wxRect rectLabel( REVERSE_FOR_VERTICAL(rect.x,rect.y),
1346 REVERSE_FOR_VERTICAL(rect.width,rect.height)
1347 );
1348 rectLabel.Deflate(1, 1);
1349 if ( isVertical )
1350 {
1351 // draw it horizontally into memory and rotate for screen
1352 wxMemoryDC dcMem;
1353 wxBitmap bitmapRotated,
1354 bitmapMem( rectLabel.x + rectLabel.width,
1355 rectLabel.y + rectLabel.height );
1356 dcMem.SelectObject(bitmapMem);
1357 dcMem.SetBackground(dc.GetBackground());
1358 dcMem.SetFont(dc.GetFont());
1359 dcMem.SetTextForeground(dc.GetTextForeground());
1360 dcMem.Clear();
1361 bitmapRotated =
1362#if wxUSE_IMAGE
1363 wxBitmap( wxImage( bitmap.ConvertToImage() ).Rotate90(dir==wxLEFT) )
1364#else
1365 bitmap
1366#endif // wxUSE_IMAGE
1367 ;
1368 dcMem.DrawLabel(label, bitmapRotated, rectLabel, wxALIGN_CENTRE, indexAccel);
1369 dcMem.SelectObject(wxNullBitmap);
1370 bitmapMem = bitmapMem.GetSubBitmap(rectLabel);
1371#if wxUSE_IMAGE
1372 bitmapMem = wxBitmap(wxImage(bitmapMem.ConvertToImage()).Rotate90(dir==wxRIGHT))
1373#endif
1374 ;
1375
1376 dc.DrawBitmap(bitmapMem, rectLabel.y, rectLabel.x, false);
1377 }
1378 else
1379 {
1380 dc.DrawLabel(label, bitmap, rectLabel, wxALIGN_CENTRE, indexAccel);
1381 }
1382
1383 // now draw the tab itself
1384 wxCoord x = SELECT_FOR_VERTICAL(rect.x,rect.y),
1385 y = SELECT_FOR_VERTICAL(rect.y,rect.x),
1386 x2 = SELECT_FOR_VERTICAL(rect.GetRight(),rect.GetBottom()),
1387 y2 = SELECT_FOR_VERTICAL(rect.GetBottom(),rect.GetRight());
1388 switch ( dir )
1389 {
1390 default:
1391 // default is top
1392 case wxLEFT:
1393 // left orientation looks like top but IsVertical makes x and y reversed
1394 case wxTOP:
1395 // top is not vertical so use coordinates in written order
1396 dc.SetPen(m_penHighlight);
1397 dc.DrawLine(REVERSE_FOR_VERTICAL(x, y2),
1398 REVERSE_FOR_VERTICAL(x, y));
1399 dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y),
1400 REVERSE_FOR_VERTICAL(x2, y));
1401
1402 dc.SetPen(m_penBlack);
1403 dc.DrawLine(REVERSE_FOR_VERTICAL(x2, y2),
1404 REVERSE_FOR_VERTICAL(x2, y));
1405
1406 dc.SetPen(m_penDarkGrey);
1407 dc.DrawLine(REVERSE_FOR_VERTICAL(x2 - 1, y2),
1408 REVERSE_FOR_VERTICAL(x2 - 1, y + 1));
1409
1410 if ( flags & wxCONTROL_SELECTED )
1411 {
1412 dc.SetPen(m_penLightGrey);
1413
1414 // overwrite the part of the border below this tab
1415 dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y2 + 1),
1416 REVERSE_FOR_VERTICAL(x2 - 1, y2 + 1));
1417
1418 // and the shadow of the tab to the left of us
1419 dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y + 2),
1420 REVERSE_FOR_VERTICAL(x + 1, y2 + 1));
1421 }
1422 break;
1423
1424 case wxRIGHT:
1425 // right orientation looks like bottom but IsVertical makes x and y reversed
1426 case wxBOTTOM:
1427 // bottom is not vertical so use coordinates in written order
1428 dc.SetPen(m_penHighlight);
1429
1430 // we need to continue one pixel further to overwrite the corner of
1431 // the border for the selected tab
1432 dc.DrawLine(REVERSE_FOR_VERTICAL(x, y - (flags & wxCONTROL_SELECTED ? 1 : 0)),
1433 REVERSE_FOR_VERTICAL(x, y2));
1434
1435 // it doesn't work like this (TODO: implement it properly)
1436#if 0
1437 // erase the corner of the tab to the right
1438 dc.SetPen(m_penLightGrey);
1439 dc.DrawPoint(REVERSE_FOR_VERTICAL(x2 - 1, y - 2));
1440 dc.DrawPoint(REVERSE_FOR_VERTICAL(x2 - 2, y - 2));
1441 dc.DrawPoint(REVERSE_FOR_VERTICAL(x2 - 2, y - 1));
1442#endif // 0
1443
1444 dc.SetPen(m_penBlack);
1445 dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y2),
1446 REVERSE_FOR_VERTICAL(x2, y2));
1447 dc.DrawLine(REVERSE_FOR_VERTICAL(x2, y),
1448 REVERSE_FOR_VERTICAL(x2, y2));
1449
1450 dc.SetPen(m_penDarkGrey);
1451 dc.DrawLine(REVERSE_FOR_VERTICAL(x + 2, y2 - 1),
1452 REVERSE_FOR_VERTICAL(x2 - 1, y2 - 1));
1453 dc.DrawLine(REVERSE_FOR_VERTICAL(x2 - 1, y),
1454 REVERSE_FOR_VERTICAL(x2 - 1, y2));
1455
1456 if ( flags & wxCONTROL_SELECTED )
1457 {
1458 dc.SetPen(m_penLightGrey);
1459
1460 // overwrite the part of the (double!) border above this tab
1461 dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y - 1),
1462 REVERSE_FOR_VERTICAL(x2 - 1, y - 1));
1463 dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y - 2),
1464 REVERSE_FOR_VERTICAL(x2 - 1, y - 2));
1465
1466 // and the shadow of the tab to the left of us
1467 dc.DrawLine(REVERSE_FOR_VERTICAL(x + 1, y2 - 1),
1468 REVERSE_FOR_VERTICAL(x + 1, y - 1));
1469 }
1470 break;
1471 }
1472}
1473
1474#endif // wxUSE_NOTEBOOK
1475
1476// ----------------------------------------------------------------------------
1477// slider
1478// ----------------------------------------------------------------------------
1479
1480#if wxUSE_SLIDER
1481
1482wxSize wxGTKRenderer::GetSliderThumbSize(const wxRect& rect,
1483 int lenThumb,
1484 wxOrientation orient) const
1485{
1486 static const wxCoord SLIDER_THUMB_LENGTH = 30;
1487
1488 wxSize size;
1489
1490 wxRect rectShaft = GetSliderShaftRect(rect, lenThumb, orient);
1491 if ( orient == wxHORIZONTAL )
1492 {
1493 size.x = wxMin(SLIDER_THUMB_LENGTH, rectShaft.width);
1494 size.y = rectShaft.height;
1495 }
1496 else // vertical
1497 {
1498 size.y = wxMin(SLIDER_THUMB_LENGTH, rectShaft.height);
1499 size.x = rectShaft.width;
1500 }
1501
1502 return size;
1503}
1504
1505wxRect wxGTKRenderer::GetSliderShaftRect(const wxRect& rect,
1506 int WXUNUSED(lenThumb),
1507 wxOrientation WXUNUSED(orient),
1508 long WXUNUSED(style)) const
1509{
1510 return rect.Deflate(2*BORDER_THICKNESS, 2*BORDER_THICKNESS);
1511}
1512
1513void wxGTKRenderer::DrawSliderShaft(wxDC& dc,
1514 const wxRect& rectOrig,
1515 int WXUNUSED(lenThumb),
1516 wxOrientation WXUNUSED(orient),
1517 int flags,
1518 long WXUNUSED(style),
1519 wxRect *rectShaft)
1520{
1521 wxRect rect = rectOrig;
1522
1523 // draw the border first
1524 if ( flags & wxCONTROL_FOCUSED )
1525 {
1526 DrawRect(dc, &rect, m_penBlack);
1527 }
1528 else // not focused, normal
1529 {
1530 DrawAntiShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
1531 }
1532
1533 DrawAntiShadedRect(dc, &rect, m_penBlack, m_penLightGrey);
1534
1535 // and the background
1536 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), rect);
1537
1538 if ( rectShaft )
1539 *rectShaft = rect;
1540}
1541
1542void wxGTKRenderer::DrawSliderThumb(wxDC& dc,
1543 const wxRect& rectOrig,
1544 wxOrientation orient,
1545 int WXUNUSED(flags),
1546 long WXUNUSED(style))
1547{
1548 // draw the thumb border
1549 wxRect rect = rectOrig;
1550 DrawAntiRaisedBorder(dc, &rect);
1551
1552 // draw the handle in the middle
1553 if ( orient == wxVERTICAL )
1554 {
1555 rect.height = 2*BORDER_THICKNESS;
1556 rect.y = rectOrig.y + (rectOrig.height - rect.height) / 2;
1557 }
1558 else // horz
1559 {
1560 rect.width = 2*BORDER_THICKNESS;
1561 rect.x = rectOrig.x + (rectOrig.width - rect.width) / 2;
1562 }
1563
1564 DrawShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
1565}
1566
1567#endif // wxUSE_SLIDER
1568
1569#if wxUSE_MENUS
1570
1571// ----------------------------------------------------------------------------
1572// menu and menubar
1573// ----------------------------------------------------------------------------
1574
1575// wxGTKMenuGeometryInfo: the wxMenuGeometryInfo used by wxGTKRenderer
1576class wxGTKMenuGeometryInfo : public wxMenuGeometryInfo
1577{
1578public:
1579 virtual wxSize GetSize() const { return m_size; }
1580
1581 wxCoord GetLabelOffset() const { return m_ofsLabel; }
1582 wxCoord GetAccelOffset() const { return m_ofsAccel; }
1583
1584 wxCoord GetItemHeight() const { return m_heightItem; }
1585
1586private:
1587 // the total size of the menu
1588 wxSize m_size;
1589
1590 // the offset of the start of the menu item label
1591 wxCoord m_ofsLabel;
1592
1593 // the offset of the start of the accel label
1594 wxCoord m_ofsAccel;
1595
1596 // the height of a normal (not separator) item
1597 wxCoord m_heightItem;
1598
1599 friend wxMenuGeometryInfo *
1600 wxGTKRenderer::GetMenuGeometry(wxWindow *, const wxMenu&) const;
1601};
1602
1603// FIXME: all constants are hardcoded but shouldn't be
1604static const wxCoord MENU_LEFT_MARGIN = 9;
1605static const wxCoord MENU_RIGHT_MARGIN = 6;
1606
1607static const wxCoord MENU_HORZ_MARGIN = 6;
1608static const wxCoord MENU_VERT_MARGIN = 3;
1609
1610// the margin around bitmap/check marks (on each side)
1611static const wxCoord MENU_BMP_MARGIN = 2;
1612
1613// the margin between the labels and accel strings
1614static const wxCoord MENU_ACCEL_MARGIN = 8;
1615
1616// the separator height in pixels: in fact, strangely enough, the real height
1617// is 2 but Windows adds one extra pixel in the bottom margin, so take it into
1618// account here
1619static const wxCoord MENU_SEPARATOR_HEIGHT = 3;
1620
1621// the size of the standard checkmark bitmap
1622static const wxCoord MENU_CHECK_SIZE = 9;
1623
1624void wxGTKRenderer::DrawMenuBarItem(wxDC& dc,
1625 const wxRect& rect,
1626 const wxString& label,
1627 int flags,
1628 int indexAccel)
1629{
1630 DoDrawMenuItem(dc, rect, label, flags, indexAccel);
1631}
1632
1633void wxGTKRenderer::DrawMenuItem(wxDC& dc,
1634 wxCoord y,
1635 const wxMenuGeometryInfo& gi,
1636 const wxString& label,
1637 const wxString& accel,
1638 const wxBitmap& bitmap,
1639 int flags,
1640 int indexAccel)
1641{
1642 const wxGTKMenuGeometryInfo& geomInfo = (const wxGTKMenuGeometryInfo&)gi;
1643
1644 wxRect rect;
1645 rect.x = 0;
1646 rect.y = y;
1647 rect.width = geomInfo.GetSize().x;
1648 rect.height = geomInfo.GetItemHeight();
1649
1650 DoDrawMenuItem(dc, rect, label, flags, indexAccel, accel, bitmap, &geomInfo);
1651}
1652
1653void wxGTKRenderer::DoDrawMenuItem(wxDC& dc,
1654 const wxRect& rectOrig,
1655 const wxString& label,
1656 int flags,
1657 int indexAccel,
1658 const wxString& accel,
1659 const wxBitmap& bitmap,
1660 const wxGTKMenuGeometryInfo *geometryInfo)
1661{
1662 wxRect rect = rectOrig;
1663
1664 // draw the selected item specially
1665 if ( flags & wxCONTROL_SELECTED )
1666 {
1667 wxRect rectIn;
1668 DrawBorder(dc, wxBORDER_RAISED, rect, flags, &rectIn);
1669
1670 DrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL_CURRENT), rectIn);
1671 }
1672
1673 rect.Deflate(MENU_HORZ_MARGIN, MENU_VERT_MARGIN);
1674
1675 // draw the bitmap: use the bitmap provided or the standard checkmark for
1676 // the checkable items
1677 if ( geometryInfo )
1678 {
1679 wxBitmap bmp = bitmap;
1680 if ( !bmp.Ok() && (flags & wxCONTROL_CHECKABLE) )
1681 {
1682 bmp = GetCheckBitmap(flags);
1683 }
1684
1685 if ( bmp.Ok() )
1686 {
1687 rect.SetRight(geometryInfo->GetLabelOffset());
1688 wxControlRenderer::DrawBitmap(dc, bmp, rect);
1689 }
1690 }
1691 //else: menubar items don't have bitmaps
1692
1693 // draw the label
1694 if ( geometryInfo )
1695 {
1696 rect.x = geometryInfo->GetLabelOffset();
1697 rect.SetRight(geometryInfo->GetAccelOffset());
1698 }
1699
1700 DrawLabel(dc, label, rect, flags, wxALIGN_CENTRE_VERTICAL, indexAccel);
1701
1702 // draw the accel string
1703 if ( !accel.empty() )
1704 {
1705 // menubar items shouldn't have them
1706 wxCHECK_RET( geometryInfo, wxT("accel strings only valid for menus") );
1707
1708 rect.x = geometryInfo->GetAccelOffset();
1709 rect.SetRight(geometryInfo->GetSize().x);
1710
1711 // NB: no accel index here
1712 DrawLabel(dc, accel, rect, flags, wxALIGN_CENTRE_VERTICAL);
1713 }
1714
1715 // draw the submenu indicator
1716 if ( flags & wxCONTROL_ISSUBMENU )
1717 {
1718 wxCHECK_RET( geometryInfo, wxT("wxCONTROL_ISSUBMENU only valid for menus") );
1719
1720 rect.x = geometryInfo->GetSize().x - MENU_RIGHT_MARGIN;
1721 rect.width = MENU_RIGHT_MARGIN;
1722
1723 DrawArrow(dc, wxRIGHT, rect, flags);
1724 }
1725}
1726
1727void wxGTKRenderer::DrawMenuSeparator(wxDC& dc,
1728 wxCoord y,
1729 const wxMenuGeometryInfo& geomInfo)
1730{
1731 DrawHorizontalLine(dc, y + MENU_VERT_MARGIN, 0, geomInfo.GetSize().x);
1732}
1733
1734wxSize wxGTKRenderer::GetMenuBarItemSize(const wxSize& sizeText) const
1735{
1736 wxSize size = sizeText;
1737
1738 // TODO: make this configurable
1739 size.x += 2*MENU_HORZ_MARGIN;
1740 size.y += 2*MENU_VERT_MARGIN;
1741
1742 return size;
1743}
1744
1745wxMenuGeometryInfo *wxGTKRenderer::GetMenuGeometry(wxWindow *win,
1746 const wxMenu& menu) const
1747{
1748 // prepare the dc: for now we draw all the items with the system font
1749 wxClientDC dc(win);
1750 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
1751
1752 // the height of a normal item
1753 wxCoord heightText = dc.GetCharHeight();
1754
1755 // the total height
1756 wxCoord height = 0;
1757
1758 // the max length of label and accel strings: the menu width is the sum of
1759 // them, even if they're for different items (as the accels should be
1760 // aligned)
1761 //
1762 // the max length of the bitmap is never 0 as Windows always leaves enough
1763 // space for a check mark indicator
1764 wxCoord widthLabelMax = 0,
1765 widthAccelMax = 0,
1766 widthBmpMax = MENU_LEFT_MARGIN;
1767
1768 for ( wxMenuItemList::compatibility_iterator node = menu.GetMenuItems().GetFirst();
1769 node;
1770 node = node->GetNext() )
1771 {
1772 // height of this item
1773 wxCoord h;
1774
1775 wxMenuItem *item = node->GetData();
1776 if ( item->IsSeparator() )
1777 {
1778 h = MENU_SEPARATOR_HEIGHT;
1779 }
1780 else // not separator
1781 {
1782 h = heightText;
1783
1784 wxCoord widthLabel;
1785 dc.GetTextExtent(item->GetItemLabelText(), &widthLabel, NULL);
1786 if ( widthLabel > widthLabelMax )
1787 {
1788 widthLabelMax = widthLabel;
1789 }
1790
1791 wxCoord widthAccel;
1792 dc.GetTextExtent(item->GetAccelString(), &widthAccel, NULL);
1793 if ( widthAccel > widthAccelMax )
1794 {
1795 widthAccelMax = widthAccel;
1796 }
1797
1798 const wxBitmap& bmp = item->GetBitmap();
1799 if ( bmp.Ok() )
1800 {
1801 wxCoord widthBmp = bmp.GetWidth();
1802 if ( widthBmp > widthBmpMax )
1803 widthBmpMax = widthBmp;
1804 }
1805 //else if ( item->IsCheckable() ): no need to check for this as
1806 // MENU_LEFT_MARGIN is big enough to show the check mark
1807 }
1808
1809 h += 2*MENU_VERT_MARGIN;
1810
1811 // remember the item position and height
1812 item->SetGeometry(height, h);
1813
1814 height += h;
1815 }
1816
1817 // bundle the metrics into a struct and return it
1818 wxGTKMenuGeometryInfo *gi = new wxGTKMenuGeometryInfo;
1819
1820 gi->m_ofsLabel = widthBmpMax + 2*MENU_BMP_MARGIN;
1821 gi->m_ofsAccel = gi->m_ofsLabel + widthLabelMax;
1822 if ( widthAccelMax > 0 )
1823 {
1824 // if we actually have any accesl, add a margin
1825 gi->m_ofsAccel += MENU_ACCEL_MARGIN;
1826 }
1827
1828 gi->m_heightItem = heightText + 2*MENU_VERT_MARGIN;
1829
1830 gi->m_size.x = gi->m_ofsAccel + widthAccelMax + MENU_RIGHT_MARGIN;
1831 gi->m_size.y = height;
1832
1833 return gi;
1834}
1835
1836#endif // wxUSE_MENUS
1837
1838// ----------------------------------------------------------------------------
1839// combobox
1840// ----------------------------------------------------------------------------
1841
1842void wxGTKRenderer::InitComboBitmaps()
1843{
1844 wxSize sizeArrow = m_sizeScrollbarArrow;
1845 sizeArrow.x -= 2;
1846 sizeArrow.y -= 2;
1847
1848 size_t n;
1849
1850 for ( n = ComboState_Normal; n < ComboState_Max; n++ )
1851 {
1852 m_bitmapsCombo[n].Create(sizeArrow.x, sizeArrow.y);
1853 }
1854
1855 static const int comboButtonFlags[ComboState_Max] =
1856 {
1857 0,
1858 wxCONTROL_CURRENT,
1859 wxCONTROL_PRESSED,
1860 wxCONTROL_DISABLED,
1861 };
1862
1863 wxRect rect(sizeArrow);
1864
1865 wxMemoryDC dc;
1866 for ( n = ComboState_Normal; n < ComboState_Max; n++ )
1867 {
1868 int flags = comboButtonFlags[n];
1869
1870 dc.SelectObject(m_bitmapsCombo[n]);
1871 DrawSolidRect(dc, GetBackgroundColour(flags), rect);
1872 DrawArrow(dc, wxDOWN, rect, flags);
1873 }
1874}
1875
1876void wxGTKRenderer::GetComboBitmaps(wxBitmap *bmpNormal,
1877 wxBitmap *bmpFocus,
1878 wxBitmap *bmpPressed,
1879 wxBitmap *bmpDisabled)
1880{
1881 if ( !m_bitmapsCombo[ComboState_Normal].Ok() )
1882 {
1883 InitComboBitmaps();
1884 }
1885
1886 if ( bmpNormal )
1887 *bmpNormal = m_bitmapsCombo[ComboState_Normal];
1888 if ( bmpFocus )
1889 *bmpFocus = m_bitmapsCombo[ComboState_Focus];
1890 if ( bmpPressed )
1891 *bmpPressed = m_bitmapsCombo[ComboState_Pressed];
1892 if ( bmpDisabled )
1893 *bmpDisabled = m_bitmapsCombo[ComboState_Disabled];
1894}
1895
1896// ----------------------------------------------------------------------------
1897// scrollbar
1898// ----------------------------------------------------------------------------
1899
1900void wxGTKRenderer::DrawArrowBorder(wxDC& dc,
1901 wxRect *rect,
1902 wxDirection dir)
1903{
1904 static const wxDirection sides[] =
1905 {
1906 wxUP, wxLEFT, wxRIGHT, wxDOWN
1907 };
1908
1909 wxRect rect1, rect2, rectInner;
1910 rect1 =
1911 rect2 =
1912 rectInner = *rect;
1913
1914 rect2.Inflate(-1);
1915 rectInner.Inflate(-2);
1916
1917 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), *rect);
1918
1919 // find the side not to draw and also adjust the rectangles to compensate
1920 // for it
1921 wxDirection sideToOmit;
1922 switch ( dir )
1923 {
1924 case wxUP:
1925 sideToOmit = wxDOWN;
1926 rect2.height += 1;
1927 rectInner.height += 1;
1928 break;
1929
1930 case wxDOWN:
1931 sideToOmit = wxUP;
1932 rect2.y -= 1;
1933 rect2.height += 1;
1934 rectInner.y -= 2;
1935 rectInner.height += 1;
1936 break;
1937
1938 case wxLEFT:
1939 sideToOmit = wxRIGHT;
1940 rect2.width += 1;
1941 rectInner.width += 1;
1942 break;
1943
1944 case wxRIGHT:
1945 sideToOmit = wxLEFT;
1946 rect2.x -= 1;
1947 rect2.width += 1;
1948 rectInner.x -= 2;
1949 rectInner.width += 1;
1950 break;
1951
1952 default:
1953 wxFAIL_MSG(wxT("unknown arrow direction"));
1954 return;
1955 }
1956
1957 // the outer rect first
1958 size_t n;
1959 for ( n = 0; n < WXSIZEOF(sides); n++ )
1960 {
1961 wxDirection side = sides[n];
1962 if ( side == sideToOmit )
1963 continue;
1964
1965 DrawAntiShadedRectSide(dc, rect1, m_penDarkGrey, m_penHighlight, side);
1966 }
1967
1968 // and then the inner one
1969 for ( n = 0; n < WXSIZEOF(sides); n++ )
1970 {
1971 wxDirection side = sides[n];
1972 if ( side == sideToOmit )
1973 continue;
1974
1975 DrawAntiShadedRectSide(dc, rect2, m_penBlack, m_penGrey, side);
1976 }
1977
1978 *rect = rectInner;
1979}
1980
1981void wxGTKRenderer::DrawScrollbarArrow(wxDC& dc,
1982 wxDirection dir,
1983 const wxRect& rectArrow,
1984 int flags)
1985{
1986 // first of all, draw the border around it - but we don't want the border
1987 // on the side opposite to the arrow point
1988 wxRect rect = rectArrow;
1989 DrawArrowBorder(dc, &rect, dir);
1990
1991 // then the arrow itself
1992 DrawArrow(dc, dir, rect, flags);
1993}
1994
1995// gtk_default_draw_arrow() takes ~350 lines and we can't do much better here
1996// these people are just crazy :-(
1997void wxGTKRenderer::DrawArrow(wxDC& dc,
1998 wxDirection dir,
1999 const wxRect& rect,
2000 int flags)
2001{
2002 enum
2003 {
2004 Point_First,
2005 Point_Second,
2006 Point_Third,
2007 Point_Max
2008 };
2009
2010 wxPoint ptArrow[Point_Max];
2011
2012 wxColour colInside = GetBackgroundColour(flags);
2013 wxPen penShadow[4];
2014 if ( flags & wxCONTROL_DISABLED )
2015 {
2016 penShadow[0] = m_penDarkGrey;
2017 penShadow[1] = m_penDarkGrey;
2018 penShadow[2] = wxNullPen;
2019 penShadow[3] = wxNullPen;
2020 }
2021 else if ( flags & wxCONTROL_PRESSED )
2022 {
2023 penShadow[0] = m_penDarkGrey;
2024 penShadow[1] = m_penHighlight;
2025 penShadow[2] = wxNullPen;
2026 penShadow[3] = m_penBlack;
2027 }
2028 else // normal arrow
2029 {
2030 penShadow[0] = m_penHighlight;
2031 penShadow[1] = m_penBlack;
2032 penShadow[2] = m_penDarkGrey;
2033 penShadow[3] = wxNullPen;
2034 }
2035
2036 wxCoord middle;
2037 if ( dir == wxUP || dir == wxDOWN )
2038 {
2039 // horz middle
2040 middle = (rect.GetRight() + rect.GetLeft() + 1) / 2;
2041 }
2042 else // horz arrow
2043 {
2044 middle = (rect.GetTop() + rect.GetBottom() + 1) / 2;
2045 }
2046
2047 // draw the arrow interior
2048 dc.SetPen(*wxTRANSPARENT_PEN);
2049 dc.SetBrush(colInside);
2050
2051 switch ( dir )
2052 {
2053 case wxUP:
2054 ptArrow[Point_First].x = rect.GetLeft();
2055 ptArrow[Point_First].y = rect.GetBottom();
2056 ptArrow[Point_Second].x = middle;
2057 ptArrow[Point_Second].y = rect.GetTop();
2058 ptArrow[Point_Third].x = rect.GetRight();
2059 ptArrow[Point_Third].y = rect.GetBottom();
2060 break;
2061
2062 case wxDOWN:
2063 ptArrow[Point_First] = rect.GetPosition();
2064 ptArrow[Point_Second].x = middle;
2065 ptArrow[Point_Second].y = rect.GetBottom();
2066 ptArrow[Point_Third].x = rect.GetRight();
2067 ptArrow[Point_Third].y = rect.GetTop();
2068 break;
2069
2070 case wxLEFT:
2071 ptArrow[Point_First].x = rect.GetRight();
2072 ptArrow[Point_First].y = rect.GetTop();
2073 ptArrow[Point_Second].x = rect.GetLeft();
2074 ptArrow[Point_Second].y = middle;
2075 ptArrow[Point_Third].x = rect.GetRight();
2076 ptArrow[Point_Third].y = rect.GetBottom();
2077 break;
2078
2079 case wxRIGHT:
2080 ptArrow[Point_First] = rect.GetPosition();
2081 ptArrow[Point_Second].x = rect.GetRight();
2082 ptArrow[Point_Second].y = middle;
2083 ptArrow[Point_Third].x = rect.GetLeft();
2084 ptArrow[Point_Third].y = rect.GetBottom();
2085 break;
2086
2087 default:
2088 wxFAIL_MSG(wxT("unknown arrow direction"));
2089 }
2090
2091 dc.DrawPolygon(WXSIZEOF(ptArrow), ptArrow);
2092
2093 // draw the arrow border
2094 dc.SetPen(penShadow[0]);
2095 switch ( dir )
2096 {
2097 case wxUP:
2098 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_First]);
2099 dc.DrawPoint(ptArrow[Point_First]);
2100 if ( penShadow[3].Ok() )
2101 {
2102 dc.SetPen(penShadow[3]);
2103 dc.DrawLine(ptArrow[Point_First].x + 1, ptArrow[Point_First].y,
2104 ptArrow[Point_Second].x, ptArrow[Point_Second].y);
2105 }
2106 dc.SetPen(penShadow[1]);
2107 dc.DrawLine(ptArrow[Point_Second].x + 1, ptArrow[Point_Second].y + 1,
2108 ptArrow[Point_Third].x, ptArrow[Point_Third].y);
2109 dc.DrawPoint(ptArrow[Point_Third]);
2110 dc.DrawLine(ptArrow[Point_Third].x - 2, ptArrow[Point_Third].y,
2111 ptArrow[Point_First].x + 1, ptArrow[Point_First].y);
2112 if ( penShadow[2].Ok() )
2113 {
2114 dc.SetPen(penShadow[2]);
2115 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y,
2116 ptArrow[Point_Second].x, ptArrow[Point_Second].y + 1);
2117 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y - 1,
2118 ptArrow[Point_First].x + 2, ptArrow[Point_First].y - 1);
2119 }
2120 break;
2121
2122 case wxDOWN:
2123 dc.DrawLine(ptArrow[Point_First], ptArrow[Point_Second]);
2124 dc.DrawLine(ptArrow[Point_First].x + 2, ptArrow[Point_First].y,
2125 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y);
2126 if ( penShadow[2].Ok() )
2127 {
2128 dc.SetPen(penShadow[2]);
2129 dc.DrawLine(ptArrow[Point_Second].x, ptArrow[Point_Second].y - 1,
2130 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y - 1);
2131 }
2132 dc.SetPen(penShadow[1]);
2133 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_Third]);
2134 dc.DrawPoint(ptArrow[Point_Third]);
2135 break;
2136
2137 case wxLEFT:
2138 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_First]);
2139 dc.DrawPoint(ptArrow[Point_First]);
2140 if ( penShadow[2].Ok() )
2141 {
2142 dc.SetPen(penShadow[2]);
2143 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y,
2144 ptArrow[Point_First].x - 1, ptArrow[Point_First].y + 2);
2145 dc.DrawLine(ptArrow[Point_Third].x, ptArrow[Point_Third].y,
2146 ptArrow[Point_Second].x + 2, ptArrow[Point_Second].y + 1);
2147 }
2148 dc.SetPen(penShadow[1]);
2149 dc.DrawLine(ptArrow[Point_Third].x, ptArrow[Point_Third].y,
2150 ptArrow[Point_First].x, ptArrow[Point_First].y + 1);
2151 dc.DrawLine(ptArrow[Point_Second].x + 1, ptArrow[Point_Second].y + 1,
2152 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y);
2153 break;
2154
2155 case wxRIGHT:
2156 dc.DrawLine(ptArrow[Point_First], ptArrow[Point_Third]);
2157 dc.DrawLine(ptArrow[Point_First].x + 2, ptArrow[Point_First].y + 1,
2158 ptArrow[Point_Second].x, ptArrow[Point_Second].y);
2159 dc.SetPen(penShadow[1]);
2160 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_Third]);
2161 dc.DrawPoint(ptArrow[Point_Third]);
2162 break;
2163
2164 default:
2165 wxFAIL_MSG(wxT("unknown arrow direction"));
2166 return;
2167 }
2168}
2169
2170void wxGTKRenderer::DrawThumbBorder(wxDC& dc,
2171 wxRect *rect,
2172 wxOrientation orient)
2173{
2174 if ( orient == wxVERTICAL )
2175 {
2176 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2177 wxLEFT);
2178 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2179 wxRIGHT);
2180 rect->Inflate(-1, 0);
2181
2182 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2183 wxLEFT);
2184 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2185 wxRIGHT);
2186 rect->Inflate(-1, 0);
2187 }
2188 else
2189 {
2190 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2191 wxUP);
2192 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2193 wxDOWN);
2194 rect->Inflate(0, -1);
2195
2196 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2197 wxUP);
2198 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2199 wxDOWN);
2200 rect->Inflate(0, -1);
2201 }
2202}
2203
2204void wxGTKRenderer::DrawScrollbarThumb(wxDC& dc,
2205 wxOrientation orient,
2206 const wxRect& rect,
2207 int flags)
2208{
2209 // the thumb is never pressed never has focus border under GTK and the
2210 // scrollbar background never changes at all
2211 int flagsThumb = flags & ~(wxCONTROL_PRESSED | wxCONTROL_FOCUSED);
2212
2213 // we don't want the border in the direction of the scrollbar movement
2214 wxRect rectThumb = rect;
2215 DrawThumbBorder(dc, &rectThumb, orient);
2216
2217 DrawButtonBorder(dc, rectThumb, flagsThumb, &rectThumb);
2218 DrawBackground(dc, wxNullColour, rectThumb, flagsThumb);
2219}
2220
2221void wxGTKRenderer::DrawScrollbarShaft(wxDC& dc,
2222 wxOrientation orient,
2223 const wxRect& rect,
2224 int WXUNUSED(flags))
2225{
2226 wxRect rectBar = rect;
2227 DrawThumbBorder(dc, &rectBar, orient);
2228 DrawSolidRect(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), rectBar);
2229}
2230
2231// ----------------------------------------------------------------------------
2232// size adjustments
2233// ----------------------------------------------------------------------------
2234
2235void wxGTKRenderer::AdjustSize(wxSize *size, const wxWindow *window)
2236{
2237#if wxUSE_BMPBUTTON
2238 if ( wxDynamicCast(window, wxBitmapButton) )
2239 {
2240 size->x += 4;
2241 size->y += 4;
2242 } else
2243#endif // wxUSE_BMPBUTTON
2244#if wxUSE_BUTTON || wxUSE_TOGGLEBTN
2245 if ( 0
2246# if wxUSE_BUTTON
2247 || wxDynamicCast(window, wxButton)
2248# endif // wxUSE_BUTTON
2249# if wxUSE_TOGGLEBTN
2250 || wxDynamicCast(window, wxToggleButton)
2251# endif // wxUSE_TOGGLEBTN
2252 )
2253 {
2254 if ( !(window->GetWindowStyle() & wxBU_EXACTFIT) )
2255 {
2256 // TODO: this is ad hoc...
2257 size->x += 3*window->GetCharWidth();
2258 wxCoord minBtnHeight = 18;
2259 if ( size->y < minBtnHeight )
2260 size->y = minBtnHeight;
2261
2262 // button border width
2263 size->y += 4;
2264 }
2265 } else
2266#endif // wxUSE_BUTTON || wxUSE_TOGGLEBTN
2267#if wxUSE_SCROLLBAR
2268 if ( wxDynamicCast(window, wxScrollBar) )
2269 {
2270 // we only set the width of vert scrollbars and height of the
2271 // horizontal ones
2272 if ( window->GetWindowStyle() & wxSB_HORIZONTAL )
2273 size->y = m_sizeScrollbarArrow.x;
2274 else
2275 size->x = m_sizeScrollbarArrow.x;
2276 }
2277 else
2278#endif // wxUSE_SCROLLBAR
2279 {
2280 // take into account the border width
2281 wxStdRenderer::AdjustSize(size, window);
2282 }
2283}
2284
2285// ----------------------------------------------------------------------------
2286// standard icons
2287// ----------------------------------------------------------------------------
2288
2289/* Copyright (c) Julian Smart */
2290static const char *error_xpm[] = {
2291/* columns rows colors chars-per-pixel */
2292"48 48 4 1",
2293" c None",
2294"X c #242424",
2295"o c #DCDF00",
2296". c #C00000",
2297/* pixels */
2298" ",
2299" ",
2300" ",
2301" ",
2302" ",
2303" ..... ",
2304" ............. ",
2305" ................. ",
2306" ................... ",
2307" ....................... ",
2308" ......................... ",
2309" ........................... ",
2310" ...........................X ",
2311" .............................X ",
2312" ............................... ",
2313" ...............................X ",
2314" .................................X ",
2315" .................................X ",
2316" .................................XX ",
2317" ...ooooooooooooooooooooooooooo...XX ",
2318" ....ooooooooooooooooooooooooooo....X ",
2319" ....ooooooooooooooooooooooooooo....X ",
2320" ....ooooooooooooooooooooooooooo....XX ",
2321" ....ooooooooooooooooooooooooooo....XX ",
2322" ....ooooooooooooooooooooooooooo....XX ",
2323" ...ooooooooooooooooooooooooooo...XXX ",
2324" ...ooooooooooooooooooooooooooo...XXX ",
2325" .................................XX ",
2326" .................................XX ",
2327" ...............................XXX ",
2328" ...............................XXX ",
2329" .............................XXX ",
2330" ...........................XXXX ",
2331" ...........................XXX ",
2332" .........................XXX ",
2333" .......................XXXX ",
2334" X...................XXXXX ",
2335" X.................XXXXX ",
2336" X.............XXXXX ",
2337" XXXX.....XXXXXXXX ",
2338" XXXXXXXXXXXXX ",
2339" XXXXX ",
2340" ",
2341" ",
2342" ",
2343" ",
2344" ",
2345" "
2346};
2347
2348/* Copyright (c) Julian Smart */
2349static const char *info_xpm[] = {
2350/* columns rows colors chars-per-pixel */
2351"48 48 9 1",
2352"$ c Black",
2353"O c #FFFFFF",
2354"@ c #808080",
2355"+ c #000080",
2356"o c #E8EB01",
2357" c None",
2358"X c #FFFF40",
2359"# c #C0C0C0",
2360". c #ABAD01",
2361/* pixels */
2362" ",
2363" ",
2364" ",
2365" ",
2366" ",
2367" ",
2368" ",
2369" ",
2370" ",
2371" ..... ",
2372" ..XXXXX.. ",
2373" ..XXXXXXXXo.. ",
2374" .XXXOXXXXXXXoo. ",
2375" .XOOXXX+XXXXXo. ",
2376" .XOOOXX+++XXXXoo. ",
2377" .XOOXXX+++XXXXXo. ",
2378" .XOOOXXX+++XXXXXXo. ",
2379" .XOOXXXX+++XXXXXXo. ",
2380" .XXXXXXX+++XXXXXXX. ",
2381" .XXXXXXX+++XXXXXXo. ",
2382" .XXXXXXX+++XXXXXoo. ",
2383" .XXXXXX+++XXXXXo. ",
2384" .XXXXXXX+XXXXXXo. ",
2385" .XXXXXXXXXXXXo. ",
2386" .XXXXX+++XXXoo. ",
2387" .XXXX+++XXoo. ",
2388" .XXXXXXXXo. ",
2389" ..XXXXXXo.. ",
2390" .XXXXXo.. ",
2391" @#######@ ",
2392" @@@@@@@@@ ",
2393" @#######@ ",
2394" @@@@@@@@@ ",
2395" @#######@ ",
2396" @@@@@@@ ",
2397" ### ",
2398" $$$ ",
2399" ",
2400" ",
2401" ",
2402" ",
2403" ",
2404" ",
2405" ",
2406" ",
2407" ",
2408" ",
2409" "
2410};
2411
2412/* Copyright (c) Julian Smart */
2413static const char *warning_xpm[] = {
2414/* columns rows colors chars-per-pixel */
2415"48 48 9 1",
2416"@ c Black",
2417"o c #A6A800",
2418"+ c #8A8C00",
2419"$ c #B8BA00",
2420" c None",
2421"O c #6E7000",
2422"X c #DCDF00",
2423". c #C00000",
2424"# c #373800",
2425/* pixels */
2426" ",
2427" ",
2428" ",
2429" ",
2430" ",
2431" ",
2432" ",
2433" . ",
2434" ... ",
2435" ... ",
2436" ..... ",
2437" ...X.. ",
2438" ..XXX.. ",
2439" ...XXX... ",
2440" ..XXXXX.. ",
2441" ..XXXXXX... ",
2442" ...XXoO+XX.. ",
2443" ..XXXO@#XXX.. ",
2444" ..XXXXO@#XXX... ",
2445" ...XXXXO@#XXXX.. ",
2446" ..XXXXXO@#XXXX... ",
2447" ...XXXXXo@OXXXXX.. ",
2448" ...XXXXXXo@OXXXXXX.. ",
2449" ..XXXXXXX$@OXXXXXX... ",
2450" ...XXXXXXXX@XXXXXXXX.. ",
2451" ...XXXXXXXXXXXXXXXXXX... ",
2452" ..XXXXXXXXXXOXXXXXXXXX.. ",
2453" ...XXXXXXXXXO@#XXXXXXXXX.. ",
2454" ..XXXXXXXXXXX#XXXXXXXXXX... ",
2455" ...XXXXXXXXXXXXXXXXXXXXXXX.. ",
2456" ...XXXXXXXXXXXXXXXXXXXXXXXX... ",
2457" .............................. ",
2458" .............................. ",
2459" ",
2460" ",
2461" ",
2462" ",
2463" ",
2464" ",
2465" ",
2466" ",
2467" ",
2468" ",
2469" ",
2470" ",
2471" ",
2472" ",
2473" "
2474};
2475
2476/* Copyright (c) Julian Smart */
2477static const char *question_xpm[] = {
2478/* columns rows colors chars-per-pixel */
2479"48 48 21 1",
2480". c Black",
2481"> c #696969",
2482"O c #1F1F00",
2483"+ c #181818",
2484"o c #F6F900",
2485"; c #3F3F00",
2486"$ c #111111",
2487" c None",
2488"& c #202020",
2489"X c #AAAA00",
2490"@ c #949400",
2491": c #303030",
2492"1 c #383838",
2493"% c #2A2A00",
2494", c #404040",
2495"= c #B4B400",
2496"- c #484848",
2497"# c #151500",
2498"< c #9F9F00",
2499"2 c #6A6A00",
2500"* c #353500",
2501/* pixels */
2502" ",
2503" ",
2504" ",
2505" ",
2506" ......... ",
2507" ...XXXXXXX.. ",
2508" ..XXXXoooooXXXO+ ",
2509" ..XXooooooooooooX@.. ",
2510" ..XoooooooooooooooXX#. ",
2511" $%XoooooooooooooooooXX#. ",
2512" &.XoooooooXXXXXXooooooXX.. ",
2513" .XooooooXX.$...$XXoooooX*. ",
2514" $.XoooooX%.$ .*oooooo=.. ",
2515" .XooooooX.. -.XoooooX.. ",
2516" .XoooooX..+ .XoooooX;. ",
2517" ...XXXX..: .XoooooX;. ",
2518" ........ >.XoooooX;. ",
2519" +.XoooooX.. ",
2520" ,.Xoooooo<.. ",
2521" 1#XooooooXO.. ",
2522" &#XooooooX2.. ",
2523" $%XooooooXX.. ",
2524" $%XooooooXX.. ",
2525" $%XooooooXX.. ",
2526" &.XooooooXX.. ",
2527" .XooooooXX.. ",
2528" &.XoooooXX.. ",
2529" ..XooooXX.. ",
2530" ..XooooX... ",
2531" ..XXooXX..& ",
2532" ...XXXXX.. ",
2533" ........ ",
2534" ",
2535" ",
2536" ....... ",
2537" ..XXXXX.. ",
2538" ..XXoooXX.. ",
2539" ..XoooooX.. ",
2540" ..XoooooX.. ",
2541" ..XXoooXX.. ",
2542" ..XXXXX.. ",
2543" ....... ",
2544" ",
2545" ",
2546" ",
2547" ",
2548" ",
2549" "
2550};
2551
2552wxBitmap wxGTKArtProvider::CreateBitmap(const wxArtID& id,
2553 const wxArtClient& WXUNUSED(client),
2554 const wxSize& WXUNUSED(size))
2555{
2556 if ( id == wxART_INFORMATION )
2557 return wxBitmap(info_xpm);
2558 if ( id == wxART_ERROR )
2559 return wxBitmap(error_xpm);
2560 if ( id == wxART_WARNING )
2561 return wxBitmap(warning_xpm);
2562 if ( id == wxART_QUESTION )
2563 return wxBitmap(question_xpm);
2564 return wxNullBitmap;
2565}
2566
2567
2568// ============================================================================
2569// wxInputHandler
2570// ============================================================================
2571
2572// ----------------------------------------------------------------------------
2573// wxGTKInputHandler
2574// ----------------------------------------------------------------------------
2575
2576bool wxGTKInputHandler::HandleKey(wxInputConsumer * WXUNUSED(control),
2577 const wxKeyEvent& WXUNUSED(event),
2578 bool WXUNUSED(pressed))
2579{
2580 return false;
2581}
2582
2583bool wxGTKInputHandler::HandleMouse(wxInputConsumer *control,
2584 const wxMouseEvent& event)
2585{
2586 // clicking on the control gives it focus
2587 if ( event.ButtonDown() && wxWindow::FindFocus() != control->GetInputWindow() )
2588 {
2589 control->GetInputWindow()->SetFocus();
2590
2591 return true;
2592 }
2593
2594 return false;
2595}
2596
2597bool wxGTKInputHandler::HandleMouseMove(wxInputConsumer *control,
2598 const wxMouseEvent& event)
2599{
2600 if ( event.Entering() )
2601 {
2602 control->GetInputWindow()->SetCurrent(true);
2603 }
2604 else if ( event.Leaving() )
2605 {
2606 control->GetInputWindow()->SetCurrent(false);
2607 }
2608 else
2609 {
2610 return false;
2611 }
2612
2613 return true;
2614}
2615
2616#if wxUSE_CHECKBOX
2617
2618// ----------------------------------------------------------------------------
2619// wxGTKCheckboxInputHandler
2620// ----------------------------------------------------------------------------
2621
2622bool wxGTKCheckboxInputHandler::HandleKey(wxInputConsumer *control,
2623 const wxKeyEvent& event,
2624 bool pressed)
2625{
2626 if ( pressed )
2627 {
2628 int keycode = event.GetKeyCode();
2629 if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
2630 {
2631 control->PerformAction(wxACTION_CHECKBOX_TOGGLE);
2632
2633 return true;
2634 }
2635 }
2636
2637 return false;
2638}
2639
2640#endif // wxUSE_CHECKBOX
2641
2642#if wxUSE_TEXTCTRL
2643
2644// ----------------------------------------------------------------------------
2645// wxGTKTextCtrlInputHandler
2646// ----------------------------------------------------------------------------
2647
2648bool wxGTKTextCtrlInputHandler::HandleKey(wxInputConsumer *control,
2649 const wxKeyEvent& event,
2650 bool pressed)
2651{
2652 // handle only GTK-specific text bindings here, the others are handled in
2653 // the base class
2654 if ( pressed )
2655 {
2656 wxControlAction action;
2657 int keycode = event.GetKeyCode();
2658 if ( event.ControlDown() )
2659 {
2660 switch ( keycode )
2661 {
2662 case 'A':
2663 action = wxACTION_TEXT_HOME;
2664 break;
2665
2666 case 'B':
2667 action = wxACTION_TEXT_LEFT;
2668 break;
2669
2670 case 'D':
2671 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_RIGHT;
2672 break;
2673
2674 case 'E':
2675 action = wxACTION_TEXT_END;
2676 break;
2677
2678 case 'F':
2679 action = wxACTION_TEXT_RIGHT;
2680 break;
2681
2682 case 'H':
2683 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_LEFT;
2684 break;
2685
2686 case 'K':
2687 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_END;
2688 break;
2689
2690 case 'N':
2691 action = wxACTION_TEXT_DOWN;
2692 break;
2693
2694 case 'P':
2695 action = wxACTION_TEXT_UP;
2696 break;
2697
2698 case 'U':
2699 //delete the entire line
2700 control->PerformAction(wxACTION_TEXT_HOME);
2701 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_END;
2702 break;
2703
2704 case 'W':
2705 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_WORD_LEFT;
2706 break;
2707 }
2708 }
2709 else if ( event.AltDown() )
2710 {
2711 switch ( keycode )
2712 {
2713 case 'B':
2714 action = wxACTION_TEXT_WORD_LEFT;
2715 break;
2716
2717 case 'D':
2718 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_WORD_RIGHT;
2719 break;
2720
2721 case 'F':
2722 action = wxACTION_TEXT_WORD_RIGHT;
2723 break;
2724 }
2725 }
2726
2727 if ( action != wxACTION_NONE )
2728 {
2729 control->PerformAction(action);
2730
2731 return true;
2732 }
2733 }
2734
2735 return wxStdInputHandler::HandleKey(control, event, pressed);
2736}
2737
2738#endif // wxUSE_TEXTCTRL
2739
2740#endif // wxUSE_THEME_GTK