]> git.saurik.com Git - wxWidgets.git/blob - src/univ/themes/gtk.cpp
renamed scrolwin file - no other way to make wxGTK/Univ compile
[wxWidgets.git] / src / univ / themes / gtk.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: univ/themes/gtk.cpp
3 // Purpose: wxUniversal theme implementing GTK-like LNF
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 06.08.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/intl.h"
29 #include "wx/log.h"
30 #include "wx/dcmemory.h"
31 #include "wx/window.h"
32
33 #include "wx/button.h"
34 #include "wx/checkbox.h"
35 #include "wx/listbox.h"
36 #include "wx/checklst.h"
37 #include "wx/combobox.h"
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
55 static const size_t BORDER_THICKNESS = 1;
56
57 // ----------------------------------------------------------------------------
58 // wxGTKRenderer: draw the GUI elements in GTK style
59 // ----------------------------------------------------------------------------
60
61 class wxGTKRenderer : public wxRenderer
62 {
63 public:
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
260 protected:
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
371 private:
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
398 class wxGTKInputHandler : public wxInputHandler
399 {
400 public:
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
410 protected:
411 wxGTKRenderer *m_renderer;
412 };
413
414 class wxGTKScrollBarInputHandler : public wxStdScrollBarInputHandler
415 {
416 public:
417 wxGTKScrollBarInputHandler(wxRenderer *renderer, wxInputHandler *handler)
418 : wxStdScrollBarInputHandler(renderer, handler) { }
419
420 protected:
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
448 class wxGTKCheckboxInputHandler : public wxStdCheckboxInputHandler
449 {
450 public:
451 wxGTKCheckboxInputHandler(wxInputHandler *handler)
452 : wxStdCheckboxInputHandler(handler) { }
453
454 virtual bool HandleKey(wxControl *control,
455 const wxKeyEvent& event,
456 bool pressed);
457 };
458
459 class wxGTKTextCtrlInputHandler : public wxStdTextCtrlInputHandler
460 {
461 public:
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
474 class wxGTKColourScheme : public wxColourScheme
475 {
476 public:
477 virtual wxColour Get(StdColour col) const;
478 virtual wxColour GetBackground(wxWindow *win) const;
479 };
480
481 // ----------------------------------------------------------------------------
482 // wxGTKTheme
483 // ----------------------------------------------------------------------------
484
485 WX_DEFINE_ARRAY(wxInputHandler *, wxArrayHandlers);
486
487 class wxGTKTheme : public wxTheme
488 {
489 public:
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
497 private:
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
519 WX_IMPLEMENT_THEME(wxGTKTheme, gtk, wxTRANSLATE("GTK+ theme"));
520
521 // ----------------------------------------------------------------------------
522 // wxGTKTheme
523 // ----------------------------------------------------------------------------
524
525 wxGTKTheme::wxGTKTheme()
526 {
527 m_scheme = new wxGTKColourScheme;
528 m_renderer = new wxGTKRenderer(m_scheme);
529 m_handlerDefault = NULL;
530 }
531
532 wxGTKTheme::~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
546 wxInputHandler *wxGTKTheme::GetDefaultInputHandler()
547 {
548 if ( !m_handlerDefault )
549 {
550 m_handlerDefault = new wxGTKInputHandler(m_renderer);
551 }
552
553 return m_handlerDefault;
554 }
555
556 wxInputHandler *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
620 wxColour 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
659 wxColour 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
701 wxGTKRenderer::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
719 void 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
730 void 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
744 void 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
763 void 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
798 void 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
817 void 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
823 void 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
829 void 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
883 wxRect 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
921 bool 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
931 void 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
954 void 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
1000 void 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
1010 void 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
1020 void 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
1069 void 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
1081 void 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
1104 void 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
1149 void 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
1172 void 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
1192 void 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
1203 void 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
1264 void 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
1275 void 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
1286 wxBitmap 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
1325 wxBitmap 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
1351 void 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
1373 void 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
1421 void 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
1457 wxRect wxGTKRenderer::GetTextTotalArea(const wxTextCtrl *text,
1458 const wxRect& rect)
1459 {
1460 wxRect rectTotal = rect;
1461 rectTotal.Inflate(2);
1462 return rectTotal;
1463 }
1464
1465 wxRect 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
1486 void 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
1498 void 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
1527 void 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
1667 wxSize 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
1689 wxRect wxGTKRenderer::GetSliderShaftRect(const wxRect& rect,
1690 wxOrientation WXUNUSED(orient)) const
1691 {
1692 return rect.Deflate(2*BORDER_THICKNESS, 2*BORDER_THICKNESS);
1693 }
1694
1695 void 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
1722 void 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
1750 void 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
1759 void 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
1771 void wxGTKRenderer::DrawMenuSeparator(wxDC& dc,
1772 wxCoord y,
1773 const wxMenuGeometryInfo& geomInfo)
1774 {
1775 wxFAIL_MSG(_T("TODO"));
1776 }
1777
1778 wxSize wxGTKRenderer::GetMenuBarItemSize(const wxSize& sizeText) const
1779 {
1780 return sizeText;
1781 }
1782
1783 wxMenuGeometryInfo *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
1795 void wxGTKRenderer::GetComboBitmaps(wxBitmap *bmpNormal,
1796 wxBitmap *bmpPressed,
1797 wxBitmap *bmpDisabled)
1798 {
1799 // TODO
1800 }
1801
1802 // ----------------------------------------------------------------------------
1803 // background
1804 // ----------------------------------------------------------------------------
1805
1806 void 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
1816 void 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
1829 void 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
1910 void 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 :-(
1926 void 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
2099 void 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
2133 void 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
2150 void 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
2160 void wxGTKRenderer::DrawScrollCorner(wxDC& dc, const wxRect& rect)
2161 {
2162 DoDrawBackground(dc, wxSCHEME_COLOUR(m_scheme, CONTROL), rect);
2163 }
2164
2165 wxRect 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
2182 wxCoord wxGTKRenderer::GetScrollbarSize(const wxScrollBar *scrollbar)
2183 {
2184 return StandardScrollBarSize(scrollbar, GetScrollbarArrowSize(scrollbar));
2185 }
2186
2187 wxHitTest wxGTKRenderer::HitTestScrollbar(const wxScrollBar *scrollbar,
2188 const wxPoint& pt) const
2189 {
2190 return StandardHitTestScrollbar(scrollbar, pt,
2191 GetScrollbarArrowSize(scrollbar));
2192 }
2193
2194 wxCoord wxGTKRenderer::ScrollbarToPixel(const wxScrollBar *scrollbar,
2195 int thumbPos)
2196 {
2197 return StandardScrollbarToPixel(scrollbar, thumbPos,
2198 GetScrollbarArrowSize(scrollbar));
2199 }
2200
2201 int 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
2212 void 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
2253 wxGTKInputHandler::wxGTKInputHandler(wxGTKRenderer *renderer)
2254 {
2255 m_renderer = renderer;
2256 }
2257
2258 bool wxGTKInputHandler::HandleKey(wxControl *control,
2259 const wxKeyEvent& event,
2260 bool pressed)
2261 {
2262 return FALSE;
2263 }
2264
2265 bool 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
2279 bool 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
2302 bool 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
2324 bool 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 }