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