]> git.saurik.com Git - wxWidgets.git/blob - src/univ/themes/gtk.cpp
moved WX_USE_THEME macros inside IMPLEMENT_APP
[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 = 2;
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 / 2; 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 / 2; 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 / 2; width++ )
877 {
878 DrawRaisedBorder(dc, &rect);
879 }
880 break;
881
882 case wxBORDER_DOUBLE:
883 for ( width = 0; width < BORDER_THICKNESS / 3; 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 for ( size_t width = 0; width < BORDER_THICKNESS / 2; width++ )
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 / 2; 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 / 2; 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 static const int TEXT_BORDER = 2;
1496
1497 wxRect wxGTKRenderer::GetTextTotalArea(const wxTextCtrl *text,
1498 const wxRect& rect)
1499 {
1500 wxRect rectTotal = rect;
1501 rectTotal.Inflate(TEXT_BORDER);
1502 return rectTotal;
1503 }
1504
1505 wxRect wxGTKRenderer::GetTextClientArea(const wxTextCtrl *text,
1506 const wxRect& rect,
1507 wxCoord *extraSpaceBeyond)
1508 {
1509 wxRect rectText = rect;
1510 rectText.Inflate(-TEXT_BORDER);
1511
1512 if ( text->WrapLines() )
1513 {
1514 // leave enough for the line wrap bitmap indicator
1515 wxCoord widthMark = GetLineWrapBitmap().GetWidth() + 2;
1516
1517 rectText.width -= widthMark;
1518
1519 if ( extraSpaceBeyond )
1520 *extraSpaceBeyond = widthMark;
1521 }
1522
1523 return rectText;
1524 }
1525
1526 void wxGTKRenderer::DrawTextLine(wxDC& dc,
1527 const wxString& text,
1528 const wxRect& rect,
1529 int selStart,
1530 int selEnd,
1531 int flags)
1532 {
1533 // TODO: GTK+ draws selection even for unfocused controls, just with
1534 // different colours
1535 StandardDrawTextLine(dc, text, rect, selStart, selEnd, flags);
1536 }
1537
1538 void wxGTKRenderer::DrawLineWrapMark(wxDC& dc, const wxRect& rect)
1539 {
1540 wxBitmap bmpLineWrap = GetLineWrapBitmap();
1541
1542 // for a mono bitmap he colours it appears in depends on the current text
1543 // colours, so set them correctly
1544 wxColour colFgOld;
1545 if ( bmpLineWrap.GetDepth() == 1 )
1546 {
1547 colFgOld = dc.GetTextForeground();
1548
1549 // FIXME: I wonder what should we do if the background is black too?
1550 dc.SetTextForeground(*wxBLACK);
1551 }
1552
1553 dc.DrawBitmap(bmpLineWrap,
1554 rect.x, rect.y + (rect.height - bmpLineWrap.GetHeight())/2);
1555
1556 if ( colFgOld.Ok() )
1557 {
1558 // restore old colour
1559 dc.SetTextForeground(colFgOld);
1560 }
1561 }
1562
1563 // ----------------------------------------------------------------------------
1564 // notebook
1565 // ----------------------------------------------------------------------------
1566
1567 void wxGTKRenderer::DrawTab(wxDC& dc,
1568 const wxRect& rectOrig,
1569 wxDirection dir,
1570 const wxString& label,
1571 const wxBitmap& bitmap,
1572 int flags,
1573 int indexAccel)
1574 {
1575 wxRect rect = rectOrig;
1576
1577 // the current tab is drawn indented (to the top for default case) and
1578 // bigger than the other ones
1579 const wxSize indent = GetTabIndent();
1580 if ( flags & wxCONTROL_SELECTED )
1581 {
1582 switch ( dir )
1583 {
1584 default:
1585 wxFAIL_MSG(_T("invaild notebook tab orientation"));
1586 // fall through
1587
1588 case wxTOP:
1589 rect.Inflate(indent.x, 0);
1590 rect.y -= indent.y;
1591 rect.height += indent.y;
1592 break;
1593
1594 case wxBOTTOM:
1595 rect.Inflate(indent.x, 0);
1596 rect.height += indent.y;
1597 break;
1598
1599 case wxLEFT:
1600 case wxRIGHT:
1601 wxFAIL_MSG(_T("TODO"));
1602 break;
1603 }
1604 }
1605
1606 // selected tab has different colour
1607 wxColour col = flags & wxCONTROL_SELECTED
1608 ? wxSCHEME_COLOUR(m_scheme, SHADOW_IN)
1609 : wxSCHEME_COLOUR(m_scheme, SCROLLBAR);
1610 DoDrawBackground(dc, col, rect);
1611
1612 if ( flags & wxCONTROL_FOCUSED )
1613 {
1614 // draw the focus rect
1615 wxRect rectBorder = rect;
1616 rectBorder.Deflate(4, 3);
1617 if ( dir == wxBOTTOM )
1618 rectBorder.Offset(0, -1);
1619
1620 DrawRect(dc, &rectBorder, m_penBlack);
1621 }
1622
1623 // draw the text, image and the focus around them (if necessary)
1624 wxRect rectLabel = rect;
1625 rectLabel.Deflate(1, 1);
1626 dc.DrawLabel(label, bitmap, rectLabel, wxALIGN_CENTRE, indexAccel);
1627
1628 // now draw the tab itself
1629 wxCoord x = rect.x,
1630 y = rect.y,
1631 x2 = rect.GetRight(),
1632 y2 = rect.GetBottom();
1633 switch ( dir )
1634 {
1635 default:
1636 case wxTOP:
1637 dc.SetPen(m_penHighlight);
1638 dc.DrawLine(x, y2, x, y);
1639 dc.DrawLine(x + 1, y, x2, y);
1640
1641 dc.SetPen(m_penBlack);
1642 dc.DrawLine(x2, y2, x2, y);
1643
1644 dc.SetPen(m_penDarkGrey);
1645 dc.DrawLine(x2 - 1, y2, x2 - 1, y + 1);
1646
1647 if ( flags & wxCONTROL_SELECTED )
1648 {
1649 dc.SetPen(m_penLightGrey);
1650
1651 // overwrite the part of the border below this tab
1652 dc.DrawLine(x + 1, y2 + 1, x2 - 1, y2 + 1);
1653
1654 // and the shadow of the tab to the left of us
1655 dc.DrawLine(x + 1, y + 2, x + 1, y2 + 1);
1656 }
1657 break;
1658
1659 case wxBOTTOM:
1660 dc.SetPen(m_penHighlight);
1661
1662 // we need to continue one pixel further to overwrite the corner of
1663 // the border for the selected tab
1664 dc.DrawLine(x, y - (flags & wxCONTROL_SELECTED ? 1 : 0),
1665 x, y2);
1666
1667 // it doesn't work like this (TODO: implement it properly)
1668 #if 0
1669 // erase the corner of the tab to the right
1670 dc.SetPen(m_penLightGrey);
1671 dc.DrawPoint(x2 - 1, y - 2);
1672 dc.DrawPoint(x2 - 2, y - 2);
1673 dc.DrawPoint(x2 - 2, y - 1);
1674 #endif // 0
1675
1676 dc.SetPen(m_penBlack);
1677 dc.DrawLine(x + 1, y2, x2, y2);
1678 dc.DrawLine(x2, y, x2, y2);
1679
1680 dc.SetPen(m_penDarkGrey);
1681 dc.DrawLine(x + 2, y2 - 1, x2 - 1, y2 - 1);
1682 dc.DrawLine(x2 - 1, y, x2 - 1, y2);
1683
1684 if ( flags & wxCONTROL_SELECTED )
1685 {
1686 dc.SetPen(m_penLightGrey);
1687
1688 // overwrite the part of the (double!) border above this tab
1689 dc.DrawLine(x + 1, y - 1, x2 - 1, y - 1);
1690 dc.DrawLine(x + 1, y - 2, x2 - 1, y - 2);
1691
1692 // and the shadow of the tab to the left of us
1693 dc.DrawLine(x + 1, y2 - 1, x + 1, y - 1);
1694 }
1695 break;
1696
1697 case wxLEFT:
1698 case wxRIGHT:
1699 wxFAIL_MSG(_T("TODO"));
1700 }
1701 }
1702
1703 // ----------------------------------------------------------------------------
1704 // slider
1705 // ----------------------------------------------------------------------------
1706
1707 wxSize wxGTKRenderer::GetSliderThumbSize(const wxRect& rect,
1708 wxOrientation orient) const
1709 {
1710 static const wxCoord SLIDER_THUMB_LENGTH = 30;
1711
1712 wxSize size;
1713
1714 wxRect rectShaft = GetSliderShaftRect(rect, orient);
1715 if ( orient == wxHORIZONTAL )
1716 {
1717 size.x = wxMin(SLIDER_THUMB_LENGTH, rectShaft.width);
1718 size.y = rectShaft.height;
1719 }
1720 else // vertical
1721 {
1722 size.y = wxMin(SLIDER_THUMB_LENGTH, rectShaft.height);
1723 size.x = rectShaft.width;
1724 }
1725
1726 return size;
1727 }
1728
1729 wxRect wxGTKRenderer::GetSliderShaftRect(const wxRect& rect,
1730 wxOrientation WXUNUSED(orient)) const
1731 {
1732 return rect.Deflate(2*BORDER_THICKNESS, 2*BORDER_THICKNESS);
1733 }
1734
1735 void wxGTKRenderer::DrawSliderShaft(wxDC& dc,
1736 const wxRect& rectOrig,
1737 wxOrientation orient,
1738 int flags,
1739 wxRect *rectShaft)
1740 {
1741 wxRect rect = rectOrig;
1742
1743 // draw the border first
1744 if ( flags & wxCONTROL_FOCUSED )
1745 {
1746 DrawRect(dc, &rect, m_penBlack);
1747 DrawAntiShadedRect(dc, &rect, m_penBlack, m_penLightGrey);
1748 }
1749 else // not focused, normal
1750 {
1751 DrawAntiShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
1752 DrawAntiShadedRect(dc, &rect, m_penBlack, m_penLightGrey);
1753 }
1754
1755 // and the background
1756 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), rect);
1757
1758 if ( rectShaft )
1759 *rectShaft = rect;
1760 }
1761
1762 void wxGTKRenderer::DrawSliderThumb(wxDC& dc,
1763 const wxRect& rectOrig,
1764 wxOrientation orient,
1765 int flags)
1766 {
1767 // draw the thumb border
1768 wxRect rect = rectOrig;
1769 DrawAntiRaisedBorder(dc, &rect);
1770
1771 // draw the handle in the middle
1772 if ( orient == wxVERTICAL )
1773 {
1774 rect.height = 2*BORDER_THICKNESS;
1775 rect.y = rectOrig.y + (rectOrig.height - rect.height) / 2;
1776 }
1777 else // horz
1778 {
1779 rect.width = 2*BORDER_THICKNESS;
1780 rect.x = rectOrig.x + (rectOrig.width - rect.width) / 2;
1781 }
1782
1783 DrawShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
1784 }
1785
1786 #if wxUSE_MENUS
1787 // ----------------------------------------------------------------------------
1788 // menu and menubar
1789 // ----------------------------------------------------------------------------
1790
1791 void wxGTKRenderer::DrawMenuBarItem(wxDC& dc,
1792 const wxRect& rect,
1793 const wxString& label,
1794 int flags,
1795 int indexAccel)
1796 {
1797 DrawLabel(dc, label, rect, flags, wxALIGN_CENTRE, indexAccel);
1798 }
1799
1800 void wxGTKRenderer::DrawMenuItem(wxDC& dc,
1801 wxCoord y,
1802 const wxMenuGeometryInfo& geometryInfo,
1803 const wxString& label,
1804 const wxString& accel,
1805 const wxBitmap& bitmap,
1806 int flags,
1807 int indexAccel)
1808 {
1809 wxFAIL_MSG(_T("TODO"));
1810 }
1811
1812 void wxGTKRenderer::DrawMenuSeparator(wxDC& dc,
1813 wxCoord y,
1814 const wxMenuGeometryInfo& geomInfo)
1815 {
1816 wxFAIL_MSG(_T("TODO"));
1817 }
1818
1819 wxSize wxGTKRenderer::GetMenuBarItemSize(const wxSize& sizeText) const
1820 {
1821 return sizeText;
1822 }
1823
1824 wxMenuGeometryInfo *wxGTKRenderer::GetMenuGeometry(wxWindow *win,
1825 const wxMenu& menu) const
1826 {
1827 wxFAIL_MSG(_T("TODO"));
1828
1829 return NULL;
1830 }
1831 #endif // wxUSE_MENUS
1832
1833 // ----------------------------------------------------------------------------
1834 // combobox
1835 // ----------------------------------------------------------------------------
1836
1837 void wxGTKRenderer::InitComboBitmaps()
1838 {
1839 wxSize sizeArrow = m_sizeScrollbarArrow;
1840 sizeArrow.x -= 2;
1841 sizeArrow.y -= 2;
1842
1843 size_t n;
1844
1845 for ( n = ComboState_Normal; n < ComboState_Max; n++ )
1846 {
1847 m_bitmapsCombo[n].Create(sizeArrow.x, sizeArrow.y);
1848 }
1849
1850 static const int comboButtonFlags[ComboState_Max] =
1851 {
1852 0,
1853 wxCONTROL_CURRENT,
1854 wxCONTROL_PRESSED,
1855 wxCONTROL_DISABLED,
1856 };
1857
1858 wxRect rect(wxPoint(0, 0), sizeArrow);
1859
1860 wxMemoryDC dc;
1861 for ( n = ComboState_Normal; n < ComboState_Max; n++ )
1862 {
1863 int flags = comboButtonFlags[n];
1864
1865 dc.SelectObject(m_bitmapsCombo[n]);
1866 DoDrawBackground(dc, GetBackgroundColour(flags), rect);
1867 DrawArrow(dc, wxDOWN, rect, flags);
1868 }
1869 }
1870
1871 void wxGTKRenderer::GetComboBitmaps(wxBitmap *bmpNormal,
1872 wxBitmap *bmpFocus,
1873 wxBitmap *bmpPressed,
1874 wxBitmap *bmpDisabled)
1875 {
1876 if ( !m_bitmapsCombo[ComboState_Normal].Ok() )
1877 {
1878 InitComboBitmaps();
1879 }
1880
1881 if ( bmpNormal )
1882 *bmpNormal = m_bitmapsCombo[ComboState_Normal];
1883 if ( bmpFocus )
1884 *bmpFocus = m_bitmapsCombo[ComboState_Focus];
1885 if ( bmpPressed )
1886 *bmpPressed = m_bitmapsCombo[ComboState_Pressed];
1887 if ( bmpDisabled )
1888 *bmpDisabled = m_bitmapsCombo[ComboState_Disabled];
1889 }
1890
1891 // ----------------------------------------------------------------------------
1892 // background
1893 // ----------------------------------------------------------------------------
1894
1895 void wxGTKRenderer::DoDrawBackground(wxDC& dc,
1896 const wxColour& col,
1897 const wxRect& rect)
1898 {
1899 wxBrush brush(col, wxSOLID);
1900 dc.SetBrush(brush);
1901 dc.SetPen(*wxTRANSPARENT_PEN);
1902 dc.DrawRectangle(rect);
1903 }
1904
1905 void wxGTKRenderer::DrawBackground(wxDC& dc,
1906 const wxColour& col,
1907 const wxRect& rect,
1908 int flags)
1909 {
1910 wxColour colBg = col.Ok() ? col : GetBackgroundColour(flags);
1911 DoDrawBackground(dc, colBg, rect);
1912 }
1913
1914 // ----------------------------------------------------------------------------
1915 // scrollbar
1916 // ----------------------------------------------------------------------------
1917
1918 void wxGTKRenderer::DrawArrowBorder(wxDC& dc,
1919 wxRect *rect,
1920 wxDirection dir)
1921 {
1922 static const wxDirection sides[] =
1923 {
1924 wxUP, wxLEFT, wxRIGHT, wxDOWN
1925 };
1926
1927 wxRect rect1, rect2, rectInner;
1928 rect1 =
1929 rect2 =
1930 rectInner = *rect;
1931
1932 rect2.Inflate(-1);
1933 rectInner.Inflate(-2);
1934
1935 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), *rect);
1936
1937 // find the side not to draw and also adjust the rectangles to compensate
1938 // for it
1939 wxDirection sideToOmit;
1940 switch ( dir )
1941 {
1942 case wxUP:
1943 sideToOmit = wxDOWN;
1944 rect2.height += 1;
1945 rectInner.height += 1;
1946 break;
1947
1948 case wxDOWN:
1949 sideToOmit = wxUP;
1950 rect2.y -= 1;
1951 rect2.height += 1;
1952 rectInner.y -= 2;
1953 rectInner.height += 1;
1954 break;
1955
1956 case wxLEFT:
1957 sideToOmit = wxRIGHT;
1958 rect2.width += 1;
1959 rectInner.width += 1;
1960 break;
1961
1962 case wxRIGHT:
1963 sideToOmit = wxLEFT;
1964 rect2.x -= 1;
1965 rect2.width += 1;
1966 rectInner.x -= 2;
1967 rectInner.width += 1;
1968 break;
1969
1970 default:
1971 wxFAIL_MSG(_T("unknown arrow direction"));
1972 return;
1973 }
1974
1975 // the outer rect first
1976 size_t n;
1977 for ( n = 0; n < WXSIZEOF(sides); n++ )
1978 {
1979 wxDirection side = sides[n];
1980 if ( side == sideToOmit )
1981 continue;
1982
1983 DrawAntiShadedRectSide(dc, rect1, m_penDarkGrey, m_penHighlight, side);
1984 }
1985
1986 // and then the inner one
1987 for ( n = 0; n < WXSIZEOF(sides); n++ )
1988 {
1989 wxDirection side = sides[n];
1990 if ( side == sideToOmit )
1991 continue;
1992
1993 DrawAntiShadedRectSide(dc, rect2, m_penBlack, m_penGrey, side);
1994 }
1995
1996 *rect = rectInner;
1997 }
1998
1999 void wxGTKRenderer::DrawScrollbarArrow(wxDC& dc,
2000 wxDirection dir,
2001 const wxRect& rectArrow,
2002 int flags)
2003 {
2004 // first of all, draw the border around it - but we don't want the border
2005 // on the side opposite to the arrow point
2006 wxRect rect = rectArrow;
2007 DrawArrowBorder(dc, &rect, dir);
2008
2009 // then the arrow itself
2010 DrawArrow(dc, dir, rect, flags);
2011 }
2012
2013 // gtk_default_draw_arrow() takes ~350 lines and we can't do much better here
2014 // these people are just crazy :-(
2015 void wxGTKRenderer::DrawArrow(wxDC& dc,
2016 wxDirection dir,
2017 const wxRect& rect,
2018 int flags)
2019 {
2020 enum
2021 {
2022 Point_First,
2023 Point_Second,
2024 Point_Third,
2025 Point_Max
2026 };
2027
2028 wxPoint ptArrow[Point_Max];
2029
2030 wxColour colInside = GetBackgroundColour(flags);
2031 wxPen penShadow[4];
2032 if ( flags & wxCONTROL_DISABLED )
2033 {
2034 penShadow[0] = m_penDarkGrey;
2035 penShadow[1] = m_penDarkGrey;
2036 penShadow[2] = wxNullPen;
2037 penShadow[3] = wxNullPen;
2038 }
2039 else if ( flags & wxCONTROL_PRESSED )
2040 {
2041 penShadow[0] = m_penDarkGrey;
2042 penShadow[1] = m_penHighlight;
2043 penShadow[2] = wxNullPen;
2044 penShadow[3] = m_penBlack;
2045 }
2046 else // normal arrow
2047 {
2048 penShadow[0] = m_penHighlight;
2049 penShadow[1] = m_penBlack;
2050 penShadow[2] = m_penDarkGrey;
2051 penShadow[3] = wxNullPen;
2052 }
2053
2054 wxCoord middle;
2055 if ( dir == wxUP || dir == wxDOWN )
2056 {
2057 // horz middle
2058 middle = (rect.GetRight() + rect.GetLeft() + 1) / 2;
2059 }
2060 else // horz arrow
2061 {
2062 middle = (rect.GetTop() + rect.GetBottom() + 1) / 2;
2063 }
2064
2065 // draw the arrow interior
2066 dc.SetPen(*wxTRANSPARENT_PEN);
2067 dc.SetBrush(wxBrush(colInside, wxSOLID));
2068
2069 switch ( dir )
2070 {
2071 case wxUP:
2072 ptArrow[Point_First].x = rect.GetLeft();
2073 ptArrow[Point_First].y = rect.GetBottom();
2074 ptArrow[Point_Second].x = middle;
2075 ptArrow[Point_Second].y = rect.GetTop();
2076 ptArrow[Point_Third].x = rect.GetRight();
2077 ptArrow[Point_Third].y = rect.GetBottom();
2078 break;
2079
2080 case wxDOWN:
2081 ptArrow[Point_First] = rect.GetPosition();
2082 ptArrow[Point_Second].x = middle;
2083 ptArrow[Point_Second].y = rect.GetBottom();
2084 ptArrow[Point_Third].x = rect.GetRight();
2085 ptArrow[Point_Third].y = rect.GetTop();
2086 break;
2087
2088 case wxLEFT:
2089 ptArrow[Point_First].x = rect.GetRight();
2090 ptArrow[Point_First].y = rect.GetTop();
2091 ptArrow[Point_Second].x = rect.GetLeft();
2092 ptArrow[Point_Second].y = middle;
2093 ptArrow[Point_Third].x = rect.GetRight();
2094 ptArrow[Point_Third].y = rect.GetBottom();
2095 break;
2096
2097 case wxRIGHT:
2098 ptArrow[Point_First] = rect.GetPosition();
2099 ptArrow[Point_Second].x = rect.GetRight();
2100 ptArrow[Point_Second].y = middle;
2101 ptArrow[Point_Third].x = rect.GetLeft();
2102 ptArrow[Point_Third].y = rect.GetBottom();
2103 break;
2104
2105 default:
2106 wxFAIL_MSG(_T("unknown arrow direction"));
2107 }
2108
2109 dc.DrawPolygon(WXSIZEOF(ptArrow), ptArrow);
2110
2111 // draw the arrow border
2112 dc.SetPen(penShadow[0]);
2113 switch ( dir )
2114 {
2115 case wxUP:
2116 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_First]);
2117 dc.DrawPoint(ptArrow[Point_First]);
2118 if ( penShadow[3].Ok() )
2119 {
2120 dc.SetPen(penShadow[3]);
2121 dc.DrawLine(ptArrow[Point_First].x + 1, ptArrow[Point_First].y,
2122 ptArrow[Point_Second].x, ptArrow[Point_Second].y);
2123 }
2124 dc.SetPen(penShadow[1]);
2125 dc.DrawLine(ptArrow[Point_Second].x + 1, ptArrow[Point_Second].y + 1,
2126 ptArrow[Point_Third].x, ptArrow[Point_Third].y);
2127 dc.DrawPoint(ptArrow[Point_Third]);
2128 dc.DrawLine(ptArrow[Point_Third].x - 2, ptArrow[Point_Third].y,
2129 ptArrow[Point_First].x + 1, ptArrow[Point_First].y);
2130 if ( penShadow[2].Ok() )
2131 {
2132 dc.SetPen(penShadow[2]);
2133 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y,
2134 ptArrow[Point_Second].x, ptArrow[Point_Second].y + 1);
2135 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y - 1,
2136 ptArrow[Point_First].x + 2, ptArrow[Point_First].y - 1);
2137 }
2138 break;
2139
2140 case wxDOWN:
2141 dc.DrawLine(ptArrow[Point_First], ptArrow[Point_Second]);
2142 dc.DrawLine(ptArrow[Point_First].x + 2, ptArrow[Point_First].y,
2143 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y);
2144 if ( penShadow[2].Ok() )
2145 {
2146 dc.SetPen(penShadow[2]);
2147 dc.DrawLine(ptArrow[Point_Second].x, ptArrow[Point_Second].y - 1,
2148 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y - 1);
2149 }
2150 dc.SetPen(penShadow[1]);
2151 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_Third]);
2152 dc.DrawPoint(ptArrow[Point_Third]);
2153 break;
2154
2155 case wxLEFT:
2156 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_First]);
2157 dc.DrawPoint(ptArrow[Point_First]);
2158 if ( penShadow[2].Ok() )
2159 {
2160 dc.SetPen(penShadow[2]);
2161 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y,
2162 ptArrow[Point_First].x - 1, ptArrow[Point_First].y + 2);
2163 dc.DrawLine(ptArrow[Point_Third].x, ptArrow[Point_Third].y,
2164 ptArrow[Point_Second].x + 2, ptArrow[Point_Second].y + 1);
2165 }
2166 dc.SetPen(penShadow[1]);
2167 dc.DrawLine(ptArrow[Point_Third].x, ptArrow[Point_Third].y,
2168 ptArrow[Point_First].x, ptArrow[Point_First].y + 1);
2169 dc.DrawLine(ptArrow[Point_Second].x + 1, ptArrow[Point_Second].y + 1,
2170 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y);
2171 break;
2172
2173 case wxRIGHT:
2174 dc.DrawLine(ptArrow[Point_First], ptArrow[Point_Third]);
2175 dc.DrawLine(ptArrow[Point_First].x + 2, ptArrow[Point_First].y + 1,
2176 ptArrow[Point_Second].x, ptArrow[Point_Second].y);
2177 dc.SetPen(penShadow[1]);
2178 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_Third]);
2179 dc.DrawPoint(ptArrow[Point_Third]);
2180 break;
2181
2182 default:
2183 wxFAIL_MSG(_T("unknown arrow direction"));
2184 return;
2185 }
2186 }
2187
2188 void wxGTKRenderer::DrawThumbBorder(wxDC& dc,
2189 wxRect *rect,
2190 wxOrientation orient)
2191 {
2192 if ( orient == wxVERTICAL )
2193 {
2194 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2195 wxLEFT);
2196 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2197 wxRIGHT);
2198 rect->Inflate(-1, 0);
2199
2200 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2201 wxLEFT);
2202 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2203 wxRIGHT);
2204 rect->Inflate(-1, 0);
2205 }
2206 else
2207 {
2208 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2209 wxUP);
2210 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2211 wxDOWN);
2212 rect->Inflate(0, -1);
2213
2214 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2215 wxUP);
2216 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2217 wxDOWN);
2218 rect->Inflate(0, -1);
2219 }
2220 }
2221
2222 void wxGTKRenderer::DrawScrollbarThumb(wxDC& dc,
2223 wxOrientation orient,
2224 const wxRect& rect,
2225 int flags)
2226 {
2227 // the thumb is never pressed never has focus border under GTK and the
2228 // scrollbar background never changes at all
2229 int flagsThumb = flags & ~(wxCONTROL_PRESSED | wxCONTROL_FOCUSED);
2230
2231 // we don't want the border in the direction of the scrollbar movement
2232 wxRect rectThumb = rect;
2233 DrawThumbBorder(dc, &rectThumb, orient);
2234
2235 DrawButtonBorder(dc, rectThumb, flagsThumb, &rectThumb);
2236 DrawBackground(dc, wxNullColour, rectThumb, flagsThumb);
2237 }
2238
2239 void wxGTKRenderer::DrawScrollbarShaft(wxDC& dc,
2240 wxOrientation orient,
2241 const wxRect& rect,
2242 int flags)
2243 {
2244 wxRect rectBar = rect;
2245 DrawThumbBorder(dc, &rectBar, orient);
2246 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), rectBar);
2247 }
2248
2249 void wxGTKRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
2250 {
2251 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
2252 }
2253
2254 wxRect wxGTKRenderer::GetScrollbarRect(const wxScrollBar *scrollbar,
2255 wxScrollBar::Element elem,
2256 int thumbPos) const
2257 {
2258 // as GTK scrollbars can't be disabled, it makes no sense to remove the
2259 // thumb for a scrollbar with range 0 - instead, make it fill the entire
2260 // scrollbar shaft
2261 if ( (elem == wxScrollBar::Element_Thumb) && !scrollbar->GetRange() )
2262 {
2263 elem = wxScrollBar::Element_Bar_2;
2264 }
2265
2266 return StandardGetScrollbarRect(scrollbar, elem,
2267 thumbPos,
2268 GetScrollbarArrowSize(scrollbar));
2269 }
2270
2271 wxCoord wxGTKRenderer::GetScrollbarSize(const wxScrollBar *scrollbar)
2272 {
2273 return StandardScrollBarSize(scrollbar, GetScrollbarArrowSize(scrollbar));
2274 }
2275
2276 wxHitTest wxGTKRenderer::HitTestScrollbar(const wxScrollBar *scrollbar,
2277 const wxPoint& pt) const
2278 {
2279 return StandardHitTestScrollbar(scrollbar, pt,
2280 GetScrollbarArrowSize(scrollbar));
2281 }
2282
2283 wxCoord wxGTKRenderer::ScrollbarToPixel(const wxScrollBar *scrollbar,
2284 int thumbPos)
2285 {
2286 return StandardScrollbarToPixel(scrollbar, thumbPos,
2287 GetScrollbarArrowSize(scrollbar));
2288 }
2289
2290 int wxGTKRenderer::PixelToScrollbar(const wxScrollBar *scrollbar,
2291 wxCoord coord)
2292 {
2293 return StandardPixelToScrollbar(scrollbar, coord,
2294 GetScrollbarArrowSize(scrollbar));
2295 }
2296
2297 // ----------------------------------------------------------------------------
2298 // size adjustments
2299 // ----------------------------------------------------------------------------
2300
2301 void wxGTKRenderer::AdjustSize(wxSize *size, const wxWindow *window)
2302 {
2303 #if wxUSE_BMPBUTTON
2304 if ( wxDynamicCast(window, wxBitmapButton) )
2305 {
2306 size->x += 4;
2307 size->y += 4;
2308 } else
2309 #endif // wxUSE_BMPBUTTON
2310 #if wxUSE_BUTTON
2311 if ( wxDynamicCast(window, wxButton) )
2312 {
2313 if ( !(window->GetWindowStyle() & wxBU_EXACTFIT) )
2314 {
2315 // TODO: this is ad hoc...
2316 size->x += 3*window->GetCharWidth();
2317 wxCoord minBtnHeight = 18;
2318 if ( size->y < minBtnHeight )
2319 size->y = minBtnHeight;
2320
2321 // button border width
2322 size->y += 4;
2323 }
2324 } else
2325 #endif wxUSE_BUTTON
2326 if ( wxDynamicCast(window, wxScrollBar) )
2327 {
2328 // we only set the width of vert scrollbars and height of the
2329 // horizontal ones
2330 if ( window->GetWindowStyle() & wxSB_HORIZONTAL )
2331 size->y = m_sizeScrollbarArrow.x;
2332 else
2333 size->x = m_sizeScrollbarArrow.x;
2334 }
2335 else
2336 {
2337 // take into account the border width
2338 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
2339 size->x += rectBorder.x + rectBorder.width;
2340 size->y += rectBorder.y + rectBorder.height;
2341 }
2342 }
2343
2344 // ============================================================================
2345 // wxInputHandler
2346 // ============================================================================
2347
2348 // ----------------------------------------------------------------------------
2349 // wxGTKInputHandler
2350 // ----------------------------------------------------------------------------
2351
2352 wxGTKInputHandler::wxGTKInputHandler(wxGTKRenderer *renderer)
2353 {
2354 m_renderer = renderer;
2355 }
2356
2357 bool wxGTKInputHandler::HandleKey(wxControl *control,
2358 const wxKeyEvent& event,
2359 bool pressed)
2360 {
2361 return FALSE;
2362 }
2363
2364 bool wxGTKInputHandler::HandleMouse(wxControl *control,
2365 const wxMouseEvent& event)
2366 {
2367 // clicking on the control gives it focus
2368 if ( event.ButtonDown() )
2369 {
2370 control->SetFocus();
2371
2372 return TRUE;
2373 }
2374
2375 return FALSE;
2376 }
2377
2378 bool wxGTKInputHandler::HandleMouseMove(wxControl *control,
2379 const wxMouseEvent& event)
2380 {
2381 if ( event.Entering() )
2382 {
2383 control->SetCurrent(TRUE);
2384 }
2385 else if ( event.Leaving() )
2386 {
2387 control->SetCurrent(FALSE);
2388 }
2389 else
2390 {
2391 return FALSE;
2392 }
2393
2394 return TRUE;
2395 }
2396
2397 // ----------------------------------------------------------------------------
2398 // wxGTKCheckboxInputHandler
2399 // ----------------------------------------------------------------------------
2400
2401 bool wxGTKCheckboxInputHandler::HandleKey(wxControl *control,
2402 const wxKeyEvent& event,
2403 bool pressed)
2404 {
2405 if ( pressed )
2406 {
2407 int keycode = event.GetKeyCode();
2408 if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
2409 {
2410 control->PerformAction(wxACTION_CHECKBOX_TOGGLE);
2411
2412 return TRUE;
2413 }
2414 }
2415
2416 return FALSE;
2417 }
2418
2419 // ----------------------------------------------------------------------------
2420 // wxGTKTextCtrlInputHandler
2421 // ----------------------------------------------------------------------------
2422
2423 bool wxGTKTextCtrlInputHandler::HandleKey(wxControl *control,
2424 const wxKeyEvent& event,
2425 bool pressed)
2426 {
2427 // handle only GTK-specific text bindings here, the others are handled in
2428 // the base class
2429 if ( pressed )
2430 {
2431 wxControlAction action;
2432 int keycode = event.GetKeyCode();
2433 if ( event.ControlDown() )
2434 {
2435 switch ( keycode )
2436 {
2437 case 'A':
2438 action = wxACTION_TEXT_HOME;
2439 break;
2440
2441 case 'B':
2442 action = wxACTION_TEXT_LEFT;
2443 break;
2444
2445 case 'D':
2446 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_RIGHT;
2447 break;
2448
2449 case 'E':
2450 action = wxACTION_TEXT_END;
2451 break;
2452
2453 case 'F':
2454 action = wxACTION_TEXT_RIGHT;
2455 break;
2456
2457 case 'H':
2458 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_LEFT;
2459 break;
2460
2461 case 'K':
2462 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_END;
2463 break;
2464
2465 case 'N':
2466 action = wxACTION_TEXT_DOWN;
2467 break;
2468
2469 case 'P':
2470 action = wxACTION_TEXT_UP;
2471 break;
2472
2473 case 'U':
2474 //delete the entire line
2475 control->PerformAction(wxACTION_TEXT_HOME);
2476 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_END;
2477 break;
2478
2479 case 'W':
2480 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_WORD_LEFT;
2481 break;
2482 }
2483 }
2484 else if ( event.AltDown() )
2485 {
2486 switch ( keycode )
2487 {
2488 case 'B':
2489 action = wxACTION_TEXT_WORD_LEFT;
2490 break;
2491
2492 case 'D':
2493 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_WORD_RIGHT;
2494 break;
2495
2496 case 'F':
2497 action = wxACTION_TEXT_WORD_RIGHT;
2498 break;
2499 }
2500 }
2501
2502 if ( action != wxACTION_NONE )
2503 {
2504 control->PerformAction(action);
2505
2506 return TRUE;
2507 }
2508 }
2509
2510 return wxStdTextCtrlInputHandler::HandleKey(control, event, pressed);
2511 }