more tweaks to drop down arrow drawing (Andreas Pflug)
[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 void DrawComboBoxDropButton(wxWindow *win,
77 wxDC& dc,
78 const wxRect& rect,
79 int flags = 0);
80
81 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
82 };
83
84 // ============================================================================
85 // implementation
86 // ============================================================================
87
88 /* static */
89 wxRendererNative& wxRendererNative::GetDefault()
90 {
91 static wxRendererGTK s_rendererGTK;
92
93 return s_rendererGTK;
94 }
95
96 // ----------------------------------------------------------------------------
97 // list/tree controls drawing
98 // ----------------------------------------------------------------------------
99
100 void
101 wxRendererGTK::DrawHeaderButton(wxWindow *win,
102 wxDC& dc,
103 const wxRect& rect,
104 int flags)
105 {
106
107 static GtkWidget *s_button = NULL;
108 static GtkWidget *s_window = NULL;
109 if (s_button == NULL)
110 {
111 s_window = gtk_window_new( GTK_WINDOW_POPUP );
112 gtk_widget_realize( s_window );
113 s_button = gtk_button_new();
114 gtk_container_add( GTK_CONTAINER(s_window), s_button );
115 gtk_widget_realize( s_button );
116 }
117
118 gtk_paint_box
119 (
120 s_button->style,
121 GTK_PIZZA(win->m_wxwindow)->bin_window,
122 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
123 GTK_SHADOW_OUT,
124 NULL,
125 s_button,
126 "button",
127 dc.XLOG2DEV(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
128 );
129 }
130
131 #ifdef __WXGTK20__
132
133 // draw a ">" or "v" button
134 //
135 // TODO: replace the code below with gtk_paint_expander()
136 void
137 wxRendererGTK::DrawTreeItemButton(wxWindow* win,
138 wxDC& dc, const wxRect& rect, int flags)
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 // This draws the GTK+ 2.2.4 triangle
150 x--;
151 GdkPoint points[3];
152
153 if ( flags & wxCONTROL_EXPANDED )
154 {
155 points[0].x = x;
156 points[0].y = y + (PM_SIZE + 2) / 6;
157 points[1].x = points[0].x + (PM_SIZE + 2);
158 points[1].y = points[0].y;
159 points[2].x = (points[0].x + (PM_SIZE + 2) / 2);
160 points[2].y = y + 2 * (PM_SIZE + 2) / 3;
161 }
162 else
163 {
164 points[0].x = x + ((PM_SIZE + 2) / 6 + 2);
165 points[0].y = y - 1;
166 points[1].x = points[0].x;
167 points[1].y = points[0].y + (PM_SIZE + 2);
168 points[2].x = (points[0].x +
169 (2 * (PM_SIZE + 2) / 3 - 1));
170 points[2].y = points[0].y + (PM_SIZE + 2) / 2;
171 }
172
173 if ( flags & wxCONTROL_CURRENT )
174 gdk_draw_polygon( pizza->bin_window, style->fg_gc[GTK_STATE_PRELIGHT], TRUE, points, 3);
175 else
176 gdk_draw_polygon( pizza->bin_window, style->base_gc[GTK_STATE_NORMAL], TRUE, points, 3);
177 gdk_draw_polygon( pizza->bin_window, style->fg_gc[GTK_STATE_NORMAL], FALSE, points, 3 );
178 }
179
180 #endif // GTK 2.0
181
182 // ----------------------------------------------------------------------------
183 // splitter sash drawing
184 // ----------------------------------------------------------------------------
185
186 // all this should probably be read from the current theme settings somehow?
187 #ifdef __WXGTK20__
188 // the full sash size
189 static const wxCoord SASH_FULL_SIZE = 5;
190 #else // GTK+ 1.x
191 // the full sash width (should be even)
192 static const wxCoord SASH_SIZE = 8;
193
194 // margin around the sash
195 static const wxCoord SASH_MARGIN = 2;
196
197 // the full sash size
198 static const wxCoord SASH_FULL_SIZE = SASH_SIZE + SASH_MARGIN;
199 #endif // GTK+ 2.x/1.x
200
201 wxSplitterRenderParams
202 wxRendererGTK::GetSplitterParams(const wxWindow * WXUNUSED(win))
203 {
204 // we don't draw any border, hence 0 for the second field
205 return wxSplitterRenderParams
206 (
207 SASH_FULL_SIZE,
208 0,
209 #ifdef __WXGTK20__
210 true // hot sensitive
211 #else // GTK+ 1.x
212 false // not
213 #endif // GTK+ 2.x/1.x
214 );
215 }
216
217 void
218 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
219 wxDC& WXUNUSED(dc),
220 const wxRect& WXUNUSED(rect),
221 int WXUNUSED(flags))
222 {
223 // nothing to do
224 }
225
226 void
227 wxRendererGTK::DrawSplitterSash(wxWindow *win,
228 wxDC& dc,
229 const wxSize& size,
230 wxCoord position,
231 wxOrientation orient,
232 int WXUNUSED_IN_GTK1(flags))
233 {
234 if ( !win->m_wxwindow->window )
235 {
236 // window not realized yet
237 return;
238 }
239
240 // are we drawing vertical or horizontal splitter?
241 const bool isVert = orient == wxVERTICAL;
242
243 GdkRectangle rect;
244 GdkRectangle erase_rect;
245 if ( isVert )
246 {
247 int h = win->GetClientSize().GetHeight();
248
249 rect.x = position;
250 rect.y = 0;
251 rect.width = SASH_FULL_SIZE;
252 rect.height = h;
253
254 erase_rect.x = position;
255 erase_rect.y = 0;
256 erase_rect.width = SASH_FULL_SIZE;
257 erase_rect.height = h;
258 }
259 else // horz
260 {
261 int w = win->GetClientSize().GetWidth();
262
263 rect.x = 0;
264 rect.y = position;
265 rect.height = SASH_FULL_SIZE;
266 rect.width = w;
267
268 erase_rect.y = position;
269 erase_rect.x = 0;
270 erase_rect.height = SASH_FULL_SIZE;
271 erase_rect.width = w;
272 }
273
274 // we must erase everything first, otherwise the garbage from the old sash
275 // is left when dragging it
276 //
277 // TODO: is this the right way to draw themed background?
278 gtk_paint_flat_box
279 (
280 win->m_wxwindow->style,
281 GTK_PIZZA(win->m_wxwindow)->bin_window,
282 GTK_STATE_NORMAL,
283 GTK_SHADOW_NONE,
284 NULL,
285 win->m_wxwindow,
286 (char *)"base", // const_cast
287 erase_rect.x,
288 erase_rect.y,
289 erase_rect.width,
290 erase_rect.height
291 );
292
293 #ifdef __WXGTK20__
294 gtk_paint_handle
295 (
296 win->m_wxwindow->style,
297 GTK_PIZZA(win->m_wxwindow)->bin_window,
298 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
299 GTK_SHADOW_NONE,
300 NULL /* no clipping */,
301 win->m_wxwindow,
302 "paned",
303 rect.x,
304 rect.y,
305 rect.width,
306 rect.height,
307 !isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
308 );
309 #else // GTK+ 1.x
310
311 // leave some margin before sash itself
312 position += SASH_MARGIN / 2;
313
314 // and finally draw it using GTK paint functions
315 typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
316 GtkStateType,
317 GdkRectangle *, GtkWidget *,
318 gchar *,
319 gint, gint, gint);
320
321 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
322
323 (*func)
324 (
325 win->m_wxwindow->style,
326 GTK_PIZZA(win->m_wxwindow)->bin_window,
327 GTK_STATE_NORMAL,
328 NULL,
329 win->m_wxwindow,
330 (char *)"paned", // const_cast
331 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
332 );
333
334 gtk_paint_box
335 (
336 win->m_wxwindow->style,
337 GTK_PIZZA(win->m_wxwindow)->bin_window,
338 GTK_STATE_NORMAL,
339 GTK_SHADOW_OUT,
340 (GdkRectangle*) NULL,
341 win->m_wxwindow,
342 (char *)"paned", // const_cast
343 isVert ? position : size.x - 2*SASH_SIZE,
344 isVert ? size.y - 2*SASH_SIZE : position,
345 SASH_SIZE, SASH_SIZE
346 );
347 #endif // GTK+ 2.x/1.x
348 }
349
350 void wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
351 wxDC& dc,
352 const wxRect& rect,
353 int flags)
354 {
355 dc.SetBrush(wxBrush(win->GetBackgroundColour()));
356 dc.SetPen(wxPen(win->GetBackgroundColour()));
357 dc.DrawRectangle(rect);
358
359 int x = (rect.GetWidth()-9) / 2;
360 int y = (rect.GetHeight()-10) / 2;
361
362 wxPoint pt[] =
363 {
364 wxPoint(x+2, y+3),
365 wxPoint(x+6, y+3),
366 wxPoint(x+6, y+6),
367 wxPoint(x+8, y+6),
368 wxPoint(x+4, y+10),
369 wxPoint(x+0, y+6),
370 wxPoint(x+2, y+6)
371 };
372 dc.SetBrush(wxBrush(win->GetForegroundColour()));
373 dc.SetPen(wxPen(win->GetForegroundColour()));
374 dc.DrawLine(x, y, x+9, y);
375 dc.DrawPolygon(WXSIZEOF(pt), pt, rect.x, rect.y);
376 }
377