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