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