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