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