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