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