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