]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/renderer.cpp
Fix crash in wxDC::GetMultiLineTextExtent() after last commit.
[wxWidgets.git] / src / gtk / renderer.cpp
CommitLineData
9c7f49f5 1///////////////////////////////////////////////////////////////////////////////
90b903c2 2// Name: src/gtk/renderer.cpp
38c4cb6a 3// Purpose: implementation of wxRendererNative for wxGTK
9c7f49f5
VZ
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>
526954c5 9// Licence: wxWindows licence
9c7f49f5
VZ
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
e1bf3ad3 27#include "wx/renderer.h"
cdccdfab
WS
28
29#ifndef WX_PRECOMP
30 #include "wx/window.h"
ed4b0fdc 31 #include "wx/dcclient.h"
9eddec69 32 #include "wx/settings.h"
f1c09bed 33 #include "wx/module.h"
cdccdfab
WS
34#endif
35
02f07b19 36#include "wx/dcgraph.h"
9dc44eff 37#ifndef __WXGTK3__
888dde65 38#include "wx/gtk/dc.h"
9dc44eff 39#endif
888dde65 40
9c7f49f5 41#include <gtk/gtk.h>
9dc44eff
PC
42#include "wx/gtk/private.h"
43#include "wx/gtk/private/gtk2-compat.h"
9c7f49f5 44
9c7f49f5 45// ----------------------------------------------------------------------------
38c4cb6a 46// wxRendererGTK: our wxRendererNative implementation
9c7f49f5
VZ
47// ----------------------------------------------------------------------------
48
38c4cb6a 49class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
9c7f49f5
VZ
50{
51public:
52 // draw the header control button (used by wxListCtrl)
c97c9952 53 virtual int DrawHeaderButton(wxWindow *win,
9c7f49f5
VZ
54 wxDC& dc,
55 const wxRect& rect,
4b94ddc4 56 int flags = 0,
80752b57 57 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
4b94ddc4 58 wxHeaderButtonParams* params = NULL);
9c7f49f5 59
6f91f3a3
RR
60 virtual int GetHeaderButtonHeight(wxWindow *win);
61
9aebcb5e
VS
62 virtual int GetHeaderButtonMargin(wxWindow *win);
63
6f91f3a3 64
9c7f49f5
VZ
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);
9c7f49f5 70
d16cf3cd
VZ
71 virtual void DrawSplitterBorder(wxWindow *win,
72 wxDC& dc,
af99040c
VZ
73 const wxRect& rect,
74 int flags = 0);
95155e75
VZ
75 virtual void DrawSplitterSash(wxWindow *win,
76 wxDC& dc,
77 const wxSize& size,
d16cf3cd 78 wxCoord position,
af99040c
VZ
79 wxOrientation orient,
80 int flags = 0);
d16cf3cd 81
38511687
VZ
82 virtual void DrawComboBoxDropButton(wxWindow *win,
83 wxDC& dc,
84 const wxRect& rect,
85 int flags = 0);
86
4c85ab75
VZ
87 virtual void DrawDropArrow(wxWindow *win,
88 wxDC& dc,
89 const wxRect& rect,
90 int flags = 0);
91
90b903c2
WS
92 virtual void DrawCheckBox(wxWindow *win,
93 wxDC& dc,
94 const wxRect& rect,
95 int flags = 0);
2209baae
RR
96
97 virtual void DrawPushButton(wxWindow *win,
98 wxDC& dc,
99 const wxRect& rect,
100 int flags = 0);
101
daebb44c
RR
102 virtual void DrawItemSelectionRect(wxWindow *win,
103 wxDC& dc,
104 const wxRect& rect,
105 int flags = 0);
90b903c2 106
99c4be68
VZ
107 virtual void DrawChoice(wxWindow* win,
108 wxDC& dc,
109 const wxRect& rect,
e4131985
KO
110 int flags=0);
111
99c4be68
VZ
112 virtual void DrawComboBox(wxWindow* win,
113 wxDC& dc,
114 const wxRect& rect,
e4131985
KO
115 int flags=0);
116
99c4be68
VZ
117 virtual void DrawTextCtrl(wxWindow* win,
118 wxDC& dc,
119 const wxRect& rect,
e4131985
KO
120 int flags=0);
121
6e6b532c 122 virtual void DrawRadioBitmap(wxWindow* win,
99c4be68
VZ
123 wxDC& dc,
124 const wxRect& rect,
e4131985
KO
125 int flags=0);
126
6d789987
JS
127 virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
128
191e43fd 129 virtual wxSize GetCheckBoxSize(wxWindow *win);
f1c09bed 130
e8759560 131 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
9c7f49f5
VZ
132};
133
134// ============================================================================
135// implementation
136// ============================================================================
137
138/* static */
f0244295 139wxRendererNative& wxRendererNative::GetDefault()
9c7f49f5
VZ
140{
141 static wxRendererGTK s_rendererGTK;
142
143 return s_rendererGTK;
144}
145
9dc44eff
PC
146#ifdef __WXGTK3__
147#define NULL_RECT
148typedef cairo_t wxGTKDrawable;
149
150static 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
157static 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,
165typedef GdkWindow wxGTKDrawable;
166
167static GdkWindow* wxGetGTKDrawable(wxWindow* win, wxDC& dc)
e4131985
KO
168{
169 GdkWindow* gdk_window = NULL;
99c4be68 170
02f07b19 171#if wxUSE_GRAPHICS_CONTEXT
345c78ca 172 if ( wxDynamicCast(&dc, wxGCDC) )
d81b2f54 173 gdk_window = win->GTKGetDrawingWindow();
02f07b19
KO
174 else
175#endif
176 {
02f07b19
KO
177 wxDCImpl *impl = dc.GetImpl();
178 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
179 if (gtk_impl)
180 gdk_window = gtk_impl->GetGDKWindow();
9dc44eff
PC
181 else
182 wxFAIL_MSG("cannot use wxRendererNative on wxDC of this type");
02f07b19 183 }
b162ccca
FM
184
185#if !wxUSE_GRAPHICS_CONTEXT
186 wxUnusedVar(win);
187#endif
188
e4131985
KO
189 return gdk_window;
190}
9dc44eff 191#endif
e4131985 192
d16cf3cd
VZ
193// ----------------------------------------------------------------------------
194// list/tree controls drawing
195// ----------------------------------------------------------------------------
196
c97c9952 197int
9c7f49f5
VZ
198wxRendererGTK::DrawHeaderButton(wxWindow *win,
199 wxDC& dc,
200 const wxRect& rect,
4b94ddc4 201 int flags,
80752b57 202 wxHeaderSortIconType sortArrow,
4b94ddc4 203 wxHeaderButtonParams* params)
9c7f49f5 204{
e8759560 205 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
09e72468
RR
206 if (flags & wxCONTROL_SPECIAL)
207 button = wxGTKPrivate::GetHeaderButtonWidgetFirst();
6f91f3a3 208 if (flags & wxCONTROL_DIRTY)
b047e876 209 button = wxGTKPrivate::GetHeaderButtonWidgetLast();
f1c09bed 210
5eefe029
RR
211 int x_diff = 0;
212 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
213 x_diff = rect.width;
f4322df6 214
1cfc4971
RR
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
9dc44eff
PC
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);
9c7f49f5
VZ
237 gtk_paint_box
238 (
385e8575 239 gtk_widget_get_style(button),
2e992e06 240 gdk_window,
1cfc4971 241 state,
9c7f49f5 242 GTK_SHADOW_OUT,
38511687 243 NULL,
bc13e772 244 button,
9b311923 245 "button",
5eefe029 246 dc.LogicalToDeviceX(rect.x) - x_diff, rect.y, rect.width, rect.height
9c7f49f5 247 );
9dc44eff 248#endif
99c4be68 249
c97c9952 250 return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
9c7f49f5
VZ
251}
252
6f91f3a3
RR
253int wxRendererGTK::GetHeaderButtonHeight(wxWindow *WXUNUSED(win))
254{
255 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
99c4be68 256
6f91f3a3 257 GtkRequisition req;
9dc44eff
PC
258#ifdef __WXGTK3__
259 gtk_widget_get_preferred_height(button, NULL, &req.height);
260#else
6f91f3a3 261 GTK_WIDGET_GET_CLASS(button)->size_request(button, &req);
9dc44eff 262#endif
99c4be68 263
6f91f3a3
RR
264 return req.height;
265}
266
9aebcb5e
VS
267int wxRendererGTK::GetHeaderButtonMargin(wxWindow *WXUNUSED(win))
268{
269 wxFAIL_MSG( "GetHeaderButtonMargin() not implemented" );
270 return -1;
271}
272
6f91f3a3 273
9c7f49f5 274// draw a ">" or "v" button
9c7f49f5 275void
f8b043e7 276wxRendererGTK::DrawTreeItemButton(wxWindow* win,
9a0b7e33 277 wxDC& dc, const wxRect& rect, int flags)
9c7f49f5 278{
e8759560 279 GtkWidget *tree = wxGTKPrivate::GetTreeWidget();
f8b043e7 280
885dd597
RR
281 GtkStateType state;
282 if ( flags & wxCONTROL_CURRENT )
283 state = GTK_STATE_PRELIGHT;
284 else
285 state = GTK_STATE_NORMAL;
91af0895 286
428f4657
RR
287 int x_diff = 0;
288 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
289 x_diff = rect.width;
2e992e06 290
9dc44eff
PC
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
5ede3d24 300 // x and y parameters specify the center of the expander
9dc44eff
PC
301 GdkWindow* gdk_window = wxGetGTKDrawable(win, dc);
302 if (gdk_window == NULL)
303 return;
bc13e772
VZ
304 gtk_paint_expander
305 (
385e8575 306 gtk_widget_get_style(tree),
2e992e06 307 gdk_window,
885dd597 308 state,
bc13e772
VZ
309 NULL,
310 tree,
311 "treeview",
5ede3d24
PC
312 dc.LogicalToDeviceX(rect.x) + rect.width / 2 - x_diff,
313 dc.LogicalToDeviceY(rect.y) + rect.height / 2,
bc13e772
VZ
314 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
315 : GTK_EXPANDER_COLLAPSED
316 );
9dc44eff 317#endif
9c7f49f5
VZ
318}
319
9c7f49f5 320
d16cf3cd
VZ
321// ----------------------------------------------------------------------------
322// splitter sash drawing
323// ----------------------------------------------------------------------------
324
f1c09bed 325static int GetGtkSplitterFullSize(GtkWidget* widget)
38418827 326{
38418827 327 gint handle_size;
f1c09bed 328 gtk_widget_style_get(widget, "handle_size", &handle_size, NULL);
91af0895 329
38418827 330 return handle_size;
38418827
RR
331}
332
af99040c 333wxSplitterRenderParams
38418827 334wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
d16cf3cd 335{
af99040c
VZ
336 // we don't draw any border, hence 0 for the second field
337 return wxSplitterRenderParams
338 (
e8759560 339 GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget()),
af99040c 340 0,
af99040c 341 true // hot sensitive
af99040c 342 );
d16cf3cd
VZ
343}
344
345void
346wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
347 wxDC& WXUNUSED(dc),
af99040c
VZ
348 const wxRect& WXUNUSED(rect),
349 int WXUNUSED(flags))
d16cf3cd
VZ
350{
351 // nothing to do
352}
95155e75 353
95155e75 354void
02f07b19 355wxRendererGTK::DrawSplitterSash(wxWindow* win,
95155e75
VZ
356 wxDC& dc,
357 const wxSize& size,
d16cf3cd 358 wxCoord position,
af99040c 359 wxOrientation orient,
68567a96 360 int flags)
95155e75 361{
385e8575 362 if (gtk_widget_get_window(win->m_wxwindow) == NULL)
95155e75 363 {
0100b858 364 // window not realized yet
95155e75
VZ
365 return;
366 }
91af0895 367
9dc44eff
PC
368 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
369 if (drawable == NULL)
370 return;
95155e75 371
d16cf3cd
VZ
372 // are we drawing vertical or horizontal splitter?
373 const bool isVert = orient == wxVERTICAL;
374
9dc44eff
PC
375 GtkWidget* widget = wxGTKPrivate::GetSplitterWidget(orient);
376 const int full_size = GetGtkSplitterFullSize(widget);
377
d16cf3cd 378 GdkRectangle rect;
91af0895 379
d16cf3cd
VZ
380 if ( isVert )
381 {
382 rect.x = position;
0100b858 383 rect.y = 0;
38418827 384 rect.width = full_size;
e4161a2a 385 rect.height = size.y;
d16cf3cd
VZ
386 }
387 else // horz
388 {
0100b858 389 rect.x = 0;
d16cf3cd 390 rect.y = position;
38418827 391 rect.height = full_size;
e4161a2a 392 rect.width = size.x;
d16cf3cd 393 }
f4322df6 394
847dfdb4
RR
395 int x_diff = 0;
396 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
397 x_diff = rect.width;
35468934 398
9dc44eff
PC
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;
af99040c
VZ
411 gtk_paint_handle
412 (
385e8575 413 gtk_widget_get_style(win->m_wxwindow),
2e992e06 414 gdk_window,
af99040c
VZ
415 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
416 GTK_SHADOW_NONE,
417 NULL /* no clipping */,
418 win->m_wxwindow,
419 "paned",
847dfdb4
RR
420 dc.LogicalToDeviceX(rect.x) - x_diff,
421 dc.LogicalToDeviceY(rect.y),
af99040c
VZ
422 rect.width,
423 rect.height,
38418827 424 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
af99040c 425 );
9dc44eff 426#endif
95155e75
VZ
427}
428
4c85ab75 429void
02f07b19 430wxRendererGTK::DrawDropArrow(wxWindow* win,
4c85ab75
VZ
431 wxDC& dc,
432 const wxRect& rect,
433 int flags)
38511687 434{
e8759560 435 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
38511687 436
02f07b19 437 // If we give WX_PIZZA(win->m_wxwindow)->bin_window as
4c85ab75
VZ
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.
a4622f29 442
4c85ab75
VZ
443 // draw arrow so that there is even space horizontally
444 // on both sides
9dc44eff
PC
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;
4c85ab75 448
e1befae3 449 GtkStateType state;
a4622f29 450
3203621a
JS
451 if ( flags & wxCONTROL_PRESSED )
452 state = GTK_STATE_ACTIVE;
a4622f29
VZ
453 else if ( flags & wxCONTROL_DISABLED )
454 state = GTK_STATE_INSENSITIVE;
3203621a
JS
455 else if ( flags & wxCONTROL_CURRENT )
456 state = GTK_STATE_PRELIGHT;
e1befae3
VZ
457 else
458 state = GTK_STATE_NORMAL;
a4622f29 459
9dc44eff
PC
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;
a4622f29 472 // draw arrow on button
a4622f29
VZ
473 gtk_paint_arrow
474 (
385e8575 475 gtk_widget_get_style(button),
2e992e06 476 gdk_window,
a4622f29 477 state,
e1befae3 478 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
a4622f29 479 NULL,
bc13e772 480 button,
a4622f29
VZ
481 "arrow",
482 GTK_ARROW_DOWN,
a8ac548e 483 FALSE,
9dc44eff
PC
484 x, y,
485 size, size
a4622f29 486 );
9dc44eff 487#endif
38511687
VZ
488}
489
4c85ab75
VZ
490void
491wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
492 wxDC& dc,
493 const wxRect& rect,
494 int flags)
495{
2209baae
RR
496 DrawPushButton(win,dc,rect,flags);
497 DrawDropArrow(win,dc,rect);
498}
499
e8759560 500wxSize
191e43fd 501wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
e8759560
VZ
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
cdccdfab 513void
02f07b19 514wxRendererGTK::DrawCheckBox(wxWindow* win,
90b903c2
WS
515 wxDC& dc,
516 const wxRect& rect,
517 int flags )
2209baae 518{
e8759560 519 GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget();
f1c09bed 520
e8759560
VZ
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
9dc44eff 527#ifndef __WXGTK3__
4c85ab75
VZ
528 GtkStateType state;
529
3203621a
JS
530 if ( flags & wxCONTROL_PRESSED )
531 state = GTK_STATE_ACTIVE;
4c85ab75
VZ
532 else if ( flags & wxCONTROL_DISABLED )
533 state = GTK_STATE_INSENSITIVE;
3203621a
JS
534 else if ( flags & wxCONTROL_CURRENT )
535 state = GTK_STATE_PRELIGHT;
4c85ab75
VZ
536 else
537 state = GTK_STATE_NORMAL;
90b903c2 538
e78778c8
RR
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;
9dc44eff
PC
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;
e78778c8 576
2209baae 577 gtk_paint_check
4c85ab75 578 (
385e8575 579 gtk_widget_get_style(button),
2e992e06 580 gdk_window,
4c85ab75 581 state,
e78778c8 582 shadow_type,
4c85ab75
VZ
583 NULL,
584 button,
2209baae 585 "cellcheck",
e8759560
VZ
586 dc.LogicalToDeviceX(rect.x) + indicator_spacing,
587 dc.LogicalToDeviceY(rect.y) + indicator_spacing,
588 indicator_size, indicator_size
4c85ab75 589 );
9dc44eff 590#endif
4c85ab75
VZ
591}
592
2209baae 593void
02f07b19 594wxRendererGTK::DrawPushButton(wxWindow* win,
2209baae
RR
595 wxDC& dc,
596 const wxRect& rect,
597 int flags)
862d8041 598{
e8759560 599 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
862d8041 600
2209baae 601 // draw button
862d8041
RR
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;
2209baae 612
9dc44eff
PC
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
2209baae 629 gtk_paint_box
862d8041 630 (
385e8575 631 gtk_widget_get_style(button),
2e992e06 632 gdk_window,
862d8041 633 state,
2209baae 634 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
862d8041
RR
635 NULL,
636 button,
2209baae 637 "button",
99c4be68
VZ
638 dc.LogicalToDeviceX(rect.x),
639 dc.LogicalToDeviceY(rect.y),
640 rect.width,
e4131985 641 rect.height
862d8041 642 );
9dc44eff 643#endif
862d8041 644}
daebb44c 645
cdccdfab 646void
02f07b19 647wxRendererGTK::DrawItemSelectionRect(wxWindow* win,
cdccdfab
WS
648 wxDC& dc,
649 const wxRect& rect,
650 int flags )
daebb44c 651{
9dc44eff 652 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
2e992e06 653
9dc44eff 654 if (drawable && (flags & wxCONTROL_SELECTED))
daebb44c 655 {
c70ad287
VZ
656 int x_diff = 0;
657 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
658 x_diff = rect.width;
659
05d97538
RR
660 // the wxCONTROL_FOCUSED state is deduced
661 // directly from the m_wxwindow by GTK+
385e8575 662 gtk_paint_flat_box(gtk_widget_get_style(wxGTKPrivate::GetTreeWidget()),
9dc44eff 663 drawable,
c70ad287 664 GTK_STATE_SELECTED,
daebb44c 665 GTK_SHADOW_NONE,
9dc44eff 666 NULL_RECT
daebb44c 667 win->m_wxwindow,
05d97538 668 "cell_even",
08f57d21 669 dc.LogicalToDeviceX(rect.x) - x_diff,
daebb44c
RR
670 dc.LogicalToDeviceY(rect.y),
671 rect.width,
672 rect.height );
673 }
90b903c2 674
ce0cf2b8 675 if ((flags & wxCONTROL_CURRENT) && (flags & wxCONTROL_FOCUSED))
c70ad287 676 DrawFocusRect(win, dc, rect, flags);
daebb44c 677}
6d789987
JS
678
679void wxRendererGTK::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
680{
9dc44eff
PC
681 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
682 if (drawable == NULL)
683 return;
6d789987
JS
684
685 GtkStateType state;
686 if (flags & wxCONTROL_SELECTED)
687 state = GTK_STATE_SELECTED;
688 else
689 state = GTK_STATE_NORMAL;
690
9dc44eff
PC
691#ifdef __WXGTK3__
692 GtkStyleContext* sc = gtk_widget_get_style_context(win->m_widget);
693 gtk_style_context_save(sc);
694 gtk_style_context_set_state(sc, stateTypeToFlags[state]);
695 gtk_render_focus(sc, drawable, rect.x, rect.y, rect.width, rect.height);
696 gtk_style_context_restore(sc);
697#else
385e8575 698 gtk_paint_focus( gtk_widget_get_style(win->m_widget),
9dc44eff 699 drawable,
6d789987 700 state,
9dc44eff 701 NULL_RECT
6d789987
JS
702 win->m_wxwindow,
703 NULL,
704 dc.LogicalToDeviceX(rect.x),
705 dc.LogicalToDeviceY(rect.y),
706 rect.width,
707 rect.height );
9dc44eff 708#endif
6d789987 709}
e4131985 710
9dc44eff
PC
711//TODO: GTK3 implementations for the remaining functions below
712
e4131985 713// Uses the theme to draw the border and fill for something like a wxTextCtrl
02f07b19 714void wxRendererGTK::DrawTextCtrl(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
e4131985
KO
715{
716 GtkWidget *entry = wxGTKPrivate::GetTextEntryWidget();
717
9dc44eff
PC
718 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
719 if (drawable == NULL)
720 return;
e4131985
KO
721
722 GtkStateType state = GTK_STATE_NORMAL;
723 if ( flags & wxCONTROL_DISABLED )
724 state = GTK_STATE_INSENSITIVE;
99c4be68 725
385e8575 726 gtk_widget_set_can_focus(entry, (flags & wxCONTROL_CURRENT) != 0);
e4131985
KO
727
728 gtk_paint_shadow
729 (
385e8575 730 gtk_widget_get_style(entry),
9dc44eff 731 drawable,
e4131985
KO
732 state,
733 GTK_SHADOW_OUT,
9dc44eff 734 NULL_RECT
e4131985
KO
735 entry,
736 "entry",
737 dc.LogicalToDeviceX(rect.x),
738 dc.LogicalToDeviceY(rect.y),
739 rect.width,
99c4be68 740 rect.height
e4131985
KO
741 );
742}
743
4c51a665 744// Draw the equivalent of a wxComboBox
02f07b19 745void wxRendererGTK::DrawComboBox(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
e4131985
KO
746{
747 GtkWidget *combo = wxGTKPrivate::GetComboBoxWidget();
748
9dc44eff 749 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
e4131985
KO
750
751 GtkStateType state = GTK_STATE_NORMAL;
752 if ( flags & wxCONTROL_DISABLED )
753 state = GTK_STATE_INSENSITIVE;
99c4be68 754
385e8575 755 gtk_widget_set_can_focus(combo, (flags & wxCONTROL_CURRENT) != 0);
e4131985 756
9dc44eff
PC
757 if (drawable == NULL)
758 return;
759
e4131985
KO
760 gtk_paint_shadow
761 (
385e8575 762 gtk_widget_get_style(combo),
9dc44eff 763 drawable,
e4131985
KO
764 state,
765 GTK_SHADOW_OUT,
9dc44eff 766 NULL_RECT
e4131985
KO
767 combo,
768 "combobox",
769 dc.LogicalToDeviceX(rect.x),
770 dc.LogicalToDeviceY(rect.y),
771 rect.width,
99c4be68 772 rect.height
e4131985
KO
773 );
774
775 wxRect r = rect;
776 int extent = rect.height / 2;
777 r.x += rect.width - extent - extent/2;
778 r.y += extent/2;
779 r.width = extent;
780 r.height = extent;
781
782 gtk_paint_arrow
783 (
385e8575 784 gtk_widget_get_style(combo),
9dc44eff 785 drawable,
e4131985
KO
786 state,
787 GTK_SHADOW_OUT,
9dc44eff 788 NULL_RECT
e4131985
KO
789 combo,
790 "arrow",
791 GTK_ARROW_DOWN,
792 TRUE,
793 dc.LogicalToDeviceX(r.x),
794 dc.LogicalToDeviceY(r.y),
795 r.width,
796 r.height
797 );
798
799 r = rect;
800 r.x += rect.width - 2*extent;
801 r.width = 2;
802
803 gtk_paint_box
804 (
385e8575 805 gtk_widget_get_style(combo),
9dc44eff 806 drawable,
e4131985
KO
807 state,
808 GTK_SHADOW_ETCHED_OUT,
9dc44eff 809 NULL_RECT
e4131985
KO
810 combo,
811 "vseparator",
812 dc.LogicalToDeviceX(r.x),
813 dc.LogicalToDeviceY(r.y+1),
814 r.width,
815 r.height-2
816 );
817}
818
819
820void wxRendererGTK::DrawChoice(wxWindow* win, wxDC& dc,
821 const wxRect& rect, int flags)
822{
823 DrawComboBox( win, dc, rect, flags );
824}
825
99c4be68 826
e4131985 827// Draw a themed radio button
6e6b532c 828void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
e4131985
KO
829{
830 GtkWidget *button = wxGTKPrivate::GetRadioButtonWidget();
831
9dc44eff
PC
832 wxGTKDrawable* drawable = wxGetGTKDrawable(win, dc);
833 if (drawable == NULL)
834 return;
99c4be68 835
e4131985
KO
836 GtkShadowType shadow_type = GTK_SHADOW_OUT;
837 if ( flags & wxCONTROL_CHECKED )
838 shadow_type = GTK_SHADOW_IN;
839 else if ( flags & wxCONTROL_UNDETERMINED )
840 shadow_type = GTK_SHADOW_ETCHED_IN;
99c4be68 841
e4131985
KO
842 GtkStateType state = GTK_STATE_NORMAL;
843 if ( flags & wxCONTROL_DISABLED )
7e717730 844 state = GTK_STATE_INSENSITIVE;
e4131985 845 if ( flags & wxCONTROL_PRESSED )
7e717730 846 state = GTK_STATE_ACTIVE;
e4131985
KO
847/*
848 Don't know when to set this
849 state_type = GTK_STATE_PRELIGHT;
850*/
851
852 gtk_paint_option
853 (
385e8575 854 gtk_widget_get_style(button),
9dc44eff 855 drawable,
e4131985
KO
856 state,
857 shadow_type,
9dc44eff 858 NULL_RECT
e4131985
KO
859 button,
860 "radiobutton",
99c4be68
VZ
861 dc.LogicalToDeviceX(rect.x),
862 dc.LogicalToDeviceY(rect.y),
e4131985
KO
863 rect.width, rect.height
864 );
865}