]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/renderer.cpp
supporting native content scaling on OSX
[wxWidgets.git] / src / gtk / renderer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/renderer.cpp
3 // Purpose: implementation of wxRendererNative for wxGTK
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 20.07.2003
7 // RCS-ID: $Id$
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
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 #include "wx/renderer.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/window.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #include "wx/module.h"
34 #endif
35
36 #include "wx/dcgraph.h"
37 #ifndef __WXGTK3__
38 #include "wx/gtk/dc.h"
39 #endif
40
41 #include <gtk/gtk.h>
42 #include "wx/gtk/private.h"
43 #include "wx/gtk/private/gtk2-compat.h"
44
45 // ----------------------------------------------------------------------------
46 // wxRendererGTK: our wxRendererNative implementation
47 // ----------------------------------------------------------------------------
48
49 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
50 {
51 public:
52 // draw the header control button (used by wxListCtrl)
53 virtual int DrawHeaderButton(wxWindow *win,
54 wxDC& dc,
55 const wxRect& rect,
56 int flags = 0,
57 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
58 wxHeaderButtonParams* params = NULL);
59
60 virtual int GetHeaderButtonHeight(wxWindow *win);
61
62 virtual int GetHeaderButtonMargin(wxWindow *win);
63
64
65 // draw the expanded/collapsed icon for a tree control item
66 virtual void DrawTreeItemButton(wxWindow *win,
67 wxDC& dc,
68 const wxRect& rect,
69 int flags = 0);
70
71 virtual void DrawSplitterBorder(wxWindow *win,
72 wxDC& dc,
73 const wxRect& rect,
74 int flags = 0);
75 virtual void DrawSplitterSash(wxWindow *win,
76 wxDC& dc,
77 const wxSize& size,
78 wxCoord position,
79 wxOrientation orient,
80 int flags = 0);
81
82 virtual void DrawComboBoxDropButton(wxWindow *win,
83 wxDC& dc,
84 const wxRect& rect,
85 int flags = 0);
86
87 virtual void DrawDropArrow(wxWindow *win,
88 wxDC& dc,
89 const wxRect& rect,
90 int flags = 0);
91
92 virtual void DrawCheckBox(wxWindow *win,
93 wxDC& dc,
94 const wxRect& rect,
95 int flags = 0);
96
97 virtual void DrawPushButton(wxWindow *win,
98 wxDC& dc,
99 const wxRect& rect,
100 int flags = 0);
101
102 virtual void DrawItemSelectionRect(wxWindow *win,
103 wxDC& dc,
104 const wxRect& rect,
105 int flags = 0);
106
107 virtual void DrawChoice(wxWindow* win,
108 wxDC& dc,
109 const wxRect& rect,
110 int flags=0);
111
112 virtual void DrawComboBox(wxWindow* win,
113 wxDC& dc,
114 const wxRect& rect,
115 int flags=0);
116
117 virtual void DrawTextCtrl(wxWindow* win,
118 wxDC& dc,
119 const wxRect& rect,
120 int flags=0);
121
122 virtual void DrawRadioBitmap(wxWindow* win,
123 wxDC& dc,
124 const wxRect& rect,
125 int flags=0);
126
127 virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
128
129 virtual wxSize GetCheckBoxSize(wxWindow *win);
130
131 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
132 };
133
134 // ============================================================================
135 // implementation
136 // ============================================================================
137
138 /* static */
139 wxRendererNative& wxRendererNative::GetDefault()
140 {
141 static wxRendererGTK s_rendererGTK;
142
143 return s_rendererGTK;
144 }
145
146 #ifdef __WXGTK3__
147 #define NULL_RECT
148 typedef cairo_t wxGTKDrawable;
149
150 static cairo_t* wxGetGTKDrawable(wxWindow*, const wxDC& dc)
151 {
152 wxGraphicsContext* gc = dc.GetGraphicsContext();
153 wxCHECK_MSG(gc, NULL, "cannot use wxRendererNative on wxDC of this type");
154 return static_cast<cairo_t*>(gc->GetNativeContext());
155 }
156
157 static const GtkStateFlags stateTypeToFlags[] = {
158 GTK_STATE_FLAG_NORMAL, GTK_STATE_FLAG_ACTIVE, GTK_STATE_FLAG_PRELIGHT,
159 GTK_STATE_FLAG_SELECTED, GTK_STATE_FLAG_INSENSITIVE, GTK_STATE_FLAG_INCONSISTENT,
160 GTK_STATE_FLAG_FOCUSED
161 };
162
163 #else
164 #define NULL_RECT NULL,
165 typedef GdkWindow wxGTKDrawable;
166
167 static GdkWindow* wxGetGTKDrawable(wxWindow* win, wxDC& dc)
168 {
169 GdkWindow* gdk_window = NULL;
170
171 #if wxUSE_GRAPHICS_CONTEXT
172 if ( wxDynamicCast(&dc, wxGCDC) )
173 gdk_window = win->GTKGetDrawingWindow();
174 else
175 #endif
176 {
177 wxDCImpl *impl = dc.GetImpl();
178 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
179 if (gtk_impl)
180 gdk_window = gtk_impl->GetGDKWindow();
181 else
182 wxFAIL_MSG("cannot use wxRendererNative on wxDC of this type");
183 }
184
185 #if !wxUSE_GRAPHICS_CONTEXT
186 wxUnusedVar(win);
187 #endif
188
189 return gdk_window;
190 }
191 #endif
192
193 // ----------------------------------------------------------------------------
194 // list/tree controls drawing
195 // ----------------------------------------------------------------------------
196
197 int
198 wxRendererGTK::DrawHeaderButton(wxWindow *win,
199 wxDC& dc,
200 const wxRect& rect,
201 int flags,
202 wxHeaderSortIconType sortArrow,
203 wxHeaderButtonParams* params)
204 {
205 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
206 if (flags & wxCONTROL_SPECIAL)
207 button = wxGTKPrivate::GetHeaderButtonWidgetFirst();
208 if (flags & wxCONTROL_DIRTY)
209 button = wxGTKPrivate::GetHeaderButtonWidgetLast();
210
211 int x_diff = 0;
212 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
213 x_diff = rect.width;
214
215 GtkStateType state = GTK_STATE_NORMAL;
216 if (flags & wxCONTROL_DISABLED)
217 state = GTK_STATE_INSENSITIVE;
218 else
219 {
220 if (flags & wxCONTROL_CURRENT)
221 state = GTK_STATE_PRELIGHT;
222 }
223
224 #ifdef __WXGTK3__
225 cairo_t* cr = wxGetGTKDrawable(win, dc);
226 if (cr)
227 {
228 GtkStyleContext* sc = gtk_widget_get_style_context(button);
229 gtk_style_context_save(sc);
230 gtk_style_context_set_state(sc, stateTypeToFlags[state]);
231 gtk_render_background(sc, cr, rect.x - x_diff+4, rect.y+4, rect.width-8, rect.height-8);
232 gtk_render_frame(sc, cr, rect.x - x_diff+4, rect.y+4, rect.width-8, rect.height-8);
233 gtk_style_context_restore(sc);
234 }
235 #else
236 GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
237 gtk_paint_box
238 (
239 gtk_widget_get_style(button),
240 gdk_window,
241 state,
242 GTK_SHADOW_OUT,
243 NULL,
244 button,
245 "button",
246 dc.LogicalToDeviceX(rect.x) - x_diff, rect.y, rect.width, rect.height
247 );
248 #endif
249
250 return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
251 }
252
253 int wxRendererGTK::GetHeaderButtonHeight(wxWindow *WXUNUSED(win))
254 {
255 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
256
257 GtkRequisition req;
258 #ifdef __WXGTK3__
259 gtk_widget_get_preferred_height(button, NULL, &req.height);
260 #else
261 GTK_WIDGET_GET_CLASS(button)->size_request(button, &req);
262 #endif
263
264 return req.height;
265 }
266
267 int wxRendererGTK::GetHeaderButtonMargin(wxWindow *WXUNUSED(win))
268 {
269 wxFAIL_MSG( "GetHeaderButtonMargin() not implemented" );
270 return -1;
271 }
272
273
274 // draw a ">" or "v" button
275 void
276 wxRendererGTK::DrawTreeItemButton(wxWindow* win,
277 wxDC& dc, const wxRect& rect, int flags)
278 {
279 GtkWidget *tree = wxGTKPrivate::GetTreeWidget();
280
281 GtkStateType state;
282 if ( flags & wxCONTROL_CURRENT )
283 state = GTK_STATE_PRELIGHT;
284 else
285 state = GTK_STATE_NORMAL;
286
287 int x_diff = 0;
288 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
289 x_diff = rect.width;
290
291 #ifdef __WXGTK3__
292 cairo_t* cr = wxGetGTKDrawable(win, dc);
293 if (cr)
294 {
295 gtk_widget_set_state_flags(tree, stateTypeToFlags[state], true);
296 GtkStyleContext* sc = gtk_widget_get_style_context(tree);
297 gtk_render_expander(sc, cr, rect.x - x_diff, rect.y, rect.width, rect.height);
298 }
299 #else
300 // x and y parameters specify the center of the expander
301 GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
302 if (gdk_window == NULL)
303 return;
304 gtk_paint_expander
305 (
306 gtk_widget_get_style(tree),
307 gdk_window,
308 state,
309 NULL,
310 tree,
311 "treeview",
312 dc.LogicalToDeviceX(rect.x) + rect.width / 2 - x_diff,
313 dc.LogicalToDeviceY(rect.y) + rect.height / 2,
314 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
315 : GTK_EXPANDER_COLLAPSED
316 );
317 #endif
318 }
319
320
321 // ----------------------------------------------------------------------------
322 // splitter sash drawing
323 // ----------------------------------------------------------------------------
324
325 static int GetGtkSplitterFullSize(GtkWidget* widget)
326 {
327 gint handle_size;
328 gtk_widget_style_get(widget, "handle_size", &handle_size, NULL);
329
330 return handle_size;
331 }
332
333 wxSplitterRenderParams
334 wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
335 {
336 // we don't draw any border, hence 0 for the second field
337 return wxSplitterRenderParams
338 (
339 GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget()),
340 0,
341 true // hot sensitive
342 );
343 }
344
345 void
346 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
347 wxDC& WXUNUSED(dc),
348 const wxRect& WXUNUSED(rect),
349 int WXUNUSED(flags))
350 {
351 // nothing to do
352 }
353
354 void
355 wxRendererGTK::DrawSplitterSash(wxWindow* win,
356 wxDC& dc,
357 const wxSize& size,
358 wxCoord position,
359 wxOrientation orient,
360 int flags)
361 {
362 if (gtk_widget_get_window(win->m_wxwindow) == NULL)
363 {
364 // window not realized yet
365 return;
366 }
367
368 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
369 if (drawable == NULL)
370 return;
371
372 // are we drawing vertical or horizontal splitter?
373 const bool isVert = orient == wxVERTICAL;
374
375 GtkWidget* widget = wxGTKPrivate::GetSplitterWidget(orient);
376 const int full_size = GetGtkSplitterFullSize(widget);
377
378 GdkRectangle rect;
379
380 if ( isVert )
381 {
382 rect.x = position;
383 rect.y = 0;
384 rect.width = full_size;
385 rect.height = size.y;
386 }
387 else // horz
388 {
389 rect.x = 0;
390 rect.y = position;
391 rect.height = full_size;
392 rect.width = size.x;
393 }
394
395 int x_diff = 0;
396 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
397 x_diff = rect.width;
398
399 #ifdef __WXGTK3__
400 cairo_t* cr = wxGetGTKDrawable(win, dc);
401 if (cr)
402 {
403 gtk_widget_set_state_flags(widget, stateTypeToFlags[flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL], true);
404 GtkStyleContext* sc = gtk_widget_get_style_context(widget);
405 gtk_render_handle(sc, cr, rect.x - x_diff, rect.y, rect.width, rect.height);
406 }
407 #else
408 GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
409 if (gdk_window == NULL)
410 return;
411 gtk_paint_handle
412 (
413 gtk_widget_get_style(win->m_wxwindow),
414 gdk_window,
415 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
416 GTK_SHADOW_NONE,
417 NULL /* no clipping */,
418 win->m_wxwindow,
419 "paned",
420 dc.LogicalToDeviceX(rect.x) - x_diff,
421 dc.LogicalToDeviceY(rect.y),
422 rect.width,
423 rect.height,
424 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
425 );
426 #endif
427 }
428
429 void
430 wxRendererGTK::DrawDropArrow(wxWindow* win,
431 wxDC& dc,
432 const wxRect& rect,
433 int flags)
434 {
435 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
436
437 // If we give WX_PIZZA(win->m_wxwindow)->bin_window as
438 // a window for gtk_paint_xxx function, then it won't
439 // work for wxMemoryDC. So that is why we assume wxDC
440 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
441 // are derived from it) and use its m_window.
442
443 // draw arrow so that there is even space horizontally
444 // on both sides
445 const int size = rect.width / 2;
446 const int x = rect.x + (size + 1) / 2;
447 const int y = rect.y + (rect.height - size + 1) / 2;
448
449 GtkStateType state;
450
451 if ( flags & wxCONTROL_PRESSED )
452 state = GTK_STATE_ACTIVE;
453 else if ( flags & wxCONTROL_DISABLED )
454 state = GTK_STATE_INSENSITIVE;
455 else if ( flags & wxCONTROL_CURRENT )
456 state = GTK_STATE_PRELIGHT;
457 else
458 state = GTK_STATE_NORMAL;
459
460 #ifdef __WXGTK3__
461 cairo_t* cr = wxGetGTKDrawable(win, dc);
462 if (cr)
463 {
464 gtk_widget_set_state_flags(button, stateTypeToFlags[state], true);
465 GtkStyleContext* sc = gtk_widget_get_style_context(button);
466 gtk_render_arrow(sc, cr, G_PI, x, y, size);
467 }
468 #else
469 GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
470 if (gdk_window == NULL)
471 return;
472 // draw arrow on button
473 gtk_paint_arrow
474 (
475 gtk_widget_get_style(button),
476 gdk_window,
477 state,
478 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
479 NULL,
480 button,
481 "arrow",
482 GTK_ARROW_DOWN,
483 FALSE,
484 x, y,
485 size, size
486 );
487 #endif
488 }
489
490 void
491 wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
492 wxDC& dc,
493 const wxRect& rect,
494 int flags)
495 {
496 DrawPushButton(win,dc,rect,flags);
497 DrawDropArrow(win,dc,rect);
498 }
499
500 wxSize
501 wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
502 {
503 gint indicator_size, indicator_spacing;
504 gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(),
505 "indicator_size", &indicator_size,
506 "indicator_spacing", &indicator_spacing,
507 NULL);
508
509 int size = indicator_size + indicator_spacing * 2;
510 return wxSize(size, size);
511 }
512
513 void
514 wxRendererGTK::DrawCheckBox(wxWindow* win,
515 wxDC& dc,
516 const wxRect& rect,
517 int flags )
518 {
519 GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget();
520
521 gint indicator_size, indicator_spacing;
522 gtk_widget_style_get(button,
523 "indicator_size", &indicator_size,
524 "indicator_spacing", &indicator_spacing,
525 NULL);
526
527 #ifndef __WXGTK3__
528 GtkStateType state;
529
530 if ( flags & wxCONTROL_PRESSED )
531 state = GTK_STATE_ACTIVE;
532 else if ( flags & wxCONTROL_DISABLED )
533 state = GTK_STATE_INSENSITIVE;
534 else if ( flags & wxCONTROL_CURRENT )
535 state = GTK_STATE_PRELIGHT;
536 else
537 state = GTK_STATE_NORMAL;
538
539 GtkShadowType shadow_type;
540
541 if ( flags & wxCONTROL_UNDETERMINED )
542 shadow_type = GTK_SHADOW_ETCHED_IN;
543 else if ( flags & wxCONTROL_CHECKED )
544 shadow_type = GTK_SHADOW_IN;
545 else
546 shadow_type = GTK_SHADOW_OUT;
547 #endif
548
549 #ifdef __WXGTK3__
550 cairo_t* cr = wxGetGTKDrawable(win, dc);
551 if (cr)
552 {
553 int stateFlags = GTK_STATE_FLAG_NORMAL;
554 if (flags & wxCONTROL_CHECKED)
555 stateFlags = GTK_STATE_FLAG_ACTIVE;
556 if (flags & wxCONTROL_DISABLED)
557 stateFlags |= GTK_STATE_FLAG_INSENSITIVE;
558 if (flags & wxCONTROL_UNDETERMINED)
559 stateFlags |= GTK_STATE_FLAG_INCONSISTENT;
560 if (flags & wxCONTROL_CURRENT)
561 stateFlags |= GTK_STATE_FLAG_PRELIGHT;
562 GtkStyleContext* sc = gtk_widget_get_style_context(button);
563 gtk_style_context_save(sc);
564 gtk_style_context_set_state(sc, GtkStateFlags(stateFlags));
565 gtk_style_context_add_class(sc, GTK_STYLE_CLASS_CHECK);
566 gtk_render_check(sc, cr,
567 rect.x + (rect.width - indicator_size) / 2,
568 rect.y + (rect.height - indicator_size) / 2,
569 indicator_size, indicator_size);
570 gtk_style_context_restore(sc);
571 }
572 #else
573 GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
574 if (gdk_window == NULL)
575 return;
576
577 gtk_paint_check
578 (
579 gtk_widget_get_style(button),
580 gdk_window,
581 state,
582 shadow_type,
583 NULL,
584 button,
585 "cellcheck",
586 dc.LogicalToDeviceX(rect.x) + indicator_spacing,
587 dc.LogicalToDeviceY(rect.y) + indicator_spacing,
588 indicator_size, indicator_size
589 );
590 #endif
591 }
592
593 void
594 wxRendererGTK::DrawPushButton(wxWindow* win,
595 wxDC& dc,
596 const wxRect& rect,
597 int flags)
598 {
599 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
600
601 // draw button
602 GtkStateType state;
603
604 if ( flags & wxCONTROL_PRESSED )
605 state = GTK_STATE_ACTIVE;
606 else if ( flags & wxCONTROL_DISABLED )
607 state = GTK_STATE_INSENSITIVE;
608 else if ( flags & wxCONTROL_CURRENT )
609 state = GTK_STATE_PRELIGHT;
610 else
611 state = GTK_STATE_NORMAL;
612
613 #ifdef __WXGTK3__
614 cairo_t* cr = wxGetGTKDrawable(win, dc);
615 if (cr)
616 {
617 GtkStyleContext* sc = gtk_widget_get_style_context(button);
618 gtk_style_context_save(sc);
619 gtk_style_context_set_state(sc, stateTypeToFlags[state]);
620 gtk_render_background(sc, cr, rect.x, rect.y, rect.width, rect.height);
621 gtk_render_frame(sc, cr, rect.x, rect.y, rect.width, rect.height);
622 gtk_style_context_restore(sc);
623 }
624 #else
625 GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
626 if (gdk_window == NULL)
627 return;
628
629 gtk_paint_box
630 (
631 gtk_widget_get_style(button),
632 gdk_window,
633 state,
634 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
635 NULL,
636 button,
637 "button",
638 dc.LogicalToDeviceX(rect.x),
639 dc.LogicalToDeviceY(rect.y),
640 rect.width,
641 rect.height
642 );
643 #endif
644 }
645
646 void
647 wxRendererGTK::DrawItemSelectionRect(wxWindow* win,
648 wxDC& dc,
649 const wxRect& rect,
650 int flags )
651 {
652 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
653 if (drawable == NULL)
654 return;
655
656 if (flags & wxCONTROL_SELECTED)
657 {
658 int x_diff = 0;
659 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
660 x_diff = rect.width;
661
662 GtkWidget* treeWidget = wxGTKPrivate::GetTreeWidget();
663
664 #ifdef __WXGTK3__
665 GtkStyleContext* sc = gtk_widget_get_style_context(treeWidget);
666 gtk_style_context_save(sc);
667 gtk_style_context_set_state(sc, GTK_STATE_FLAG_SELECTED);
668 gtk_style_context_add_class(sc, GTK_STYLE_CLASS_CELL);
669 gtk_render_background(sc, drawable, rect.x - x_diff, rect.y, rect.width, rect.height);
670 gtk_style_context_restore(sc);
671 #else
672 // the wxCONTROL_FOCUSED state is deduced
673 // directly from the m_wxwindow by GTK+
674 gtk_paint_flat_box(gtk_widget_get_style(treeWidget),
675 drawable,
676 GTK_STATE_SELECTED,
677 GTK_SHADOW_NONE,
678 NULL_RECT
679 win->m_wxwindow,
680 "cell_even",
681 dc.LogicalToDeviceX(rect.x) - x_diff,
682 dc.LogicalToDeviceY(rect.y),
683 rect.width,
684 rect.height );
685 #endif
686 }
687
688 if ((flags & wxCONTROL_CURRENT) && (flags & wxCONTROL_FOCUSED))
689 DrawFocusRect(win, dc, rect, flags);
690 }
691
692 void wxRendererGTK::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
693 {
694 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
695 if (drawable == NULL)
696 return;
697
698 GtkStateType state;
699 if (flags & wxCONTROL_SELECTED)
700 state = GTK_STATE_SELECTED;
701 else
702 state = GTK_STATE_NORMAL;
703
704 #ifdef __WXGTK3__
705 GtkStyleContext* sc = gtk_widget_get_style_context(win->m_widget);
706 gtk_style_context_save(sc);
707 gtk_style_context_set_state(sc, stateTypeToFlags[state]);
708 gtk_render_focus(sc, drawable, rect.x, rect.y, rect.width, rect.height);
709 gtk_style_context_restore(sc);
710 #else
711 gtk_paint_focus( gtk_widget_get_style(win->m_widget),
712 drawable,
713 state,
714 NULL_RECT
715 win->m_wxwindow,
716 NULL,
717 dc.LogicalToDeviceX(rect.x),
718 dc.LogicalToDeviceY(rect.y),
719 rect.width,
720 rect.height );
721 #endif
722 }
723
724 // Uses the theme to draw the border and fill for something like a wxTextCtrl
725 void wxRendererGTK::DrawTextCtrl(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
726 {
727 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
728 if (drawable == NULL)
729 return;
730
731 GtkWidget* entry = wxGTKPrivate::GetTextEntryWidget();
732
733 GtkStateType state = GTK_STATE_NORMAL;
734 if ( flags & wxCONTROL_DISABLED )
735 state = GTK_STATE_INSENSITIVE;
736
737 gtk_widget_set_can_focus(entry, (flags & wxCONTROL_CURRENT) != 0);
738
739 #ifdef __WXGTK3__
740 GtkStyleContext* sc = gtk_widget_get_style_context(entry);
741 gtk_style_context_save(sc);
742 gtk_style_context_set_state(sc, stateTypeToFlags[state]);
743 gtk_render_background(sc, drawable, rect.x, rect.y, rect.width, rect.height);
744 gtk_render_frame(sc, drawable, rect.x, rect.y, rect.width, rect.height);
745 gtk_style_context_restore(sc);
746 #else
747 gtk_paint_shadow
748 (
749 gtk_widget_get_style(entry),
750 drawable,
751 state,
752 GTK_SHADOW_OUT,
753 NULL_RECT
754 entry,
755 "entry",
756 dc.LogicalToDeviceX(rect.x),
757 dc.LogicalToDeviceY(rect.y),
758 rect.width,
759 rect.height
760 );
761 #endif
762 }
763
764 // Draw the equivalent of a wxComboBox
765 void wxRendererGTK::DrawComboBox(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
766 {
767 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
768 if (drawable == NULL)
769 return;
770
771 GtkWidget* combo = wxGTKPrivate::GetComboBoxWidget();
772
773 GtkStateType state = GTK_STATE_NORMAL;
774 if ( flags & wxCONTROL_DISABLED )
775 state = GTK_STATE_INSENSITIVE;
776
777 gtk_widget_set_can_focus(combo, (flags & wxCONTROL_CURRENT) != 0);
778
779 #ifdef __WXGTK3__
780 GtkStyleContext* sc = gtk_widget_get_style_context(combo);
781 gtk_style_context_save(sc);
782 gtk_style_context_set_state(sc, stateTypeToFlags[state]);
783 gtk_render_background(sc, drawable, rect.x, rect.y, rect.width, rect.height);
784 gtk_render_frame(sc, drawable, rect.x, rect.y, rect.width, rect.height);
785 gtk_style_context_restore(sc);
786 wxRect r = rect;
787 r.x += r.width - r.height;
788 r.width = r.height;
789 DrawComboBoxDropButton(win, dc, r, flags);
790 #else
791 gtk_paint_shadow
792 (
793 gtk_widget_get_style(combo),
794 drawable,
795 state,
796 GTK_SHADOW_OUT,
797 NULL_RECT
798 combo,
799 "combobox",
800 dc.LogicalToDeviceX(rect.x),
801 dc.LogicalToDeviceY(rect.y),
802 rect.width,
803 rect.height
804 );
805
806 wxRect r = rect;
807 int extent = rect.height / 2;
808 r.x += rect.width - extent - extent/2;
809 r.y += extent/2;
810 r.width = extent;
811 r.height = extent;
812
813 gtk_paint_arrow
814 (
815 gtk_widget_get_style(combo),
816 drawable,
817 state,
818 GTK_SHADOW_OUT,
819 NULL_RECT
820 combo,
821 "arrow",
822 GTK_ARROW_DOWN,
823 TRUE,
824 dc.LogicalToDeviceX(r.x),
825 dc.LogicalToDeviceY(r.y),
826 r.width,
827 r.height
828 );
829
830 r = rect;
831 r.x += rect.width - 2*extent;
832 r.width = 2;
833
834 gtk_paint_box
835 (
836 gtk_widget_get_style(combo),
837 drawable,
838 state,
839 GTK_SHADOW_ETCHED_OUT,
840 NULL_RECT
841 combo,
842 "vseparator",
843 dc.LogicalToDeviceX(r.x),
844 dc.LogicalToDeviceY(r.y+1),
845 r.width,
846 r.height-2
847 );
848 #endif
849 }
850
851 void wxRendererGTK::DrawChoice(wxWindow* win, wxDC& dc,
852 const wxRect& rect, int flags)
853 {
854 DrawComboBox( win, dc, rect, flags );
855 }
856
857
858 // Draw a themed radio button
859 void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
860 {
861 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
862 if (drawable == NULL)
863 return;
864
865 GtkWidget* button = wxGTKPrivate::GetRadioButtonWidget();
866
867 #ifdef __WXGTK3__
868 int state = GTK_STATE_FLAG_NORMAL;
869 if (flags & wxCONTROL_CHECKED)
870 state = GTK_STATE_FLAG_ACTIVE;
871 else if (flags & wxCONTROL_UNDETERMINED)
872 state = GTK_STATE_FLAG_INCONSISTENT;
873 if (flags & wxCONTROL_DISABLED)
874 state |= GTK_STATE_FLAG_INSENSITIVE;
875
876 GtkStyleContext* sc = gtk_widget_get_style_context(button);
877 gtk_style_context_save(sc);
878 gtk_style_context_add_class(sc, GTK_STYLE_CLASS_RADIO);
879 gtk_style_context_set_state(sc, GtkStateFlags(state));
880 gtk_render_option(sc, drawable, rect.x, rect.y, rect.width, rect.height);
881 gtk_style_context_restore(sc);
882 #else
883 GtkShadowType shadow_type = GTK_SHADOW_OUT;
884 if ( flags & wxCONTROL_CHECKED )
885 shadow_type = GTK_SHADOW_IN;
886 else if ( flags & wxCONTROL_UNDETERMINED )
887 shadow_type = GTK_SHADOW_ETCHED_IN;
888
889 GtkStateType state = GTK_STATE_NORMAL;
890 if ( flags & wxCONTROL_DISABLED )
891 state = GTK_STATE_INSENSITIVE;
892 if ( flags & wxCONTROL_PRESSED )
893 state = GTK_STATE_ACTIVE;
894 /*
895 Don't know when to set this
896 state_type = GTK_STATE_PRELIGHT;
897 */
898
899 gtk_paint_option
900 (
901 gtk_widget_get_style(button),
902 drawable,
903 state,
904 shadow_type,
905 NULL_RECT
906 button,
907 "radiobutton",
908 dc.LogicalToDeviceX(rect.x),
909 dc.LogicalToDeviceY(rect.y),
910 rect.width, rect.height
911 );
912 #endif
913 }