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