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