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