There shouldn't be any need to draw the backgound
[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 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 #include <gtk/gtk.h>
29 #include "wx/gtk/win_gtk.h"
30
31 #include "wx/window.h"
32 #include "wx/dc.h"
33 #include "wx/dcclient.h"
34
35 #ifdef __WXGTK20__
36 #include "wx/settings.h"
37 #endif // GTK 2.0
38
39 #ifdef __WXGTK20__
40 #define WXUNUSED_IN_GTK1(arg) arg
41 #else
42 #define WXUNUSED_IN_GTK1(arg)
43 #endif
44
45 // ----------------------------------------------------------------------------
46 // wxRendererGTK: our wxRendererNative implementation
47 // ----------------------------------------------------------------------------
48
49 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
50 {
51 public:
52 // draw the header control button (used by wxListCtrl)
53 virtual void DrawHeaderButton(wxWindow *win,
54 wxDC& dc,
55 const wxRect& rect,
56 int flags = 0);
57
58 #ifdef __WXGTK20__
59 // draw the expanded/collapsed icon for a tree control item
60 virtual void DrawTreeItemButton(wxWindow *win,
61 wxDC& dc,
62 const wxRect& rect,
63 int flags = 0);
64 #endif // GTK+ 2.0
65
66 virtual void DrawSplitterBorder(wxWindow *win,
67 wxDC& dc,
68 const wxRect& rect,
69 int flags = 0);
70 virtual void DrawSplitterSash(wxWindow *win,
71 wxDC& dc,
72 const wxSize& size,
73 wxCoord position,
74 wxOrientation orient,
75 int flags = 0);
76
77 virtual void DrawComboBoxDropButton(wxWindow *win,
78 wxDC& dc,
79 const wxRect& rect,
80 int flags = 0);
81
82 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
83
84 private:
85 // FIXME: shouldn't we destroy these windows somewhere?
86
87 // used by DrawHeaderButton and DrawComboBoxDropButton
88 static GtkWidget *GetButtonWidget();
89
90 #ifdef __WXGTK20__
91 // used by DrawTreeItemButton()
92 static GtkWidget *GetTreeWidget();
93 #endif // GTK+ 2.0
94 };
95
96 // ============================================================================
97 // implementation
98 // ============================================================================
99
100 /* static */
101 wxRendererNative& wxRendererNative::GetDefault()
102 {
103 static wxRendererGTK s_rendererGTK;
104
105 return s_rendererGTK;
106 }
107
108 // ----------------------------------------------------------------------------
109 // helper functions
110 // ----------------------------------------------------------------------------
111
112 GtkWidget *
113 wxRendererGTK::GetButtonWidget()
114 {
115 static GtkWidget *s_button = NULL;
116 static GtkWidget *s_window = NULL;
117
118 if ( !s_button )
119 {
120 s_window = gtk_window_new( GTK_WINDOW_POPUP );
121 gtk_widget_realize( s_window );
122 s_button = gtk_button_new();
123 gtk_container_add( GTK_CONTAINER(s_window), s_button );
124 gtk_widget_realize( s_button );
125 }
126
127 return s_button;
128 }
129
130 #ifdef __WXGTK20__
131
132 GtkWidget *
133 wxRendererGTK::GetTreeWidget()
134 {
135 static GtkWidget *s_tree = NULL;
136 static GtkWidget *s_window = NULL;
137
138 if ( !s_tree )
139 {
140 s_tree = gtk_tree_view_new();
141 s_window = gtk_window_new( GTK_WINDOW_POPUP );
142 gtk_widget_realize( s_window );
143 gtk_container_add( GTK_CONTAINER(s_window), s_tree );
144 gtk_widget_realize( s_tree );
145 }
146
147 return s_tree;
148 }
149
150 #endif // GTK+ 2.0
151
152 // ----------------------------------------------------------------------------
153 // list/tree controls drawing
154 // ----------------------------------------------------------------------------
155
156 void
157 wxRendererGTK::DrawHeaderButton(wxWindow *win,
158 wxDC& dc,
159 const wxRect& rect,
160 int flags)
161 {
162
163 GtkWidget *button = GetButtonWidget();
164
165 gtk_paint_box
166 (
167 button->style,
168 // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC.
169 // Maybe use code similar as in DrawComboBoxDropButton below?
170 GTK_PIZZA(win->m_wxwindow)->bin_window,
171 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
172 GTK_SHADOW_OUT,
173 NULL,
174 button,
175 "button",
176 dc.XLOG2DEV(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
177 );
178 }
179
180 #ifdef __WXGTK20__
181
182 // draw a ">" or "v" button
183 void
184 wxRendererGTK::DrawTreeItemButton(wxWindow* win,
185 wxDC& dc, const wxRect& rect, int flags)
186 {
187 GtkWidget *tree = GetTreeWidget();
188
189 GtkStateType state;
190 if ( flags & wxCONTROL_CURRENT )
191 state = GTK_STATE_PRELIGHT;
192 else
193 state = GTK_STATE_NORMAL;
194
195 // VZ: I don't know how to get the size of the expander so as to centre it
196 // in the given rectangle, +2/3 below is just what looks good here...
197 gtk_paint_expander
198 (
199 tree->style,
200 GTK_PIZZA(win->m_wxwindow)->bin_window,
201 state,
202 NULL,
203 tree,
204 "treeview",
205 dc.LogicalToDeviceX(rect.x) + 2,
206 dc.LogicalToDeviceY(rect.y) + 3,
207 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
208 : GTK_EXPANDER_COLLAPSED
209 );
210 }
211
212 #endif // GTK+ 2.0
213
214 // ----------------------------------------------------------------------------
215 // splitter sash drawing
216 // ----------------------------------------------------------------------------
217
218 // all this should probably be read from the current theme settings somehow?
219 #ifdef __WXGTK20__
220 // the full sash size
221 static const wxCoord SASH_FULL_SIZE = 5;
222 #else // GTK+ 1.x
223 // the full sash width (should be even)
224 static const wxCoord SASH_SIZE = 8;
225
226 // margin around the sash
227 static const wxCoord SASH_MARGIN = 2;
228
229 // the full sash size
230 static const wxCoord SASH_FULL_SIZE = SASH_SIZE + SASH_MARGIN;
231 #endif // GTK+ 2.x/1.x
232
233 wxSplitterRenderParams
234 wxRendererGTK::GetSplitterParams(const wxWindow * WXUNUSED(win))
235 {
236 // we don't draw any border, hence 0 for the second field
237 return wxSplitterRenderParams
238 (
239 SASH_FULL_SIZE,
240 0,
241 #ifdef __WXGTK20__
242 true // hot sensitive
243 #else // GTK+ 1.x
244 false // not
245 #endif // GTK+ 2.x/1.x
246 );
247 }
248
249 void
250 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
251 wxDC& WXUNUSED(dc),
252 const wxRect& WXUNUSED(rect),
253 int WXUNUSED(flags))
254 {
255 // nothing to do
256 }
257
258 void
259 wxRendererGTK::DrawSplitterSash(wxWindow *win,
260 wxDC& dc,
261 const wxSize& size,
262 wxCoord position,
263 wxOrientation orient,
264 int WXUNUSED_IN_GTK1(flags))
265 {
266 if ( !win->m_wxwindow->window )
267 {
268 // window not realized yet
269 return;
270 }
271
272 // are we drawing vertical or horizontal splitter?
273 const bool isVert = orient == wxVERTICAL;
274
275 GdkRectangle rect;
276 GdkRectangle erase_rect;
277 if ( isVert )
278 {
279 int h = win->GetClientSize().GetHeight();
280
281 rect.x = position;
282 rect.y = 0;
283 rect.width = SASH_FULL_SIZE;
284 rect.height = h;
285
286 erase_rect.x = position;
287 erase_rect.y = 0;
288 erase_rect.width = SASH_FULL_SIZE;
289 erase_rect.height = h;
290 }
291 else // horz
292 {
293 int w = win->GetClientSize().GetWidth();
294
295 rect.x = 0;
296 rect.y = position;
297 rect.height = SASH_FULL_SIZE;
298 rect.width = w;
299
300 erase_rect.y = position;
301 erase_rect.x = 0;
302 erase_rect.height = SASH_FULL_SIZE;
303 erase_rect.width = w;
304 }
305
306 #if 0
307 // RR: After a correction to the orientation of the sash
308 // this doesn't seem to be required anymore and it
309 // seems to confuse some themes
310
311 // we must erase everything first, otherwise the garbage
312 // from the old sash is left when dragging it
313 gtk_paint_flat_box
314 (
315 win->m_wxwindow->style,
316 GTK_PIZZA(win->m_wxwindow)->bin_window,
317 GTK_STATE_NORMAL,
318 GTK_SHADOW_NONE,
319 NULL,
320 win->m_wxwindow,
321 (char *)"viewportbin", // const_cast
322 erase_rect.x,
323 erase_rect.y,
324 erase_rect.width,
325 erase_rect.height
326 );
327 #endif
328
329 #ifdef __WXGTK20__
330 gtk_paint_handle
331 (
332 win->m_wxwindow->style,
333 GTK_PIZZA(win->m_wxwindow)->bin_window,
334 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
335 GTK_SHADOW_NONE,
336 NULL /* no clipping */,
337 win->m_wxwindow,
338 "paned",
339 rect.x,
340 rect.y,
341 rect.width,
342 rect.height,
343 !isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
344 );
345 #else // GTK+ 1.x
346
347 // leave some margin before sash itself
348 position += SASH_MARGIN / 2;
349
350 // and finally draw it using GTK paint functions
351 typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
352 GtkStateType,
353 GdkRectangle *, GtkWidget *,
354 gchar *,
355 gint, gint, gint);
356
357 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
358
359 (*func)
360 (
361 win->m_wxwindow->style,
362 GTK_PIZZA(win->m_wxwindow)->bin_window,
363 GTK_STATE_NORMAL,
364 NULL,
365 win->m_wxwindow,
366 (char *)"paned", // const_cast
367 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
368 );
369
370 gtk_paint_box
371 (
372 win->m_wxwindow->style,
373 GTK_PIZZA(win->m_wxwindow)->bin_window,
374 GTK_STATE_NORMAL,
375 GTK_SHADOW_OUT,
376 (GdkRectangle*) NULL,
377 win->m_wxwindow,
378 (char *)"paned", // const_cast
379 isVert ? position : size.x - 2*SASH_SIZE,
380 isVert ? size.y - 2*SASH_SIZE : position,
381 SASH_SIZE, SASH_SIZE
382 );
383 #endif // GTK+ 2.x/1.x
384 }
385
386 void wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
387 wxDC& dc,
388 const wxRect& rect,
389 int flags)
390 {
391 GtkWidget *button = GetButtonWidget();
392
393 // device context must inherit from wxWindowDC
394 // (so it must be wxClientDC, wxMemoryDC or wxPaintDC)
395 wxWindowDC& wdc = (wxWindowDC&)dc;
396
397 // only doing debug-time checking here (it should probably be enough)
398 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
399
400 GtkStateType state;
401
402 if ( flags & wxCONTROL_CURRENT )
403 state = GTK_STATE_PRELIGHT;
404 else if ( flags & wxCONTROL_DISABLED )
405 state = GTK_STATE_INSENSITIVE;
406 else
407 state = GTK_STATE_NORMAL;
408
409 // draw arrow on button
410 gtk_paint_arrow
411 (
412 button->style,
413 wdc.m_window,
414 state,
415 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
416 NULL,
417 button,
418 "arrow",
419 GTK_ARROW_DOWN,
420 FALSE,
421 rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2
422 );
423 }
424