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