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