1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/renderer.cpp
3 // Purpose: implementation of wxRendererNative for wxGTK
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/renderer.h"
30 #include "wx/window.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #include "wx/module.h"
36 #include "wx/gtk/dc.h"
37 #include "wx/gtk/private.h"
41 // ----------------------------------------------------------------------------
42 // wxRendererGTK: our wxRendererNative implementation
43 // ----------------------------------------------------------------------------
45 class WXDLLEXPORT wxRendererGTK
: public wxDelegateRendererNative
48 // draw the header control button (used by wxListCtrl)
49 virtual int DrawHeaderButton(wxWindow
*win
,
53 wxHeaderSortIconType sortArrow
= wxHDR_SORT_ICON_NONE
,
54 wxHeaderButtonParams
* params
= NULL
);
56 // draw the expanded/collapsed icon for a tree control item
57 virtual void DrawTreeItemButton(wxWindow
*win
,
62 virtual void DrawSplitterBorder(wxWindow
*win
,
66 virtual void DrawSplitterSash(wxWindow
*win
,
73 virtual void DrawComboBoxDropButton(wxWindow
*win
,
78 virtual void DrawDropArrow(wxWindow
*win
,
83 virtual void DrawCheckBox(wxWindow
*win
,
88 virtual void DrawPushButton(wxWindow
*win
,
93 virtual void DrawItemSelectionRect(wxWindow
*win
,
98 virtual void DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
= 0);
100 virtual wxSize
GetCheckBoxSize(wxWindow
*win
);
102 virtual wxSplitterRenderParams
GetSplitterParams(const wxWindow
*win
);
105 // ============================================================================
107 // ============================================================================
110 wxRendererNative
& wxRendererNative::GetDefault()
112 static wxRendererGTK s_rendererGTK
;
114 return s_rendererGTK
;
117 // ----------------------------------------------------------------------------
118 // list/tree controls drawing
119 // ----------------------------------------------------------------------------
122 wxRendererGTK::DrawHeaderButton(wxWindow
*win
,
126 wxHeaderSortIconType sortArrow
,
127 wxHeaderButtonParams
* params
)
130 GtkWidget
*button
= wxGTKPrivate::GetHeaderButtonWidget();
132 GdkWindow
* gdk_window
= NULL
;
134 wxDCImpl
*impl
= dc
.GetImpl();
135 wxGTKDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxGTKDCImpl
);
137 gdk_window
= gtk_impl
->GetGDKWindow();
139 gdk_window
= dc
.GetGDKWindow();
141 wxASSERT_MSG( gdk_window
,
142 wxT("cannot use wxRendererNative on wxDC of this type") );
145 if (win
->GetLayoutDirection() == wxLayout_RightToLeft
)
148 GtkStateType state
= GTK_STATE_NORMAL
;
149 if (flags
& wxCONTROL_DISABLED
)
150 state
= GTK_STATE_INSENSITIVE
;
153 if (flags
& wxCONTROL_CURRENT
)
154 state
= GTK_STATE_PRELIGHT
;
166 dc
.LogicalToDeviceX(rect
.x
) - x_diff
, rect
.y
, rect
.width
, rect
.height
169 return DrawHeaderButtonContents(win
, dc
, rect
, flags
, sortArrow
, params
);
172 // draw a ">" or "v" button
174 wxRendererGTK::DrawTreeItemButton(wxWindow
* win
,
175 wxDC
& dc
, const wxRect
& rect
, int flags
)
177 GtkWidget
*tree
= wxGTKPrivate::GetTreeWidget();
179 GdkWindow
* gdk_window
= NULL
;
181 wxDCImpl
*impl
= dc
.GetImpl();
182 wxGTKDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxGTKDCImpl
);
184 gdk_window
= gtk_impl
->GetGDKWindow();
186 gdk_window
= dc
.GetGDKWindow();
188 wxASSERT_MSG( gdk_window
,
189 wxT("cannot use wxRendererNative on wxDC of this type") );
192 if ( flags
& wxCONTROL_CURRENT
)
193 state
= GTK_STATE_PRELIGHT
;
195 state
= GTK_STATE_NORMAL
;
198 if (win
->GetLayoutDirection() == wxLayout_RightToLeft
)
201 // VZ: I don't know how to get the size of the expander so as to centre it
202 // in the given rectangle, +2/3 below is just what looks good here...
211 dc
.LogicalToDeviceX(rect
.x
) + 6 - x_diff
,
212 dc
.LogicalToDeviceY(rect
.y
) + 3,
213 flags
& wxCONTROL_EXPANDED
? GTK_EXPANDER_EXPANDED
214 : GTK_EXPANDER_COLLAPSED
219 // ----------------------------------------------------------------------------
220 // splitter sash drawing
221 // ----------------------------------------------------------------------------
223 static int GetGtkSplitterFullSize(GtkWidget
* widget
)
226 gtk_widget_style_get(widget
, "handle_size", &handle_size
, NULL
);
231 wxSplitterRenderParams
232 wxRendererGTK::GetSplitterParams(const wxWindow
*WXUNUSED(win
))
234 // we don't draw any border, hence 0 for the second field
235 return wxSplitterRenderParams
237 GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget()),
239 true // hot sensitive
244 wxRendererGTK::DrawSplitterBorder(wxWindow
* WXUNUSED(win
),
246 const wxRect
& WXUNUSED(rect
),
253 wxRendererGTK::DrawSplitterSash(wxWindow
*win
,
257 wxOrientation orient
,
260 if ( !win
->m_wxwindow
->window
)
262 // window not realized yet
266 GdkWindow
* gdk_window
= NULL
;
268 wxDCImpl
*impl
= dc
.GetImpl();
269 wxGTKDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxGTKDCImpl
);
271 gdk_window
= gtk_impl
->GetGDKWindow();
273 gdk_window
= dc
.GetGDKWindow();
275 wxASSERT_MSG( gdk_window
,
276 wxT("cannot use wxRendererNative on wxDC of this type") );
278 wxCoord full_size
= GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget());
280 // are we drawing vertical or horizontal splitter?
281 const bool isVert
= orient
== wxVERTICAL
;
289 rect
.width
= full_size
;
290 rect
.height
= size
.y
;
296 rect
.height
= full_size
;
301 if (win
->GetLayoutDirection() == wxLayout_RightToLeft
)
306 win
->m_wxwindow
->style
,
308 flags
& wxCONTROL_CURRENT
? GTK_STATE_PRELIGHT
: GTK_STATE_NORMAL
,
310 NULL
/* no clipping */,
313 dc
.LogicalToDeviceX(rect
.x
) - x_diff
,
314 dc
.LogicalToDeviceY(rect
.y
),
317 isVert
? GTK_ORIENTATION_VERTICAL
: GTK_ORIENTATION_HORIZONTAL
322 wxRendererGTK::DrawDropArrow(wxWindow
*WXUNUSED(win
),
327 GtkWidget
*button
= wxGTKPrivate::GetButtonWidget();
329 // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
330 // a window for gtk_paint_xxx function, then it won't
331 // work for wxMemoryDC. So that is why we assume wxDC
332 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
333 // are derived from it) and use its m_window.
334 GdkWindow
* gdk_window
= NULL
;
336 wxDCImpl
*impl
= dc
.GetImpl();
337 wxGTKDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxGTKDCImpl
);
339 gdk_window
= gtk_impl
->GetGDKWindow();
341 gdk_window
= dc
.GetGDKWindow();
343 wxASSERT_MSG( gdk_window
,
344 wxT("cannot use wxRendererNative on wxDC of this type") );
346 // draw arrow so that there is even space horizontally
348 int arrowX
= rect
.width
/4 + 1;
349 int arrowWidth
= rect
.width
- (arrowX
*2);
351 // scale arrow's height accoording to the width
352 int arrowHeight
= rect
.width
/3;
353 int arrowY
= (rect
.height
-arrowHeight
)/2 +
354 ((rect
.height
-arrowHeight
) & 1);
358 if ( flags
& wxCONTROL_PRESSED
)
359 state
= GTK_STATE_ACTIVE
;
360 else if ( flags
& wxCONTROL_DISABLED
)
361 state
= GTK_STATE_INSENSITIVE
;
362 else if ( flags
& wxCONTROL_CURRENT
)
363 state
= GTK_STATE_PRELIGHT
;
365 state
= GTK_STATE_NORMAL
;
367 // draw arrow on button
373 flags
& wxCONTROL_PRESSED
? GTK_SHADOW_IN
: GTK_SHADOW_OUT
,
387 wxRendererGTK::DrawComboBoxDropButton(wxWindow
*win
,
392 DrawPushButton(win
,dc
,rect
,flags
);
393 DrawDropArrow(win
,dc
,rect
);
397 wxRendererGTK::GetCheckBoxSize(wxWindow
*WXUNUSED(win
))
399 gint indicator_size
, indicator_spacing
;
400 gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(),
401 "indicator_size", &indicator_size
,
402 "indicator_spacing", &indicator_spacing
,
405 int size
= indicator_size
+ indicator_spacing
* 2;
406 return wxSize(size
, size
);
410 wxRendererGTK::DrawCheckBox(wxWindow
*WXUNUSED(win
),
415 GtkWidget
*button
= wxGTKPrivate::GetCheckButtonWidget();
417 GdkWindow
* gdk_window
= NULL
;
419 wxDCImpl
*impl
= dc
.GetImpl();
420 wxGTKDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxGTKDCImpl
);
422 gdk_window
= gtk_impl
->GetGDKWindow();
424 gdk_window
= dc
.GetGDKWindow();
426 wxASSERT_MSG( gdk_window
,
427 wxT("cannot use wxRendererNative on wxDC of this type") );
429 gint indicator_size
, indicator_spacing
;
430 gtk_widget_style_get(button
,
431 "indicator_size", &indicator_size
,
432 "indicator_spacing", &indicator_spacing
,
437 if ( flags
& wxCONTROL_PRESSED
)
438 state
= GTK_STATE_ACTIVE
;
439 else if ( flags
& wxCONTROL_DISABLED
)
440 state
= GTK_STATE_INSENSITIVE
;
441 else if ( flags
& wxCONTROL_CURRENT
)
442 state
= GTK_STATE_PRELIGHT
;
444 state
= GTK_STATE_NORMAL
;
451 flags
& wxCONTROL_CHECKED
? GTK_SHADOW_IN
: GTK_SHADOW_OUT
,
455 dc
.LogicalToDeviceX(rect
.x
) + indicator_spacing
,
456 dc
.LogicalToDeviceY(rect
.y
) + indicator_spacing
,
457 indicator_size
, indicator_size
462 wxRendererGTK::DrawPushButton(wxWindow
*WXUNUSED(win
),
467 GtkWidget
*button
= wxGTKPrivate::GetButtonWidget();
469 GdkWindow
* gdk_window
= NULL
;
471 wxDCImpl
*impl
= dc
.GetImpl();
472 wxGTKDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxGTKDCImpl
);
474 gdk_window
= gtk_impl
->GetGDKWindow();
476 gdk_window
= dc
.GetGDKWindow();
478 wxASSERT_MSG( gdk_window
,
479 wxT("cannot use wxRendererNative on wxDC of this type") );
484 if ( flags
& wxCONTROL_PRESSED
)
485 state
= GTK_STATE_ACTIVE
;
486 else if ( flags
& wxCONTROL_DISABLED
)
487 state
= GTK_STATE_INSENSITIVE
;
488 else if ( flags
& wxCONTROL_CURRENT
)
489 state
= GTK_STATE_PRELIGHT
;
491 state
= GTK_STATE_NORMAL
;
498 flags
& wxCONTROL_PRESSED
? GTK_SHADOW_IN
: GTK_SHADOW_OUT
,
502 rect
.x
, rect
.y
, rect
.width
, rect
.height
507 wxRendererGTK::DrawItemSelectionRect(wxWindow
*win
,
512 GdkWindow
* gdk_window
= NULL
;
514 wxDCImpl
*impl
= dc
.GetImpl();
515 wxGTKDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxGTKDCImpl
);
517 gdk_window
= gtk_impl
->GetGDKWindow();
519 gdk_window
= dc
.GetGDKWindow();
521 wxASSERT_MSG( gdk_window
,
522 wxT("cannot use wxRendererNative on wxDC of this type") );
525 if (win
->GetLayoutDirection() == wxLayout_RightToLeft
)
529 if (flags
& wxCONTROL_SELECTED
)
531 // the wxCONTROL_FOCUSED state is deduced
532 // directly from the m_wxwindow by GTK+
533 state
= GTK_STATE_SELECTED
;
535 gtk_paint_flat_box( win
->m_widget
->style
,
542 dc
.LogicalToDeviceX(rect
.x
) - x_diff
,
543 dc
.LogicalToDeviceY(rect
.y
),
547 else // !wxCONTROL_SELECTED
549 state
= GTK_STATE_NORMAL
;
552 if ((flags
& wxCONTROL_CURRENT
) && (flags
& wxCONTROL_FOCUSED
))
554 gtk_paint_focus( win
->m_widget
->style
,
559 // Detail "treeview" causes warning with GTK+ 2.12 Clearlooks theme:
560 // "... no property named `row-ending-details'"
561 // Using "treeview-middle" would fix the warning, but the right
562 // edge of the focus rect is not getting erased properly either.
563 // Better to not specify this detail unless the drawing is fixed.
565 dc
.LogicalToDeviceX(rect
.x
),
566 dc
.LogicalToDeviceY(rect
.y
),
572 void wxRendererGTK::DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
)
574 GdkWindow
* gdk_window
= NULL
;
576 wxDCImpl
*impl
= dc
.GetImpl();
577 wxGTKDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxGTKDCImpl
);
579 gdk_window
= gtk_impl
->GetGDKWindow();
581 gdk_window
= dc
.GetGDKWindow();
583 wxASSERT_MSG( gdk_window
,
584 wxT("cannot use wxRendererNative on wxDC of this type") );
587 if (flags
& wxCONTROL_SELECTED
)
588 state
= GTK_STATE_SELECTED
;
590 state
= GTK_STATE_NORMAL
;
592 gtk_paint_focus( win
->m_widget
->style
,
598 dc
.LogicalToDeviceX(rect
.x
),
599 dc
.LogicalToDeviceY(rect
.y
),