Draw listctrls's headers right for themes.
[wxWidgets.git] / src / gtk / renderer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: 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 // License: wxWindows license
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 #ifndef WX_PRECOMP
28 #endif // WX_PRECOMP
29
30 #include <gtk/gtk.h>
31 #include "wx/gtk/win_gtk.h"
32
33 #include "wx/window.h"
34 #include "wx/dc.h"
35 #include "wx/renderer.h"
36
37 #ifdef __WXGTK20__
38 #include "wx/settings.h"
39 #endif // GTK 2.0
40
41 #ifdef __WXGTK20__
42 #define WXUNUSED_IN_GTK1(arg) arg
43 #else
44 #define WXUNUSED_IN_GTK1(arg)
45 #endif
46
47 // ----------------------------------------------------------------------------
48 // wxRendererGTK: our wxRendererNative implementation
49 // ----------------------------------------------------------------------------
50
51 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
52 {
53 public:
54 // draw the header control button (used by wxListCtrl)
55 virtual void DrawHeaderButton(wxWindow *win,
56 wxDC& dc,
57 const wxRect& rect,
58 int flags = 0);
59
60 #ifdef __WXGTK20__
61 // draw the expanded/collapsed icon for a tree control item
62 virtual void DrawTreeItemButton(wxWindow *win,
63 wxDC& dc,
64 const wxRect& rect,
65 int flags = 0);
66 #endif // GTK 2.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 wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
80 };
81
82 // ============================================================================
83 // implementation
84 // ============================================================================
85
86 /* static */
87 wxRendererNative& wxRendererNative::GetDefault()
88 {
89 static wxRendererGTK s_rendererGTK;
90
91 return s_rendererGTK;
92 }
93
94 // ----------------------------------------------------------------------------
95 // list/tree controls drawing
96 // ----------------------------------------------------------------------------
97
98 void
99 wxRendererGTK::DrawHeaderButton(wxWindow *win,
100 wxDC& dc,
101 const wxRect& rect,
102 int flags)
103 {
104
105 static GtkWidget *s_button = NULL;
106 static GtkWidget *s_window = NULL;
107 if (s_button == NULL)
108 {
109 s_window = gtk_window_new( GTK_WINDOW_POPUP );
110 gtk_widget_realize( s_window );
111 s_button = gtk_button_new();
112 gtk_container_add( GTK_CONTAINER(s_window), s_button );
113 gtk_widget_realize( s_button );
114 }
115
116 gtk_paint_box
117 (
118 s_button->style,
119 GTK_PIZZA(win->m_wxwindow)->bin_window,
120 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
121 GTK_SHADOW_OUT,
122 NULL,
123 s_button,
124 "button",
125 dc.XLOG2DEV(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
126 );
127 }
128
129 #ifdef __WXGTK20__
130
131 // draw a ">" or "v" button
132 //
133 // TODO: isn't there a GTK function to draw it?
134 void
135 wxRendererGTK::DrawTreeItemButton(wxWindow* WXUNUSED(win),
136 wxDC& dc, const wxRect& rect, int flags)
137 {
138 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),
139 wxSOLID));
140 dc.SetPen(*wxBLACK_PEN);
141 wxPoint button[3];
142
143 const wxCoord xMiddle = rect.x + rect.width/2;
144 const wxCoord yMiddle = rect.y + rect.height/2;
145
146 if ( flags & wxCONTROL_EXPANDED )
147 {
148 button[0].x = rect.GetLeft();
149 button[0].y = yMiddle - 2;
150 button[1].x = rect.GetRight();
151 button[1].y = yMiddle - 2;
152 button[2].x = xMiddle;
153 button[2].y = yMiddle + 3;
154 }
155 else // collapsed
156 {
157 button[0].y = rect.GetBottom();
158 button[0].x = xMiddle - 2;
159 button[1].y = rect.GetTop();
160 button[1].x = xMiddle - 2;
161 button[2].y = yMiddle;
162 button[2].x = xMiddle + 3;
163 }
164
165 dc.DrawPolygon(3, button);
166 }
167
168 #endif // GTK 2.0
169
170 // ----------------------------------------------------------------------------
171 // splitter sash drawing
172 // ----------------------------------------------------------------------------
173
174 // all this should probably be read from the current theme settings somehow?
175 #ifdef __WXGTK20__
176 // the full sash size
177 static const wxCoord SASH_FULL_SIZE = 5;
178 #else // GTK+ 1.x
179 // the full sash width (should be even)
180 static const wxCoord SASH_SIZE = 10;
181
182 // margin around the sash
183 static const wxCoord SASH_MARGIN = 5;
184
185 // the full sash size
186 static const wxCoord SASH_FULL_SIZE = SASH_SIZE + SASH_MARGIN;
187 #endif // GTK+ 2.x/1.x
188
189 wxSplitterRenderParams
190 wxRendererGTK::GetSplitterParams(const wxWindow * WXUNUSED(win))
191 {
192 // we don't draw any border, hence 0 for the second field
193 return wxSplitterRenderParams
194 (
195 SASH_FULL_SIZE,
196 0,
197 #ifdef __WXGTK20__
198 true // hot sensitive
199 #else // GTK+ 1.x
200 false // not
201 #endif // GTK+ 2.x/1.x
202 );
203 }
204
205 void
206 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
207 wxDC& WXUNUSED(dc),
208 const wxRect& WXUNUSED(rect),
209 int WXUNUSED(flags))
210 {
211 // nothing to do
212 }
213
214 void
215 wxRendererGTK::DrawSplitterSash(wxWindow *win,
216 wxDC& dc,
217 const wxSize& size,
218 wxCoord position,
219 wxOrientation orient,
220 int WXUNUSED_IN_GTK1(flags))
221 {
222 if ( !win->m_wxwindow->window )
223 {
224 // VZ: this happens on startup -- why?
225 return;
226 }
227
228 // are we drawing vertical or horizontal splitter?
229 const bool isVert = orient == wxVERTICAL;
230
231 GdkRectangle rect;
232 if ( isVert )
233 {
234 rect.x = position;
235 rect.y = 0;
236 rect.width = SASH_FULL_SIZE;
237 rect.height = size.y;
238 }
239 else // horz
240 {
241 rect.x = 0;
242 rect.y = position;
243 rect.height = SASH_FULL_SIZE;
244 rect.width = size.x;
245 }
246
247 #ifdef __WXGTK20__
248 gtk_paint_handle
249 (
250 win->m_wxwindow->style,
251 GTK_PIZZA(win->m_wxwindow)->bin_window,
252 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
253 GTK_SHADOW_NONE,
254 NULL /* no clipping */,
255 win->m_wxwindow,
256 "paned",
257 rect.x,
258 rect.y,
259 rect.width,
260 rect.height,
261 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
262 );
263 #else // GTK+ 1.x
264 // we must erase everything first, otherwise the garbage from the old sash
265 // is left when dragging it
266 //
267 // TODO: is this the right way to draw themed background?
268 gtk_paint_flat_box
269 (
270 win->m_wxwindow->style,
271 GTK_PIZZA(win->m_wxwindow)->bin_window,
272 GTK_STATE_NORMAL,
273 GTK_SHADOW_NONE,
274 &rect,
275 win->m_wxwindow,
276 (char *)"base", // const_cast
277 0, 0, -1, -1
278 );
279
280
281 // leave some margin before sash itself
282 position += SASH_MARGIN / 2;
283
284 // and finally draw it using GTK paint functions
285 typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
286 GtkStateType,
287 GdkRectangle *, GtkWidget *,
288 gchar *,
289 gint, gint, gint);
290
291 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
292
293 (*func)
294 (
295 win->m_wxwindow->style,
296 GTK_PIZZA(win->m_wxwindow)->bin_window,
297 GTK_STATE_NORMAL,
298 NULL,
299 win->m_wxwindow,
300 (char *)"paned", // const_cast
301 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
302 );
303
304 gtk_paint_box
305 (
306 win->m_wxwindow->style,
307 GTK_PIZZA(win->m_wxwindow)->bin_window,
308 GTK_STATE_NORMAL,
309 GTK_SHADOW_OUT,
310 (GdkRectangle*) NULL,
311 win->m_wxwindow,
312 (char *)"paned", // const_cast
313 isVert ? position : size.x - 2*SASH_SIZE,
314 isVert ? size.y - 2*SASH_SIZE : position,
315 SASH_SIZE, SASH_SIZE
316 );
317 #endif // GTK+ 2.x/1.x
318 }
319