remove code ifdef-ed on __X__, it is never defined for wxGTK
[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 #include "wx/gtk/dc.h"
38 #include "wx/gtk/private.h"
39
40 #include <gtk/gtk.h>
41
42 // ----------------------------------------------------------------------------
43 // wxRendererGTK: our wxRendererNative implementation
44 // ----------------------------------------------------------------------------
45
46 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
47 {
48 public:
49 // draw the header control button (used by wxListCtrl)
50 virtual int DrawHeaderButton(wxWindow *win,
51 wxDC& dc,
52 const wxRect& rect,
53 int flags = 0,
54 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
55 wxHeaderButtonParams* params = NULL);
56
57 virtual int GetHeaderButtonHeight(wxWindow *win);
58
59 virtual int GetHeaderButtonMargin(wxWindow *win);
60
61
62 // draw the expanded/collapsed icon for a tree control item
63 virtual void DrawTreeItemButton(wxWindow *win,
64 wxDC& dc,
65 const wxRect& rect,
66 int flags = 0);
67
68 virtual void DrawSplitterBorder(wxWindow *win,
69 wxDC& dc,
70 const wxRect& rect,
71 int flags = 0);
72 virtual void DrawSplitterSash(wxWindow *win,
73 wxDC& dc,
74 const wxSize& size,
75 wxCoord position,
76 wxOrientation orient,
77 int flags = 0);
78
79 virtual void DrawComboBoxDropButton(wxWindow *win,
80 wxDC& dc,
81 const wxRect& rect,
82 int flags = 0);
83
84 virtual void DrawDropArrow(wxWindow *win,
85 wxDC& dc,
86 const wxRect& rect,
87 int flags = 0);
88
89 virtual void DrawCheckBox(wxWindow *win,
90 wxDC& dc,
91 const wxRect& rect,
92 int flags = 0);
93
94 virtual void DrawPushButton(wxWindow *win,
95 wxDC& dc,
96 const wxRect& rect,
97 int flags = 0);
98
99 virtual void DrawItemSelectionRect(wxWindow *win,
100 wxDC& dc,
101 const wxRect& rect,
102 int flags = 0);
103
104 virtual void DrawChoice(wxWindow* win,
105 wxDC& dc,
106 const wxRect& rect,
107 int flags=0);
108
109 virtual void DrawComboBox(wxWindow* win,
110 wxDC& dc,
111 const wxRect& rect,
112 int flags=0);
113
114 virtual void DrawTextCtrl(wxWindow* win,
115 wxDC& dc,
116 const wxRect& rect,
117 int flags=0);
118
119 virtual void DrawRadioBitmap(wxWindow* win,
120 wxDC& dc,
121 const wxRect& rect,
122 int flags=0);
123
124 virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
125
126 virtual wxSize GetCheckBoxSize(wxWindow *win);
127
128 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
129 };
130
131 // ============================================================================
132 // implementation
133 // ============================================================================
134
135 /* static */
136 wxRendererNative& wxRendererNative::GetDefault()
137 {
138 static wxRendererGTK s_rendererGTK;
139
140 return s_rendererGTK;
141 }
142
143 static GdkWindow* wxGetGdkWindowForDC(wxWindow* win, wxDC& dc)
144 {
145 GdkWindow* gdk_window = NULL;
146
147 #if wxUSE_GRAPHICS_CONTEXT
148 if ( dc.IsKindOf( CLASSINFO(wxGCDC) ) )
149 gdk_window = win->GTKGetDrawingWindow();
150 else
151 #endif
152 {
153 #if wxUSE_NEW_DC
154 wxDCImpl *impl = dc.GetImpl();
155 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
156 if (gtk_impl)
157 gdk_window = gtk_impl->GetGDKWindow();
158 #else
159 gdk_window = dc.GetGDKWindow();
160 #endif
161 }
162
163 #if !wxUSE_GRAPHICS_CONTEXT
164 wxUnusedVar(win);
165 #endif
166
167 return gdk_window;
168 }
169
170 // ----------------------------------------------------------------------------
171 // list/tree controls drawing
172 // ----------------------------------------------------------------------------
173
174 int
175 wxRendererGTK::DrawHeaderButton(wxWindow *win,
176 wxDC& dc,
177 const wxRect& rect,
178 int flags,
179 wxHeaderSortIconType sortArrow,
180 wxHeaderButtonParams* params)
181 {
182
183 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
184 if (flags & wxCONTROL_SPECIAL)
185 button = wxGTKPrivate::GetHeaderButtonWidgetFirst();
186 if (flags & wxCONTROL_DIRTY)
187 button = wxGTKPrivate::GetHeaderButtonWidgetLast();
188
189 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
190 wxASSERT_MSG( gdk_window,
191 wxT("cannot use wxRendererNative on wxDC of this type") );
192
193 int x_diff = 0;
194 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
195 x_diff = rect.width;
196
197 GtkStateType state = GTK_STATE_NORMAL;
198 if (flags & wxCONTROL_DISABLED)
199 state = GTK_STATE_INSENSITIVE;
200 else
201 {
202 if (flags & wxCONTROL_CURRENT)
203 state = GTK_STATE_PRELIGHT;
204 }
205
206 gtk_paint_box
207 (
208 gtk_widget_get_style(button),
209 gdk_window,
210 state,
211 GTK_SHADOW_OUT,
212 NULL,
213 button,
214 "button",
215 dc.LogicalToDeviceX(rect.x) - x_diff, rect.y, rect.width, rect.height
216 );
217
218 return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
219 }
220
221 int wxRendererGTK::GetHeaderButtonHeight(wxWindow *WXUNUSED(win))
222 {
223 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
224
225 GtkRequisition req;
226 GTK_WIDGET_GET_CLASS(button)->size_request(button, &req);
227
228 return req.height;
229 }
230
231 int wxRendererGTK::GetHeaderButtonMargin(wxWindow *WXUNUSED(win))
232 {
233 wxFAIL_MSG( "GetHeaderButtonMargin() not implemented" );
234 return -1;
235 }
236
237
238 // draw a ">" or "v" button
239 void
240 wxRendererGTK::DrawTreeItemButton(wxWindow* win,
241 wxDC& dc, const wxRect& rect, int flags)
242 {
243 GtkWidget *tree = wxGTKPrivate::GetTreeWidget();
244
245 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
246 wxASSERT_MSG( gdk_window,
247 wxT("cannot use wxRendererNative on wxDC of this type") );
248
249 GtkStateType state;
250 if ( flags & wxCONTROL_CURRENT )
251 state = GTK_STATE_PRELIGHT;
252 else
253 state = GTK_STATE_NORMAL;
254
255 int x_diff = 0;
256 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
257 x_diff = rect.width;
258
259 // x and y parameters specify the center of the expander
260 gtk_paint_expander
261 (
262 gtk_widget_get_style(tree),
263 gdk_window,
264 state,
265 NULL,
266 tree,
267 "treeview",
268 dc.LogicalToDeviceX(rect.x) + rect.width / 2 - x_diff,
269 dc.LogicalToDeviceY(rect.y) + rect.height / 2,
270 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
271 : GTK_EXPANDER_COLLAPSED
272 );
273 }
274
275
276 // ----------------------------------------------------------------------------
277 // splitter sash drawing
278 // ----------------------------------------------------------------------------
279
280 static int GetGtkSplitterFullSize(GtkWidget* widget)
281 {
282 gint handle_size;
283 gtk_widget_style_get(widget, "handle_size", &handle_size, NULL);
284
285 return handle_size;
286 }
287
288 wxSplitterRenderParams
289 wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
290 {
291 // we don't draw any border, hence 0 for the second field
292 return wxSplitterRenderParams
293 (
294 GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget()),
295 0,
296 true // hot sensitive
297 );
298 }
299
300 void
301 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
302 wxDC& WXUNUSED(dc),
303 const wxRect& WXUNUSED(rect),
304 int WXUNUSED(flags))
305 {
306 // nothing to do
307 }
308
309 void
310 wxRendererGTK::DrawSplitterSash(wxWindow* win,
311 wxDC& dc,
312 const wxSize& size,
313 wxCoord position,
314 wxOrientation orient,
315 int flags)
316 {
317 if (gtk_widget_get_window(win->m_wxwindow) == NULL)
318 {
319 // window not realized yet
320 return;
321 }
322
323 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
324 wxASSERT_MSG( gdk_window,
325 wxT("cannot use wxRendererNative on wxDC of this type") );
326
327 wxCoord full_size = GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget());
328
329 // are we drawing vertical or horizontal splitter?
330 const bool isVert = orient == wxVERTICAL;
331
332 GdkRectangle rect;
333
334 if ( isVert )
335 {
336 rect.x = position;
337 rect.y = 0;
338 rect.width = full_size;
339 rect.height = size.y;
340 }
341 else // horz
342 {
343 rect.x = 0;
344 rect.y = position;
345 rect.height = full_size;
346 rect.width = size.x;
347 }
348
349 int x_diff = 0;
350 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
351 x_diff = rect.width;
352
353 gtk_paint_handle
354 (
355 gtk_widget_get_style(win->m_wxwindow),
356 gdk_window,
357 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
358 GTK_SHADOW_NONE,
359 NULL /* no clipping */,
360 win->m_wxwindow,
361 "paned",
362 dc.LogicalToDeviceX(rect.x) - x_diff,
363 dc.LogicalToDeviceY(rect.y),
364 rect.width,
365 rect.height,
366 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
367 );
368 }
369
370 void
371 wxRendererGTK::DrawDropArrow(wxWindow* win,
372 wxDC& dc,
373 const wxRect& rect,
374 int flags)
375 {
376 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
377
378 // If we give WX_PIZZA(win->m_wxwindow)->bin_window as
379 // a window for gtk_paint_xxx function, then it won't
380 // work for wxMemoryDC. So that is why we assume wxDC
381 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
382 // are derived from it) and use its m_window.
383 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
384 wxASSERT_MSG( gdk_window,
385 wxT("cannot use wxRendererNative on wxDC of this type") );
386
387 // draw arrow so that there is even space horizontally
388 // on both sides
389 int arrowX = rect.width/4 + 1;
390 int arrowWidth = rect.width - (arrowX*2);
391
392 // scale arrow's height accoording to the width
393 int arrowHeight = rect.width/3;
394 int arrowY = (rect.height-arrowHeight)/2 +
395 ((rect.height-arrowHeight) & 1);
396
397 GtkStateType state;
398
399 if ( flags & wxCONTROL_PRESSED )
400 state = GTK_STATE_ACTIVE;
401 else if ( flags & wxCONTROL_DISABLED )
402 state = GTK_STATE_INSENSITIVE;
403 else if ( flags & wxCONTROL_CURRENT )
404 state = GTK_STATE_PRELIGHT;
405 else
406 state = GTK_STATE_NORMAL;
407
408 // draw arrow on button
409 gtk_paint_arrow
410 (
411 gtk_widget_get_style(button),
412 gdk_window,
413 state,
414 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
415 NULL,
416 button,
417 "arrow",
418 GTK_ARROW_DOWN,
419 FALSE,
420 rect.x + arrowX,
421 rect.y + arrowY,
422 arrowWidth,
423 arrowHeight
424 );
425 }
426
427 void
428 wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
429 wxDC& dc,
430 const wxRect& rect,
431 int flags)
432 {
433 DrawPushButton(win,dc,rect,flags);
434 DrawDropArrow(win,dc,rect);
435 }
436
437 wxSize
438 wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
439 {
440 gint indicator_size, indicator_spacing;
441 gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(),
442 "indicator_size", &indicator_size,
443 "indicator_spacing", &indicator_spacing,
444 NULL);
445
446 int size = indicator_size + indicator_spacing * 2;
447 return wxSize(size, size);
448 }
449
450 void
451 wxRendererGTK::DrawCheckBox(wxWindow* win,
452 wxDC& dc,
453 const wxRect& rect,
454 int flags )
455 {
456 GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget();
457
458 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
459 wxASSERT_MSG( gdk_window,
460 wxT("cannot use wxRendererNative on wxDC of this type") );
461
462 gint indicator_size, indicator_spacing;
463 gtk_widget_style_get(button,
464 "indicator_size", &indicator_size,
465 "indicator_spacing", &indicator_spacing,
466 NULL);
467
468 GtkStateType state;
469
470 if ( flags & wxCONTROL_PRESSED )
471 state = GTK_STATE_ACTIVE;
472 else if ( flags & wxCONTROL_DISABLED )
473 state = GTK_STATE_INSENSITIVE;
474 else if ( flags & wxCONTROL_CURRENT )
475 state = GTK_STATE_PRELIGHT;
476 else
477 state = GTK_STATE_NORMAL;
478
479 GtkShadowType shadow_type;
480
481 if ( flags & wxCONTROL_UNDETERMINED )
482 shadow_type = GTK_SHADOW_ETCHED_IN;
483 else if ( flags & wxCONTROL_CHECKED )
484 shadow_type = GTK_SHADOW_IN;
485 else
486 shadow_type = GTK_SHADOW_OUT;
487
488 gtk_paint_check
489 (
490 gtk_widget_get_style(button),
491 gdk_window,
492 state,
493 shadow_type,
494 NULL,
495 button,
496 "cellcheck",
497 dc.LogicalToDeviceX(rect.x) + indicator_spacing,
498 dc.LogicalToDeviceY(rect.y) + indicator_spacing,
499 indicator_size, indicator_size
500 );
501 }
502
503 void
504 wxRendererGTK::DrawPushButton(wxWindow* win,
505 wxDC& dc,
506 const wxRect& rect,
507 int flags)
508 {
509 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
510
511 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
512 wxASSERT_MSG( gdk_window,
513 wxT("cannot use wxRendererNative on wxDC of this type") );
514
515 // draw button
516 GtkStateType state;
517
518 if ( flags & wxCONTROL_PRESSED )
519 state = GTK_STATE_ACTIVE;
520 else if ( flags & wxCONTROL_DISABLED )
521 state = GTK_STATE_INSENSITIVE;
522 else if ( flags & wxCONTROL_CURRENT )
523 state = GTK_STATE_PRELIGHT;
524 else
525 state = GTK_STATE_NORMAL;
526
527 gtk_paint_box
528 (
529 gtk_widget_get_style(button),
530 gdk_window,
531 state,
532 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
533 NULL,
534 button,
535 "button",
536 dc.LogicalToDeviceX(rect.x),
537 dc.LogicalToDeviceY(rect.y),
538 rect.width,
539 rect.height
540 );
541 }
542
543 void
544 wxRendererGTK::DrawItemSelectionRect(wxWindow* win,
545 wxDC& dc,
546 const wxRect& rect,
547 int flags )
548 {
549 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
550 wxASSERT_MSG( gdk_window,
551 wxT("cannot use wxRendererNative on wxDC of this type") );
552
553 if (flags & wxCONTROL_SELECTED)
554 {
555 int x_diff = 0;
556 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
557 x_diff = rect.width;
558
559 // the wxCONTROL_FOCUSED state is deduced
560 // directly from the m_wxwindow by GTK+
561 gtk_paint_flat_box(gtk_widget_get_style(wxGTKPrivate::GetTreeWidget()),
562 gdk_window,
563 GTK_STATE_SELECTED,
564 GTK_SHADOW_NONE,
565 NULL,
566 win->m_wxwindow,
567 "cell_even",
568 dc.LogicalToDeviceX(rect.x) - x_diff,
569 dc.LogicalToDeviceY(rect.y),
570 rect.width,
571 rect.height );
572 }
573
574 if ((flags & wxCONTROL_CURRENT) && (flags & wxCONTROL_FOCUSED))
575 DrawFocusRect(win, dc, rect, flags);
576 }
577
578 void wxRendererGTK::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
579 {
580 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
581 wxASSERT_MSG( gdk_window,
582 wxT("cannot use wxRendererNative on wxDC of this type") );
583
584 GtkStateType state;
585 if (flags & wxCONTROL_SELECTED)
586 state = GTK_STATE_SELECTED;
587 else
588 state = GTK_STATE_NORMAL;
589
590 gtk_paint_focus( gtk_widget_get_style(win->m_widget),
591 gdk_window,
592 state,
593 NULL,
594 win->m_wxwindow,
595 NULL,
596 dc.LogicalToDeviceX(rect.x),
597 dc.LogicalToDeviceY(rect.y),
598 rect.width,
599 rect.height );
600 }
601
602 // Uses the theme to draw the border and fill for something like a wxTextCtrl
603 void wxRendererGTK::DrawTextCtrl(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
604 {
605 GtkWidget *entry = wxGTKPrivate::GetTextEntryWidget();
606
607 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
608
609 GtkStateType state = GTK_STATE_NORMAL;
610 if ( flags & wxCONTROL_DISABLED )
611 state = GTK_STATE_INSENSITIVE;
612
613 gtk_widget_set_can_focus(entry, (flags & wxCONTROL_CURRENT) != 0);
614
615 gtk_paint_shadow
616 (
617 gtk_widget_get_style(entry),
618 gdk_window,
619 state,
620 GTK_SHADOW_OUT,
621 NULL,
622 entry,
623 "entry",
624 dc.LogicalToDeviceX(rect.x),
625 dc.LogicalToDeviceY(rect.y),
626 rect.width,
627 rect.height
628 );
629 }
630
631 // Draw the equivalent of a wxComboBox
632 void wxRendererGTK::DrawComboBox(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
633 {
634 GtkWidget *combo = wxGTKPrivate::GetComboBoxWidget();
635
636 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
637
638 GtkStateType state = GTK_STATE_NORMAL;
639 if ( flags & wxCONTROL_DISABLED )
640 state = GTK_STATE_INSENSITIVE;
641
642 gtk_widget_set_can_focus(combo, (flags & wxCONTROL_CURRENT) != 0);
643
644 gtk_paint_shadow
645 (
646 gtk_widget_get_style(combo),
647 gdk_window,
648 state,
649 GTK_SHADOW_OUT,
650 NULL,
651 combo,
652 "combobox",
653 dc.LogicalToDeviceX(rect.x),
654 dc.LogicalToDeviceY(rect.y),
655 rect.width,
656 rect.height
657 );
658
659 wxRect r = rect;
660 int extent = rect.height / 2;
661 r.x += rect.width - extent - extent/2;
662 r.y += extent/2;
663 r.width = extent;
664 r.height = extent;
665
666 gtk_paint_arrow
667 (
668 gtk_widget_get_style(combo),
669 gdk_window,
670 state,
671 GTK_SHADOW_OUT,
672 NULL,
673 combo,
674 "arrow",
675 GTK_ARROW_DOWN,
676 TRUE,
677 dc.LogicalToDeviceX(r.x),
678 dc.LogicalToDeviceY(r.y),
679 r.width,
680 r.height
681 );
682
683 r = rect;
684 r.x += rect.width - 2*extent;
685 r.width = 2;
686
687 gtk_paint_box
688 (
689 gtk_widget_get_style(combo),
690 gdk_window,
691 state,
692 GTK_SHADOW_ETCHED_OUT,
693 NULL,
694 combo,
695 "vseparator",
696 dc.LogicalToDeviceX(r.x),
697 dc.LogicalToDeviceY(r.y+1),
698 r.width,
699 r.height-2
700 );
701 }
702
703
704 void wxRendererGTK::DrawChoice(wxWindow* win, wxDC& dc,
705 const wxRect& rect, int flags)
706 {
707 DrawComboBox( win, dc, rect, flags );
708 }
709
710
711 // Draw a themed radio button
712 void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
713 {
714 GtkWidget *button = wxGTKPrivate::GetRadioButtonWidget();
715
716 GdkWindow* gdk_window = wxGetGdkWindowForDC(win, dc);
717
718 GtkShadowType shadow_type = GTK_SHADOW_OUT;
719 if ( flags & wxCONTROL_CHECKED )
720 shadow_type = GTK_SHADOW_IN;
721 else if ( flags & wxCONTROL_UNDETERMINED )
722 shadow_type = GTK_SHADOW_ETCHED_IN;
723
724 GtkStateType state = GTK_STATE_NORMAL;
725 if ( flags & wxCONTROL_DISABLED )
726 state = GTK_STATE_INSENSITIVE;
727 if ( flags & wxCONTROL_PRESSED )
728 state = GTK_STATE_ACTIVE;
729 /*
730 Don't know when to set this
731 state_type = GTK_STATE_PRELIGHT;
732 */
733
734 gtk_paint_option
735 (
736 gtk_widget_get_style(button),
737 gdk_window,
738 state,
739 shadow_type,
740 NULL,
741 button,
742 "radiobutton",
743 dc.LogicalToDeviceX(rect.x),
744 dc.LogicalToDeviceY(rect.y),
745 rect.width, rect.height
746 );
747 }