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