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