(partially) fixed splitter sash rendering under GTK2
[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 #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* win,
136 wxDC& dc, const wxRect& rect, int flags)
137 {
138 #if 1
139
140 #define PM_SIZE 8
141
142 GtkPizza *pizza = GTK_PIZZA( win->m_wxwindow );
143 GtkStyle *style = win->m_widget->style;
144 int x = rect.x;
145 int y = rect.y;
146 y = dc.LogicalToDeviceY( y );
147 x = dc.LogicalToDeviceX( x );
148
149 #if 1
150 // This draws the GTK+ 2.2.4 triangle
151 x--;
152 GdkPoint points[3];
153
154 if ( flags & wxCONTROL_EXPANDED )
155 {
156 points[0].x = x;
157 points[0].y = y + (PM_SIZE + 2) / 6;
158 points[1].x = points[0].x + (PM_SIZE + 2);
159 points[1].y = points[0].y;
160 points[2].x = (points[0].x + (PM_SIZE + 2) / 2);
161 points[2].y = y + 2 * (PM_SIZE + 2) / 3;
162 }
163 else
164 {
165 points[0].x = x + ((PM_SIZE + 2) / 6 + 2);
166 points[0].y = y - 1;
167 points[1].x = points[0].x;
168 points[1].y = points[0].y + (PM_SIZE + 2);
169 points[2].x = (points[0].x +
170 (2 * (PM_SIZE + 2) / 3 - 1));
171 points[2].y = points[0].y + (PM_SIZE + 2) / 2;
172 }
173
174 if ( flags & wxCONTROL_CURRENT )
175 gdk_draw_polygon( pizza->bin_window, style->fg_gc[GTK_STATE_PRELIGHT], TRUE, points, 3);
176 else
177 gdk_draw_polygon( pizza->bin_window, style->base_gc[GTK_STATE_NORMAL], TRUE, points, 3);
178 gdk_draw_polygon( pizza->bin_window, style->fg_gc[GTK_STATE_NORMAL], FALSE, points, 3 );
179 #else
180 // this draws the GTK+ 2.2.3 tree item square
181 gdk_draw_rectangle( pizza->bin_window,
182 style->base_gc[GTK_STATE_NORMAL], TRUE,
183 x, y, PM_SIZE, PM_SIZE);
184 gdk_draw_rectangle( pizza->bin_window,
185 style->fg_gc[GTK_STATE_NORMAL], FALSE,
186 x, y, PM_SIZE, PM_SIZE);
187
188 gdk_draw_line( pizza->bin_window, style->fg_gc[GTK_STATE_NORMAL],
189 x + 2, y + PM_SIZE / 2, x + PM_SIZE - 2, y + PM_SIZE / 2);
190
191 if ( flags & wxCONTROL_EXPANDED )
192 {
193 gdk_draw_line( pizza->bin_window, style->fg_gc[GTK_STATE_NORMAL],
194 x + PM_SIZE / 2, y + 2,
195 x + PM_SIZE / 2, y + PM_SIZE - 2);
196 }
197 #endif
198
199
200 #else
201 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),
202 wxSOLID));
203 dc.SetPen(*wxBLACK_PEN);
204 wxPoint button[3];
205
206 const wxCoord xMiddle = rect.x + rect.width/2;
207 const wxCoord yMiddle = rect.y + rect.height/2;
208
209 if ( flags & wxCONTROL_EXPANDED )
210 {
211 button[0].x = rect.GetLeft();
212 button[0].y = yMiddle - 2;
213 button[1].x = rect.GetRight();
214 button[1].y = yMiddle - 2;
215 button[2].x = xMiddle;
216 button[2].y = yMiddle + 3;
217 }
218 else // collapsed
219 {
220 button[0].y = rect.GetBottom();
221 button[0].x = xMiddle - 2;
222 button[1].y = rect.GetTop();
223 button[1].x = xMiddle - 2;
224 button[2].y = yMiddle;
225 button[2].x = xMiddle + 3;
226 }
227
228 dc.DrawPolygon(3, button);
229 #endif
230 }
231
232 #endif // GTK 2.0
233
234 // ----------------------------------------------------------------------------
235 // splitter sash drawing
236 // ----------------------------------------------------------------------------
237
238 // all this should probably be read from the current theme settings somehow?
239 #ifdef __WXGTK20__
240 // the full sash size
241 static const wxCoord SASH_FULL_SIZE = 5;
242 #else // GTK+ 1.x
243 // the full sash width (should be even)
244 static const wxCoord SASH_SIZE = 8;
245
246 // margin around the sash
247 static const wxCoord SASH_MARGIN = 2;
248
249 // the full sash size
250 static const wxCoord SASH_FULL_SIZE = SASH_SIZE + SASH_MARGIN;
251 #endif // GTK+ 2.x/1.x
252
253 wxSplitterRenderParams
254 wxRendererGTK::GetSplitterParams(const wxWindow * WXUNUSED(win))
255 {
256 // we don't draw any border, hence 0 for the second field
257 return wxSplitterRenderParams
258 (
259 SASH_FULL_SIZE,
260 0,
261 #ifdef __WXGTK20__
262 true // hot sensitive
263 #else // GTK+ 1.x
264 false // not
265 #endif // GTK+ 2.x/1.x
266 );
267 }
268
269 void
270 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
271 wxDC& WXUNUSED(dc),
272 const wxRect& WXUNUSED(rect),
273 int WXUNUSED(flags))
274 {
275 // nothing to do
276 }
277
278 void
279 wxRendererGTK::DrawSplitterSash(wxWindow *win,
280 wxDC& dc,
281 const wxSize& size,
282 wxCoord position,
283 wxOrientation orient,
284 int WXUNUSED_IN_GTK1(flags))
285 {
286 if ( !win->m_wxwindow->window )
287 {
288 // window not realized yet
289 return;
290 }
291
292 // are we drawing vertical or horizontal splitter?
293 const bool isVert = orient == wxVERTICAL;
294
295 GdkRectangle rect;
296 GdkRectangle erase_rect;
297 if ( isVert )
298 {
299 int h = win->GetClientSize().GetHeight();
300
301 rect.x = position;
302 rect.y = 0;
303 rect.width = SASH_FULL_SIZE;
304 rect.height = h;
305
306 erase_rect.x = position;
307 erase_rect.y = 0;
308 erase_rect.width = SASH_FULL_SIZE;
309 erase_rect.height = h;
310 }
311 else // horz
312 {
313 int w = win->GetClientSize().GetWidth();
314
315 rect.x = 0;
316 rect.y = position;
317 rect.height = SASH_FULL_SIZE;
318 rect.width = w;
319
320 erase_rect.y = position;
321 erase_rect.x = 0;
322 erase_rect.height = SASH_FULL_SIZE;
323 erase_rect.width = w;
324 }
325
326 // we must erase everything first, otherwise the garbage from the old sash
327 // is left when dragging it
328 //
329 // TODO: is this the right way to draw themed background?
330 gtk_paint_flat_box
331 (
332 win->m_wxwindow->style,
333 GTK_PIZZA(win->m_wxwindow)->bin_window,
334 GTK_STATE_NORMAL,
335 GTK_SHADOW_NONE,
336 NULL,
337 win->m_wxwindow,
338 (char *)"base", // const_cast
339 erase_rect.x,
340 erase_rect.y,
341 erase_rect.width,
342 erase_rect.height
343 );
344
345 #ifdef __WXGTK20__
346 gtk_paint_handle
347 (
348 win->m_wxwindow->style,
349 GTK_PIZZA(win->m_wxwindow)->bin_window,
350 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
351 GTK_SHADOW_NONE,
352 NULL /* no clipping */,
353 win->m_wxwindow,
354 "paned",
355 rect.x,
356 rect.y,
357 rect.width,
358 rect.height,
359 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
360 );
361 #else // GTK+ 1.x
362
363 // leave some margin before sash itself
364 position += SASH_MARGIN / 2;
365
366 // and finally draw it using GTK paint functions
367 typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
368 GtkStateType,
369 GdkRectangle *, GtkWidget *,
370 gchar *,
371 gint, gint, gint);
372
373 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
374
375 (*func)
376 (
377 win->m_wxwindow->style,
378 GTK_PIZZA(win->m_wxwindow)->bin_window,
379 GTK_STATE_NORMAL,
380 NULL,
381 win->m_wxwindow,
382 (char *)"paned", // const_cast
383 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
384 );
385
386 gtk_paint_box
387 (
388 win->m_wxwindow->style,
389 GTK_PIZZA(win->m_wxwindow)->bin_window,
390 GTK_STATE_NORMAL,
391 GTK_SHADOW_OUT,
392 (GdkRectangle*) NULL,
393 win->m_wxwindow,
394 (char *)"paned", // const_cast
395 isVert ? position : size.x - 2*SASH_SIZE,
396 isVert ? size.y - 2*SASH_SIZE : position,
397 SASH_SIZE, SASH_SIZE
398 );
399 #endif // GTK+ 2.x/1.x
400 }
401