]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/renderer.cpp
guard against errors like in wxStringBase::AllocBeforeWrite code (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
34 #ifdef __WXGTK20__
35 #include "wx/settings.h"
36 #endif // GTK 2.0
37
38 #ifdef __WXGTK20__
39 #define WXUNUSED_IN_GTK1(arg) arg
40 #else
41 #define WXUNUSED_IN_GTK1(arg)
42 #endif
43
44 // ----------------------------------------------------------------------------
45 // wxRendererGTK: our wxRendererNative implementation
46 // ----------------------------------------------------------------------------
47
48 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
49 {
50 public:
51 // draw the header control button (used by wxListCtrl)
52 virtual void DrawHeaderButton(wxWindow *win,
53 wxDC& dc,
54 const wxRect& rect,
55 int flags = 0);
56
57 #ifdef __WXGTK20__
58 // draw the expanded/collapsed icon for a tree control item
59 virtual void DrawTreeItemButton(wxWindow *win,
60 wxDC& dc,
61 const wxRect& rect,
62 int flags = 0);
63 #endif // GTK 2.0
64
65 virtual void DrawSplitterBorder(wxWindow *win,
66 wxDC& dc,
67 const wxRect& rect,
68 int flags = 0);
69 virtual void DrawSplitterSash(wxWindow *win,
70 wxDC& dc,
71 const wxSize& size,
72 wxCoord position,
73 wxOrientation orient,
74 int flags = 0);
75
76 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
77 };
78
79 // ============================================================================
80 // implementation
81 // ============================================================================
82
83 /* static */
84 wxRendererNative& wxRendererNative::GetDefault()
85 {
86 static wxRendererGTK s_rendererGTK;
87
88 return s_rendererGTK;
89 }
90
91 // ----------------------------------------------------------------------------
92 // list/tree controls drawing
93 // ----------------------------------------------------------------------------
94
95 void
96 wxRendererGTK::DrawHeaderButton(wxWindow *win,
97 wxDC& dc,
98 const wxRect& rect,
99 int flags)
100 {
101
102 static GtkWidget *s_button = NULL;
103 static GtkWidget *s_window = NULL;
104 if (s_button == NULL)
105 {
106 s_window = gtk_window_new( GTK_WINDOW_POPUP );
107 gtk_widget_realize( s_window );
108 s_button = gtk_button_new();
109 gtk_container_add( GTK_CONTAINER(s_window), s_button );
110 gtk_widget_realize( s_button );
111 }
112
113 gtk_paint_box
114 (
115 s_button->style,
116 GTK_PIZZA(win->m_wxwindow)->bin_window,
117 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
118 GTK_SHADOW_OUT,
119 NULL,
120 s_button,
121 "button",
122 dc.XLOG2DEV(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
123 );
124 }
125
126 #ifdef __WXGTK20__
127
128 // draw a ">" or "v" button
129 //
130 // TODO: replace the code below with gtk_paint_expander()
131 void
132 wxRendererGTK::DrawTreeItemButton(wxWindow* win,
133 wxDC& dc, const wxRect& rect, int flags)
134 {
135 #define PM_SIZE 8
136
137 GtkPizza *pizza = GTK_PIZZA( win->m_wxwindow );
138 GtkStyle *style = win->m_widget->style;
139 int x = rect.x;
140 int y = rect.y;
141 y = dc.LogicalToDeviceY( y );
142 x = dc.LogicalToDeviceX( x );
143
144 // This draws the GTK+ 2.2.4 triangle
145 x--;
146 GdkPoint points[3];
147
148 if ( flags & wxCONTROL_EXPANDED )
149 {
150 points[0].x = x;
151 points[0].y = y + (PM_SIZE + 2) / 6;
152 points[1].x = points[0].x + (PM_SIZE + 2);
153 points[1].y = points[0].y;
154 points[2].x = (points[0].x + (PM_SIZE + 2) / 2);
155 points[2].y = y + 2 * (PM_SIZE + 2) / 3;
156 }
157 else
158 {
159 points[0].x = x + ((PM_SIZE + 2) / 6 + 2);
160 points[0].y = y - 1;
161 points[1].x = points[0].x;
162 points[1].y = points[0].y + (PM_SIZE + 2);
163 points[2].x = (points[0].x +
164 (2 * (PM_SIZE + 2) / 3 - 1));
165 points[2].y = points[0].y + (PM_SIZE + 2) / 2;
166 }
167
168 if ( flags & wxCONTROL_CURRENT )
169 gdk_draw_polygon( pizza->bin_window, style->fg_gc[GTK_STATE_PRELIGHT], TRUE, points, 3);
170 else
171 gdk_draw_polygon( pizza->bin_window, style->base_gc[GTK_STATE_NORMAL], TRUE, points, 3);
172 gdk_draw_polygon( pizza->bin_window, style->fg_gc[GTK_STATE_NORMAL], FALSE, points, 3 );
173 }
174
175 #endif // GTK 2.0
176
177 // ----------------------------------------------------------------------------
178 // splitter sash drawing
179 // ----------------------------------------------------------------------------
180
181 // all this should probably be read from the current theme settings somehow?
182 #ifdef __WXGTK20__
183 // the full sash size
184 static const wxCoord SASH_FULL_SIZE = 5;
185 #else // GTK+ 1.x
186 // the full sash width (should be even)
187 static const wxCoord SASH_SIZE = 8;
188
189 // margin around the sash
190 static const wxCoord SASH_MARGIN = 2;
191
192 // the full sash size
193 static const wxCoord SASH_FULL_SIZE = SASH_SIZE + SASH_MARGIN;
194 #endif // GTK+ 2.x/1.x
195
196 wxSplitterRenderParams
197 wxRendererGTK::GetSplitterParams(const wxWindow * WXUNUSED(win))
198 {
199 // we don't draw any border, hence 0 for the second field
200 return wxSplitterRenderParams
201 (
202 SASH_FULL_SIZE,
203 0,
204 #ifdef __WXGTK20__
205 true // hot sensitive
206 #else // GTK+ 1.x
207 false // not
208 #endif // GTK+ 2.x/1.x
209 );
210 }
211
212 void
213 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
214 wxDC& WXUNUSED(dc),
215 const wxRect& WXUNUSED(rect),
216 int WXUNUSED(flags))
217 {
218 // nothing to do
219 }
220
221 void
222 wxRendererGTK::DrawSplitterSash(wxWindow *win,
223 wxDC& dc,
224 const wxSize& size,
225 wxCoord position,
226 wxOrientation orient,
227 int WXUNUSED_IN_GTK1(flags))
228 {
229 if ( !win->m_wxwindow->window )
230 {
231 // window not realized yet
232 return;
233 }
234
235 // are we drawing vertical or horizontal splitter?
236 const bool isVert = orient == wxVERTICAL;
237
238 GdkRectangle rect;
239 GdkRectangle erase_rect;
240 if ( isVert )
241 {
242 int h = win->GetClientSize().GetHeight();
243
244 rect.x = position;
245 rect.y = 0;
246 rect.width = SASH_FULL_SIZE;
247 rect.height = h;
248
249 erase_rect.x = position;
250 erase_rect.y = 0;
251 erase_rect.width = SASH_FULL_SIZE;
252 erase_rect.height = h;
253 }
254 else // horz
255 {
256 int w = win->GetClientSize().GetWidth();
257
258 rect.x = 0;
259 rect.y = position;
260 rect.height = SASH_FULL_SIZE;
261 rect.width = w;
262
263 erase_rect.y = position;
264 erase_rect.x = 0;
265 erase_rect.height = SASH_FULL_SIZE;
266 erase_rect.width = w;
267 }
268
269 // we must erase everything first, otherwise the garbage from the old sash
270 // is left when dragging it
271 //
272 // TODO: is this the right way to draw themed background?
273 gtk_paint_flat_box
274 (
275 win->m_wxwindow->style,
276 GTK_PIZZA(win->m_wxwindow)->bin_window,
277 GTK_STATE_NORMAL,
278 GTK_SHADOW_NONE,
279 NULL,
280 win->m_wxwindow,
281 (char *)"base", // const_cast
282 erase_rect.x,
283 erase_rect.y,
284 erase_rect.width,
285 erase_rect.height
286 );
287
288 #ifdef __WXGTK20__
289 gtk_paint_handle
290 (
291 win->m_wxwindow->style,
292 GTK_PIZZA(win->m_wxwindow)->bin_window,
293 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
294 GTK_SHADOW_NONE,
295 NULL /* no clipping */,
296 win->m_wxwindow,
297 "paned",
298 rect.x,
299 rect.y,
300 rect.width,
301 rect.height,
302 !isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
303 );
304 #else // GTK+ 1.x
305
306 // leave some margin before sash itself
307 position += SASH_MARGIN / 2;
308
309 // and finally draw it using GTK paint functions
310 typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
311 GtkStateType,
312 GdkRectangle *, GtkWidget *,
313 gchar *,
314 gint, gint, gint);
315
316 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
317
318 (*func)
319 (
320 win->m_wxwindow->style,
321 GTK_PIZZA(win->m_wxwindow)->bin_window,
322 GTK_STATE_NORMAL,
323 NULL,
324 win->m_wxwindow,
325 (char *)"paned", // const_cast
326 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
327 );
328
329 gtk_paint_box
330 (
331 win->m_wxwindow->style,
332 GTK_PIZZA(win->m_wxwindow)->bin_window,
333 GTK_STATE_NORMAL,
334 GTK_SHADOW_OUT,
335 (GdkRectangle*) NULL,
336 win->m_wxwindow,
337 (char *)"paned", // const_cast
338 isVert ? position : size.x - 2*SASH_SIZE,
339 isVert ? size.y - 2*SASH_SIZE : position,
340 SASH_SIZE, SASH_SIZE
341 );
342 #endif // GTK+ 2.x/1.x
343 }
344