]> git.saurik.com Git - wxWidgets.git/blame - src/univ/themes/gtk.cpp
removed obsolete comment
[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
3379ed37
VZ
1457static const int TEXT_BORDER = 2;
1458
1e6feb95
VZ
1459wxRect wxGTKRenderer::GetTextTotalArea(const wxTextCtrl *text,
1460 const wxRect& rect)
1461{
1462 wxRect rectTotal = rect;
3379ed37 1463 rectTotal.Inflate(TEXT_BORDER);
1e6feb95
VZ
1464 return rectTotal;
1465}
1466
1467wxRect wxGTKRenderer::GetTextClientArea(const wxTextCtrl *text,
1468 const wxRect& rect,
1469 wxCoord *extraSpaceBeyond)
1470{
1471 wxRect rectText = rect;
3379ed37 1472 rectText.Inflate(-TEXT_BORDER);
1e6feb95
VZ
1473
1474 if ( text->WrapLines() )
1475 {
1476 // leave enough for the line wrap bitmap indicator
1477 wxCoord widthMark = GetLineWrapBitmap().GetWidth() + 2;
1478
1479 rectText.width -= widthMark;
1480
1481 if ( extraSpaceBeyond )
1482 *extraSpaceBeyond = widthMark;
1483 }
1484
1485 return rectText;
1486}
1487
1488void wxGTKRenderer::DrawTextLine(wxDC& dc,
1489 const wxString& text,
1490 const wxRect& rect,
1491 int selStart,
1492 int selEnd,
1493 int flags)
1494{
1495 // TODO: GTK+ draws selection even for unfocused controls, just with
1496 // different colours
1497 StandardDrawTextLine(dc, text, rect, selStart, selEnd, flags);
1498}
1499
1500void wxGTKRenderer::DrawLineWrapMark(wxDC& dc, const wxRect& rect)
1501{
1502 wxBitmap bmpLineWrap = GetLineWrapBitmap();
1503
1504 // for a mono bitmap he colours it appears in depends on the current text
1505 // colours, so set them correctly
1506 wxColour colFgOld;
1507 if ( bmpLineWrap.GetDepth() == 1 )
1508 {
1509 colFgOld = dc.GetTextForeground();
1510
1511 // FIXME: I wonder what should we do if the background is black too?
1512 dc.SetTextForeground(*wxBLACK);
1513 }
1514
1515 dc.DrawBitmap(bmpLineWrap,
1516 rect.x, rect.y + (rect.height - bmpLineWrap.GetHeight())/2);
1517
1518 if ( colFgOld.Ok() )
1519 {
1520 // restore old colour
1521 dc.SetTextForeground(colFgOld);
1522 }
1523}
1524
1525// ----------------------------------------------------------------------------
1526// notebook
1527// ----------------------------------------------------------------------------
1528
1529void wxGTKRenderer::DrawTab(wxDC& dc,
1530 const wxRect& rectOrig,
1531 wxDirection dir,
1532 const wxString& label,
1533 const wxBitmap& bitmap,
1534 int flags,
1535 int indexAccel)
1536{
1537 wxRect rect = rectOrig;
1538
1539 // the current tab is drawn indented (to the top for default case) and
1540 // bigger than the other ones
1541 const wxSize indent = GetTabIndent();
1542 if ( flags & wxCONTROL_SELECTED )
1543 {
1544 switch ( dir )
1545 {
1546 default:
1547 wxFAIL_MSG(_T("invaild notebook tab orientation"));
1548 // fall through
1549
1550 case wxTOP:
1551 rect.Inflate(indent.x, 0);
1552 rect.y -= indent.y;
1553 rect.height += indent.y;
1554 break;
1555
1556 case wxBOTTOM:
1557 rect.Inflate(indent.x, 0);
1558 rect.height += indent.y;
1559 break;
1560
1561 case wxLEFT:
1562 case wxRIGHT:
1563 wxFAIL_MSG(_T("TODO"));
1564 break;
1565 }
1566 }
1567
1568 // selected tab has different colour
1569 wxColour col = flags & wxCONTROL_SELECTED
1570 ? wxSCHEME_COLOUR(m_scheme, SHADOW_IN)
1571 : wxSCHEME_COLOUR(m_scheme, SCROLLBAR);
1572 DoDrawBackground(dc, col, rect);
1573
1574 if ( flags & wxCONTROL_FOCUSED )
1575 {
1576 // draw the focus rect
1577 wxRect rectBorder = rect;
1578 rectBorder.Deflate(4, 3);
1579 if ( dir == wxBOTTOM )
1580 rectBorder.Offset(0, -1);
1581
1582 DrawRect(dc, &rectBorder, m_penBlack);
1583 }
1584
1585 // draw the text, image and the focus around them (if necessary)
1586 wxRect rectLabel = rect;
1587 rectLabel.Deflate(1, 1);
1588 dc.DrawLabel(label, bitmap, rectLabel, wxALIGN_CENTRE, indexAccel);
1589
1590 // now draw the tab itself
1591 wxCoord x = rect.x,
1592 y = rect.y,
1593 x2 = rect.GetRight(),
1594 y2 = rect.GetBottom();
1595 switch ( dir )
1596 {
1597 default:
1598 case wxTOP:
1599 dc.SetPen(m_penHighlight);
1600 dc.DrawLine(x, y2, x, y);
1601 dc.DrawLine(x + 1, y, x2, y);
1602
1603 dc.SetPen(m_penBlack);
1604 dc.DrawLine(x2, y2, x2, y);
1605
1606 dc.SetPen(m_penDarkGrey);
1607 dc.DrawLine(x2 - 1, y2, x2 - 1, y + 1);
1608
1609 if ( flags & wxCONTROL_SELECTED )
1610 {
1611 dc.SetPen(m_penLightGrey);
1612
1613 // overwrite the part of the border below this tab
1614 dc.DrawLine(x + 1, y2 + 1, x2 - 1, y2 + 1);
1615
1616 // and the shadow of the tab to the left of us
1617 dc.DrawLine(x + 1, y + 2, x + 1, y2 + 1);
1618 }
1619 break;
1620
1621 case wxBOTTOM:
1622 dc.SetPen(m_penHighlight);
1623
1624 // we need to continue one pixel further to overwrite the corner of
1625 // the border for the selected tab
1626 dc.DrawLine(x, y - (flags & wxCONTROL_SELECTED ? 1 : 0),
1627 x, y2);
1628
1629 // it doesn't work like this (TODO: implement it properly)
1630#if 0
1631 // erase the corner of the tab to the right
1632 dc.SetPen(m_penLightGrey);
1633 dc.DrawPoint(x2 - 1, y - 2);
1634 dc.DrawPoint(x2 - 2, y - 2);
1635 dc.DrawPoint(x2 - 2, y - 1);
1636#endif // 0
1637
1638 dc.SetPen(m_penBlack);
1639 dc.DrawLine(x + 1, y2, x2, y2);
1640 dc.DrawLine(x2, y, x2, y2);
1641
1642 dc.SetPen(m_penDarkGrey);
1643 dc.DrawLine(x + 2, y2 - 1, x2 - 1, y2 - 1);
1644 dc.DrawLine(x2 - 1, y, x2 - 1, y2);
1645
1646 if ( flags & wxCONTROL_SELECTED )
1647 {
1648 dc.SetPen(m_penLightGrey);
1649
1650 // overwrite the part of the (double!) border above this tab
1651 dc.DrawLine(x + 1, y - 1, x2 - 1, y - 1);
1652 dc.DrawLine(x + 1, y - 2, x2 - 1, y - 2);
1653
1654 // and the shadow of the tab to the left of us
1655 dc.DrawLine(x + 1, y2 - 1, x + 1, y - 1);
1656 }
1657 break;
1658
1659 case wxLEFT:
1660 case wxRIGHT:
1661 wxFAIL_MSG(_T("TODO"));
1662 }
1663}
1664
1665// ----------------------------------------------------------------------------
1666// slider
1667// ----------------------------------------------------------------------------
1668
1669wxSize wxGTKRenderer::GetSliderThumbSize(const wxRect& rect,
1670 wxOrientation orient) const
1671{
1672 static const wxCoord SLIDER_THUMB_LENGTH = 30;
1673
1674 wxSize size;
1675
1676 wxRect rectShaft = GetSliderShaftRect(rect, orient);
1677 if ( orient == wxHORIZONTAL )
1678 {
1679 size.x = wxMin(SLIDER_THUMB_LENGTH, rectShaft.width);
1680 size.y = rectShaft.height;
1681 }
1682 else // vertical
1683 {
1684 size.y = wxMin(SLIDER_THUMB_LENGTH, rectShaft.height);
1685 size.x = rectShaft.width;
1686 }
1687
1688 return size;
1689}
1690
1691wxRect wxGTKRenderer::GetSliderShaftRect(const wxRect& rect,
1692 wxOrientation WXUNUSED(orient)) const
1693{
1694 return rect.Deflate(2*BORDER_THICKNESS, 2*BORDER_THICKNESS);
1695}
1696
1697void wxGTKRenderer::DrawSliderShaft(wxDC& dc,
1698 const wxRect& rectOrig,
1699 wxOrientation orient,
1700 int flags,
1701 wxRect *rectShaft)
1702{
1703 wxRect rect = rectOrig;
1704
1705 // draw the border first
1706 if ( flags & wxCONTROL_FOCUSED )
1707 {
1708 DrawRect(dc, &rect, m_penBlack);
1709 DrawAntiShadedRect(dc, &rect, m_penBlack, m_penLightGrey);
1710 }
1711 else // not focused, normal
1712 {
1713 DrawAntiShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
1714 DrawAntiShadedRect(dc, &rect, m_penBlack, m_penLightGrey);
1715 }
1716
1717 // and the background
1718 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), rect);
1719
1720 if ( rectShaft )
1721 *rectShaft = rect;
1722}
1723
1724void wxGTKRenderer::DrawSliderThumb(wxDC& dc,
1725 const wxRect& rectOrig,
1726 wxOrientation orient,
1727 int flags)
1728{
1729 // draw the thumb border
1730 wxRect rect = rectOrig;
1731 DrawAntiRaisedBorder(dc, &rect);
1732
1733 // draw the handle in the middle
1734 if ( orient == wxVERTICAL )
1735 {
1736 rect.height = 2*BORDER_THICKNESS;
1737 rect.y = rectOrig.y + (rectOrig.height - rect.height) / 2;
1738 }
1739 else // horz
1740 {
1741 rect.width = 2*BORDER_THICKNESS;
1742 rect.x = rectOrig.x + (rectOrig.width - rect.width) / 2;
1743 }
1744
1745 DrawShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight);
1746}
1747
1748// ----------------------------------------------------------------------------
1749// menu and menubar
1750// ----------------------------------------------------------------------------
1751
1752void wxGTKRenderer::DrawMenuBarItem(wxDC& dc,
1753 const wxRect& rect,
1754 const wxString& label,
1755 int flags,
1756 int indexAccel)
1757{
1758 DrawLabel(dc, label, rect, flags, wxALIGN_CENTRE, indexAccel);
1759}
1760
1761void wxGTKRenderer::DrawMenuItem(wxDC& dc,
1762 wxCoord y,
1763 const wxMenuGeometryInfo& geometryInfo,
1764 const wxString& label,
1765 const wxString& accel,
1766 const wxBitmap& bitmap,
1767 int flags,
1768 int indexAccel)
1769{
1770 wxFAIL_MSG(_T("TODO"));
1771}
1772
1773void wxGTKRenderer::DrawMenuSeparator(wxDC& dc,
1774 wxCoord y,
1775 const wxMenuGeometryInfo& geomInfo)
1776{
1777 wxFAIL_MSG(_T("TODO"));
1778}
1779
1780wxSize wxGTKRenderer::GetMenuBarItemSize(const wxSize& sizeText) const
1781{
1782 return sizeText;
1783}
1784
1785wxMenuGeometryInfo *wxGTKRenderer::GetMenuGeometry(wxWindow *win,
1786 const wxMenu& menu) const
1787{
1788 wxFAIL_MSG(_T("TODO"));
1789
1790 return NULL;
1791}
1792
1793// ----------------------------------------------------------------------------
1794// combobox
1795// ----------------------------------------------------------------------------
1796
1797void wxGTKRenderer::GetComboBitmaps(wxBitmap *bmpNormal,
1798 wxBitmap *bmpPressed,
1799 wxBitmap *bmpDisabled)
1800{
1801 // TODO
1802}
1803
1804// ----------------------------------------------------------------------------
1805// background
1806// ----------------------------------------------------------------------------
1807
1808void wxGTKRenderer::DoDrawBackground(wxDC& dc,
1809 const wxColour& col,
1810 const wxRect& rect)
1811{
1812 wxBrush brush(col, wxSOLID);
1813 dc.SetBrush(brush);
1814 dc.SetPen(*wxTRANSPARENT_PEN);
1815 dc.DrawRectangle(rect);
1816}
1817
1818void wxGTKRenderer::DrawBackground(wxDC& dc,
1819 const wxColour& col,
1820 const wxRect& rect,
1821 int flags)
1822{
1823 wxColour colBg = col.Ok() ? col : GetBackgroundColour(flags);
1824 DoDrawBackground(dc, colBg, rect);
1825}
1826
1827// ----------------------------------------------------------------------------
1828// scrollbar
1829// ----------------------------------------------------------------------------
1830
1831void wxGTKRenderer::DrawArrowBorder(wxDC& dc,
1832 wxRect *rect,
1833 wxDirection dir)
1834{
1835 static const wxDirection sides[] =
1836 {
1837 wxUP, wxLEFT, wxRIGHT, wxDOWN
1838 };
1839
1840 wxRect rect1, rect2, rectInner;
1841 rect1 =
1842 rect2 =
1843 rectInner = *rect;
1844
1845 rect2.Inflate(-1);
1846 rectInner.Inflate(-2);
1847
1848 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), *rect);
1849
1850 // find the side not to draw and also adjust the rectangles to compensate
1851 // for it
1852 wxDirection sideToOmit;
1853 switch ( dir )
1854 {
1855 case wxUP:
1856 sideToOmit = wxDOWN;
1857 rect2.height += 1;
1858 rectInner.height += 1;
1859 break;
1860
1861 case wxDOWN:
1862 sideToOmit = wxUP;
1863 rect2.y -= 1;
1864 rect2.height += 1;
1865 rectInner.y -= 2;
1866 rectInner.height += 1;
1867 break;
1868
1869 case wxLEFT:
1870 sideToOmit = wxRIGHT;
1871 rect2.width += 1;
1872 rectInner.width += 1;
1873 break;
1874
1875 case wxRIGHT:
1876 sideToOmit = wxLEFT;
1877 rect2.x -= 1;
1878 rect2.width += 1;
1879 rectInner.x -= 2;
1880 rectInner.width += 1;
1881 break;
1882
1883 default:
1884 wxFAIL_MSG(_T("unknown arrow direction"));
1885 return;
1886 }
1887
1888 // the outer rect first
1889 size_t n;
1890 for ( n = 0; n < WXSIZEOF(sides); n++ )
1891 {
1892 wxDirection side = sides[n];
1893 if ( side == sideToOmit )
1894 continue;
1895
1896 DrawAntiShadedRectSide(dc, rect1, m_penDarkGrey, m_penHighlight, side);
1897 }
1898
1899 // and then the inner one
1900 for ( n = 0; n < WXSIZEOF(sides); n++ )
1901 {
1902 wxDirection side = sides[n];
1903 if ( side == sideToOmit )
1904 continue;
1905
1906 DrawAntiShadedRectSide(dc, rect2, m_penBlack, m_penGrey, side);
1907 }
1908
1909 *rect = rectInner;
1910}
1911
1912void wxGTKRenderer::DrawScrollbarArrow(wxDC& dc,
1913 wxDirection dir,
1914 const wxRect& rectArrow,
1915 int flags)
1916{
1917 // first of all, draw the border around it - but we don't want the border
1918 // on the side opposite to the arrow point
1919 wxRect rect = rectArrow;
1920 DrawArrowBorder(dc, &rect, dir);
1921
1922 // then the arrow itself
1923 DrawArrow(dc, dir, rect, flags);
1924}
1925
1926// gtk_default_draw_arrow() takes ~350 lines and we can't do much better here
1927// these people are just crazy :-(
1928void wxGTKRenderer::DrawArrow(wxDC& dc,
1929 wxDirection dir,
1930 const wxRect& rect,
1931 int flags)
1932{
1933 enum
1934 {
1935 Point_First,
1936 Point_Second,
1937 Point_Third,
1938 Point_Max
1939 };
1940
1941 wxPoint ptArrow[Point_Max];
1942
1943 wxColour colInside = GetBackgroundColour(flags);
1944 wxPen penShadow[4];
1945 if ( flags & wxCONTROL_DISABLED )
1946 {
1947 penShadow[0] = m_penDarkGrey;
1948 penShadow[1] = m_penDarkGrey;
1949 penShadow[2] = wxNullPen;
1950 penShadow[3] = wxNullPen;
1951 }
1952 else if ( flags & wxCONTROL_PRESSED )
1953 {
1954 penShadow[0] = m_penDarkGrey;
1955 penShadow[1] = m_penHighlight;
1956 penShadow[2] = wxNullPen;
1957 penShadow[3] = m_penBlack;
1958 }
1959 else // normal arrow
1960 {
1961 penShadow[0] = m_penHighlight;
1962 penShadow[1] = m_penBlack;
1963 penShadow[2] = m_penDarkGrey;
1964 penShadow[3] = wxNullPen;
1965 }
1966
1967 wxCoord middle;
1968 if ( dir == wxUP || dir == wxDOWN )
1969 {
1970 // horz middle
1971 middle = (rect.GetRight() + rect.GetLeft() + 1) / 2;
1972 }
1973 else // horz arrow
1974 {
1975 middle = (rect.GetTop() + rect.GetBottom() + 1) / 2;
1976 }
1977
1978 // draw the arrow interior
1979 dc.SetPen(*wxTRANSPARENT_PEN);
1980 dc.SetBrush(wxBrush(colInside, wxSOLID));
1981
1982 switch ( dir )
1983 {
1984 case wxUP:
1985 ptArrow[Point_First].x = rect.GetLeft();
1986 ptArrow[Point_First].y = rect.GetBottom();
1987 ptArrow[Point_Second].x = middle;
1988 ptArrow[Point_Second].y = rect.GetTop();
1989 ptArrow[Point_Third].x = rect.GetRight();
1990 ptArrow[Point_Third].y = rect.GetBottom();
1991 break;
1992
1993 case wxDOWN:
1994 ptArrow[Point_First] = rect.GetPosition();
1995 ptArrow[Point_Second].x = middle;
1996 ptArrow[Point_Second].y = rect.GetBottom();
1997 ptArrow[Point_Third].x = rect.GetRight();
1998 ptArrow[Point_Third].y = rect.GetTop();
1999 break;
2000
2001 case wxLEFT:
2002 ptArrow[Point_First].x = rect.GetRight();
2003 ptArrow[Point_First].y = rect.GetTop();
2004 ptArrow[Point_Second].x = rect.GetLeft();
2005 ptArrow[Point_Second].y = middle;
2006 ptArrow[Point_Third].x = rect.GetRight();
2007 ptArrow[Point_Third].y = rect.GetBottom();
2008 break;
2009
2010 case wxRIGHT:
2011 ptArrow[Point_First] = rect.GetPosition();
2012 ptArrow[Point_Second].x = rect.GetRight();
2013 ptArrow[Point_Second].y = middle;
2014 ptArrow[Point_Third].x = rect.GetLeft();
2015 ptArrow[Point_Third].y = rect.GetBottom();
2016 break;
2017
2018 default:
2019 wxFAIL_MSG(_T("unknown arrow direction"));
2020 }
2021
2022 dc.DrawPolygon(WXSIZEOF(ptArrow), ptArrow);
2023
2024 // draw the arrow border
2025 dc.SetPen(penShadow[0]);
2026 switch ( dir )
2027 {
2028 case wxUP:
2029 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_First]);
2030 dc.DrawPoint(ptArrow[Point_First]);
2031 if ( penShadow[3].Ok() )
2032 {
2033 dc.SetPen(penShadow[3]);
2034 dc.DrawLine(ptArrow[Point_First].x + 1, ptArrow[Point_First].y,
2035 ptArrow[Point_Second].x, ptArrow[Point_Second].y);
2036 }
2037 dc.SetPen(penShadow[1]);
2038 dc.DrawLine(ptArrow[Point_Second].x + 1, ptArrow[Point_Second].y + 1,
2039 ptArrow[Point_Third].x, ptArrow[Point_Third].y);
2040 dc.DrawPoint(ptArrow[Point_Third]);
2041 dc.DrawLine(ptArrow[Point_Third].x - 2, ptArrow[Point_Third].y,
2042 ptArrow[Point_First].x + 1, ptArrow[Point_First].y);
2043 if ( penShadow[2].Ok() )
2044 {
2045 dc.SetPen(penShadow[2]);
2046 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y,
2047 ptArrow[Point_Second].x, ptArrow[Point_Second].y + 1);
2048 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y - 1,
2049 ptArrow[Point_First].x + 2, ptArrow[Point_First].y - 1);
2050 }
2051 break;
2052
2053 case wxDOWN:
2054 dc.DrawLine(ptArrow[Point_First], ptArrow[Point_Second]);
2055 dc.DrawLine(ptArrow[Point_First].x + 2, ptArrow[Point_First].y,
2056 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y);
2057 if ( penShadow[2].Ok() )
2058 {
2059 dc.SetPen(penShadow[2]);
2060 dc.DrawLine(ptArrow[Point_Second].x, ptArrow[Point_Second].y - 1,
2061 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y - 1);
2062 }
2063 dc.SetPen(penShadow[1]);
2064 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_Third]);
2065 dc.DrawPoint(ptArrow[Point_Third]);
2066 break;
2067
2068 case wxLEFT:
2069 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_First]);
2070 dc.DrawPoint(ptArrow[Point_First]);
2071 if ( penShadow[2].Ok() )
2072 {
2073 dc.SetPen(penShadow[2]);
2074 dc.DrawLine(ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y,
2075 ptArrow[Point_First].x - 1, ptArrow[Point_First].y + 2);
2076 dc.DrawLine(ptArrow[Point_Third].x, ptArrow[Point_Third].y,
2077 ptArrow[Point_Second].x + 2, ptArrow[Point_Second].y + 1);
2078 }
2079 dc.SetPen(penShadow[1]);
2080 dc.DrawLine(ptArrow[Point_Third].x, ptArrow[Point_Third].y,
2081 ptArrow[Point_First].x, ptArrow[Point_First].y + 1);
2082 dc.DrawLine(ptArrow[Point_Second].x + 1, ptArrow[Point_Second].y + 1,
2083 ptArrow[Point_Third].x - 1, ptArrow[Point_Third].y);
2084 break;
2085
2086 case wxRIGHT:
2087 dc.DrawLine(ptArrow[Point_First], ptArrow[Point_Third]);
2088 dc.DrawLine(ptArrow[Point_First].x + 2, ptArrow[Point_First].y + 1,
2089 ptArrow[Point_Second].x, ptArrow[Point_Second].y);
2090 dc.SetPen(penShadow[1]);
2091 dc.DrawLine(ptArrow[Point_Second], ptArrow[Point_Third]);
2092 dc.DrawPoint(ptArrow[Point_Third]);
2093 break;
2094
2095 default:
2096 wxFAIL_MSG(_T("unknown arrow direction"));
2097 return;
2098 }
2099}
2100
2101void wxGTKRenderer::DrawThumbBorder(wxDC& dc,
2102 wxRect *rect,
2103 wxOrientation orient)
2104{
2105 if ( orient == wxVERTICAL )
2106 {
2107 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2108 wxLEFT);
2109 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2110 wxRIGHT);
2111 rect->Inflate(-1, 0);
2112
2113 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2114 wxLEFT);
2115 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2116 wxRIGHT);
2117 rect->Inflate(-1, 0);
2118 }
2119 else
2120 {
2121 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2122 wxUP);
2123 DrawAntiShadedRectSide(dc, *rect, m_penDarkGrey, m_penHighlight,
2124 wxDOWN);
2125 rect->Inflate(0, -1);
2126
2127 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2128 wxUP);
2129 DrawAntiShadedRectSide(dc, *rect, m_penBlack, m_penGrey,
2130 wxDOWN);
2131 rect->Inflate(0, -1);
2132 }
2133}
2134
2135void wxGTKRenderer::DrawScrollbarThumb(wxDC& dc,
2136 wxOrientation orient,
2137 const wxRect& rect,
2138 int flags)
2139{
2140 // the thumb is never pressed never has focus border under GTK and the
2141 // scrollbar background never changes at all
2142 int flagsThumb = flags & ~(wxCONTROL_PRESSED | wxCONTROL_FOCUSED);
2143
2144 // we don't want the border in the direction of the scrollbar movement
2145 wxRect rectThumb = rect;
2146 DrawThumbBorder(dc, &rectThumb, orient);
2147
2148 DrawButtonBorder(dc, rectThumb, flagsThumb, &rectThumb);
2149 DrawBackground(dc, wxNullColour, rectThumb, flagsThumb);
2150}
2151
2152void wxGTKRenderer::DrawScrollbarShaft(wxDC& dc,
2153 wxOrientation orient,
2154 const wxRect& rect,
2155 int flags)
2156{
2157 wxRect rectBar = rect;
2158 DrawThumbBorder(dc, &rectBar, orient);
2159 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, SCROLLBAR), rectBar);
2160}
2161
2162void wxGTKRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
2163{
2164 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
2165}
2166
2167wxRect wxGTKRenderer::GetScrollbarRect(const wxScrollBar *scrollbar,
2168 wxScrollBar::Element elem,
2169 int thumbPos) const
2170{
2171 // as GTK scrollbars can't be disabled, it makes no sense to remove the
2172 // thumb for a scrollbar with range 0 - instead, make it fill the entire
2173 // scrollbar shaft
2174 if ( (elem == wxScrollBar::Element_Thumb) && !scrollbar->GetRange() )
2175 {
2176 elem = wxScrollBar::Element_Bar_2;
2177 }
2178
2179 return StandardGetScrollbarRect(scrollbar, elem,
2180 thumbPos,
2181 GetScrollbarArrowSize(scrollbar));
2182}
2183
2184wxCoord wxGTKRenderer::GetScrollbarSize(const wxScrollBar *scrollbar)
2185{
2186 return StandardScrollBarSize(scrollbar, GetScrollbarArrowSize(scrollbar));
2187}
2188
2189wxHitTest wxGTKRenderer::HitTestScrollbar(const wxScrollBar *scrollbar,
2190 const wxPoint& pt) const
2191{
2192 return StandardHitTestScrollbar(scrollbar, pt,
2193 GetScrollbarArrowSize(scrollbar));
2194}
2195
2196wxCoord wxGTKRenderer::ScrollbarToPixel(const wxScrollBar *scrollbar,
2197 int thumbPos)
2198{
2199 return StandardScrollbarToPixel(scrollbar, thumbPos,
2200 GetScrollbarArrowSize(scrollbar));
2201}
2202
2203int wxGTKRenderer::PixelToScrollbar(const wxScrollBar *scrollbar,
2204 wxCoord coord)
2205{
2206 return StandardPixelToScrollbar(scrollbar, coord,
2207 GetScrollbarArrowSize(scrollbar));
2208}
2209
2210// ----------------------------------------------------------------------------
2211// size adjustments
2212// ----------------------------------------------------------------------------
2213
2214void wxGTKRenderer::AdjustSize(wxSize *size, const wxWindow *window)
2215{
2216 if ( wxDynamicCast(window, wxButton) )
2217 {
2218 // TODO: this is ad hoc...
2219 size->x += 3*window->GetCharWidth();
2220 if ( size->x < 80 )
2221 size->x = 80;
2222 wxCoord minBtnHeight = 22;
2223 if ( size->y < minBtnHeight )
2224 size->y = minBtnHeight;
2225
2226 // button border width
2227 size->y += 4;
2228 }
2229 else if ( wxDynamicCast(window, wxScrollBar) )
2230 {
2231 // we only set the width of vert scrollbars and height of the
2232 // horizontal ones
2233 if ( window->GetWindowStyle() & wxSB_HORIZONTAL )
2234 size->y = m_sizeScrollbarArrow.x;
2235 else
2236 size->x = m_sizeScrollbarArrow.x;
2237 }
2238 else
2239 {
2240 // take into account the border width
2241 wxRect rectBorder = GetBorderDimensions(window->GetBorder());
2242 size->x += rectBorder.x + rectBorder.width;
2243 size->y += rectBorder.y + rectBorder.height;
2244 }
2245}
2246
2247// ============================================================================
2248// wxInputHandler
2249// ============================================================================
2250
2251// ----------------------------------------------------------------------------
2252// wxGTKInputHandler
2253// ----------------------------------------------------------------------------
2254
2255wxGTKInputHandler::wxGTKInputHandler(wxGTKRenderer *renderer)
2256{
2257 m_renderer = renderer;
2258}
2259
2260bool wxGTKInputHandler::HandleKey(wxControl *control,
2261 const wxKeyEvent& event,
2262 bool pressed)
2263{
2264 return FALSE;
2265}
2266
2267bool wxGTKInputHandler::HandleMouse(wxControl *control,
2268 const wxMouseEvent& event)
2269{
2270 // clicking on the control gives it focus
2271 if ( event.ButtonDown() )
2272 {
2273 control->SetFocus();
2274
2275 return TRUE;
2276 }
2277
2278 return FALSE;
2279}
2280
2281bool wxGTKInputHandler::HandleMouseMove(wxControl *control,
2282 const wxMouseEvent& event)
2283{
2284 if ( event.Entering() )
2285 {
2286 control->SetCurrent(TRUE);
2287 }
2288 else if ( event.Leaving() )
2289 {
2290 control->SetCurrent(FALSE);
2291 }
2292 else
2293 {
2294 return FALSE;
2295 }
2296
2297 return TRUE;
2298}
2299
2300// ----------------------------------------------------------------------------
2301// wxGTKCheckboxInputHandler
2302// ----------------------------------------------------------------------------
2303
2304bool wxGTKCheckboxInputHandler::HandleKey(wxControl *control,
2305 const wxKeyEvent& event,
2306 bool pressed)
2307{
2308 if ( pressed )
2309 {
2310 int keycode = event.GetKeyCode();
2311 if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
2312 {
2313 control->PerformAction(wxACTION_CHECKBOX_TOGGLE);
2314
2315 return TRUE;
2316 }
2317 }
2318
2319 return FALSE;
2320}
2321
2322// ----------------------------------------------------------------------------
2323// wxGTKTextCtrlInputHandler
2324// ----------------------------------------------------------------------------
2325
2326bool wxGTKTextCtrlInputHandler::HandleKey(wxControl *control,
2327 const wxKeyEvent& event,
2328 bool pressed)
2329{
2330 // handle only GTK-specific text bindings here, the others are handled in
2331 // the base class
2332 if ( pressed )
2333 {
2334 wxControlAction action;
2335 int keycode = event.GetKeyCode();
2336 if ( event.ControlDown() )
2337 {
2338 switch ( keycode )
2339 {
2340 case 'A':
2341 action = wxACTION_TEXT_HOME;
2342 break;
2343
2344 case 'B':
2345 action = wxACTION_TEXT_LEFT;
2346 break;
2347
2348 case 'D':
2349 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_RIGHT;
2350 break;
2351
2352 case 'E':
2353 action = wxACTION_TEXT_END;
2354 break;
2355
2356 case 'F':
2357 action = wxACTION_TEXT_RIGHT;
2358 break;
2359
2360 case 'H':
2361 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_LEFT;
2362 break;
2363
2364 case 'K':
2365 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_END;
2366 break;
2367
2368 case 'N':
2369 action = wxACTION_TEXT_DOWN;
2370 break;
2371
2372 case 'P':
2373 action = wxACTION_TEXT_UP;
2374 break;
2375
2376 case 'U':
2377 //delete the entire line
2378 control->PerformAction(wxACTION_TEXT_HOME);
2379 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_END;
2380 break;
2381
2382 case 'W':
2383 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_WORD_LEFT;
2384 break;
2385 }
2386 }
2387 else if ( event.AltDown() )
2388 {
2389 switch ( keycode )
2390 {
2391 case 'B':
2392 action = wxACTION_TEXT_WORD_LEFT;
2393 break;
2394
2395 case 'D':
2396 action << wxACTION_TEXT_PREFIX_DEL << wxACTION_TEXT_WORD_RIGHT;
2397 break;
2398
2399 case 'F':
2400 action = wxACTION_TEXT_WORD_RIGHT;
2401 break;
2402 }
2403 }
2404
2405 if ( action != wxACTION_NONE )
2406 {
2407 control->PerformAction(action);
2408
2409 return TRUE;
2410 }
2411 }
2412
2413 return wxStdTextCtrlInputHandler::HandleKey(control, event, pressed);
2414}