1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/renderer.cpp
3 // Purpose: implementation of wxRendererNative for wxGTK
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 20.07.2003
7 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22
23 #include "wx/renderer.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/window.h"
27 #include "wx/dc.h"
28 #endif
29
30 #include <gtk/gtk.h>
31 #include "wx/gtk1/win_gtk.h"
32 #include "wx/gtk1/dcclient.h"
33
34 // RR: After a correction to the orientation of the sash
35 // this doesn't seem to be required anymore and it
36 // seems to confuse some themes so USE_ERASE_RECT=0
37 #define USE_ERASE_RECT 0
38
39 // ----------------------------------------------------------------------------
40 // wxRendererGTK: our wxRendererNative implementation
41 // ----------------------------------------------------------------------------
42
43 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
44 {
45 public:
46 // draw the header control button (used by wxListCtrl)
47 virtual int DrawHeaderButton(wxWindow *win,
48 wxDC& dc,
49 const wxRect& rect,
50 int flags = 0,
51 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
52 wxHeaderButtonParams* params=NULL);
53
54 virtual void DrawSplitterBorder(wxWindow *win,
55 wxDC& dc,
56 const wxRect& rect,
57 int flags = 0);
58 virtual void DrawSplitterSash(wxWindow *win,
59 wxDC& dc,
60 const wxSize& size,
61 wxCoord position,
62 wxOrientation orient,
63 int flags = 0);
64
65 virtual void DrawComboBoxDropButton(wxWindow *win,
66 wxDC& dc,
67 const wxRect& rect,
68 int flags = 0);
69
70 virtual void DrawDropArrow(wxWindow *win,
71 wxDC& dc,
72 const wxRect& rect,
73 int flags = 0);
74
75 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
76
77 private:
78 // FIXME: shouldn't we destroy these windows somewhere?
79
80 // used by DrawHeaderButton and DrawComboBoxDropButton
81 static GtkWidget *GetButtonWidget();
82 };
83
84 // ============================================================================
85 // implementation
86 // ============================================================================
87
88 /* static */
GetDefault()89 wxRendererNative& wxRendererNative::GetDefault()
90 {
91 static wxRendererGTK s_rendererGTK;
92
93 return s_rendererGTK;
94 }
95
96 // ----------------------------------------------------------------------------
97 // helper functions
98 // ----------------------------------------------------------------------------
99
100 GtkWidget *
GetButtonWidget()101 wxRendererGTK::GetButtonWidget()
102 {
103 static GtkWidget *s_button = NULL;
104 static GtkWidget *s_window = NULL;
105
106 if ( !s_button )
107 {
108 s_window = gtk_window_new( GTK_WINDOW_POPUP );
109 gtk_widget_realize( s_window );
110 s_button = gtk_button_new();
111 gtk_container_add( GTK_CONTAINER(s_window), s_button );
112 gtk_widget_realize( s_button );
113 }
114
115 return s_button;
116 }
117
118 // ----------------------------------------------------------------------------
119 // list/tree controls drawing
120 // ----------------------------------------------------------------------------
121
122 int
DrawHeaderButton(wxWindow * win,wxDC & dc,const wxRect & rect,int flags,wxHeaderSortIconType WXUNUSED (sortArrow),wxHeaderButtonParams * WXUNUSED (params))123 wxRendererGTK::DrawHeaderButton(wxWindow *win,
124 wxDC& dc,
125 const wxRect& rect,
126 int flags,
127 wxHeaderSortIconType WXUNUSED(sortArrow),
128 wxHeaderButtonParams* WXUNUSED(params))
129 {
130
131 GtkWidget *button = GetButtonWidget();
132
133 gtk_paint_box
134 (
135 button->style,
136 // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC.
137 // Maybe use code similar as in DrawComboBoxDropButton below?
138 GTK_PIZZA(win->m_wxwindow)->bin_window,
139 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
140 GTK_SHADOW_OUT,
141 NULL,
142 button,
143 "button",
144 dc.LogicalToDeviceX(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
145 );
146
147 return rect.width + 2;
148 }
149
150 // ----------------------------------------------------------------------------
151 // splitter sash drawing
152 // ----------------------------------------------------------------------------
153
154 // the full sash width (should be even)
155 static const wxCoord SASH_SIZE = 8;
156
157 // margin around the sash
158 static const wxCoord SASH_MARGIN = 2;
159
GetGtkSplitterFullSize()160 static int GetGtkSplitterFullSize()
161 {
162 return SASH_SIZE + SASH_MARGIN;
163 }
164
165 wxSplitterRenderParams
GetSplitterParams(const wxWindow * WXUNUSED (win))166 wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
167 {
168 // we don't draw any border, hence 0 for the second field
169 return wxSplitterRenderParams
170 (
171 GetGtkSplitterFullSize(),
172 0,
173 false // not
174 );
175 }
176
177 void
DrawSplitterBorder(wxWindow * WXUNUSED (win),wxDC & WXUNUSED (dc),const wxRect & WXUNUSED (rect),int WXUNUSED (flags))178 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
179 wxDC& WXUNUSED(dc),
180 const wxRect& WXUNUSED(rect),
181 int WXUNUSED(flags))
182 {
183 // nothing to do
184 }
185
186 void
DrawSplitterSash(wxWindow * win,wxDC & WXUNUSED (dc),const wxSize & size,wxCoord position,wxOrientation orient,int WXUNUSED (flags))187 wxRendererGTK::DrawSplitterSash(wxWindow *win,
188 wxDC& WXUNUSED(dc),
189 const wxSize& size,
190 wxCoord position,
191 wxOrientation orient,
192 int WXUNUSED(flags))
193 {
194 if ( !win->m_wxwindow->window )
195 {
196 // window not realized yet
197 return;
198 }
199
200 wxCoord full_size = GetGtkSplitterFullSize();
201
202 // are we drawing vertical or horizontal splitter?
203 const bool isVert = orient == wxVERTICAL;
204
205 GdkRectangle rect;
206 #if USE_ERASE_RECT
207 GdkRectangle erase_rect;
208 #endif
209
210 if ( isVert )
211 {
212 int h = win->GetClientSize().GetHeight();
213
214 rect.x = position;
215 rect.y = 0;
216 rect.width = full_size;
217 rect.height = h;
218
219 #if USE_ERASE_RECT
220 erase_rect.x = position;
221 erase_rect.y = 0;
222 erase_rect.width = full_size;
223 erase_rect.height = h;
224 #endif
225 }
226 else // horz
227 {
228 int w = win->GetClientSize().GetWidth();
229
230 rect.x = 0;
231 rect.y = position;
232 rect.height = full_size;
233 rect.width = w;
234
235 #if USE_ERASE_RECT
236 erase_rect.y = position;
237 erase_rect.x = 0;
238 erase_rect.height = full_size;
239 erase_rect.width = w;
240 #endif
241 }
242
243 #if USE_ERASE_RECT
244 // we must erase everything first, otherwise the garbage
245 // from the old sash is left when dragging it
246 gtk_paint_flat_box
247 (
248 win->m_wxwindow->style,
249 GTK_PIZZA(win->m_wxwindow)->bin_window,
250 GTK_STATE_NORMAL,
251 GTK_SHADOW_NONE,
252 NULL,
253 win->m_wxwindow,
254 (char *)"viewportbin", // const_cast
255 erase_rect.x,
256 erase_rect.y,
257 erase_rect.width,
258 erase_rect.height
259 );
260 #endif
261
262
263 // leave some margin before sash itself
264 position += SASH_MARGIN / 2;
265
266 // and finally draw it using GTK paint functions
267 typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
268 GtkStateType,
269 GdkRectangle *, GtkWidget *,
270 gchar *,
271 gint, gint, gint);
272
273 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
274
275 (*func)
276 (
277 win->m_wxwindow->style,
278 GTK_PIZZA(win->m_wxwindow)->bin_window,
279 GTK_STATE_NORMAL,
280 NULL,
281 win->m_wxwindow,
282 (char *)"paned", // const_cast
283 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
284 );
285
286 gtk_paint_box
287 (
288 win->m_wxwindow->style,
289 GTK_PIZZA(win->m_wxwindow)->bin_window,
290 GTK_STATE_NORMAL,
291 GTK_SHADOW_OUT,
292 NULL,
293 win->m_wxwindow,
294 (char *)"paned", // const_cast
295 isVert ? position : size.x - 2*SASH_SIZE,
296 isVert ? size.y - 2*SASH_SIZE : position,
297 SASH_SIZE, SASH_SIZE
298 );
299 }
300
301 void
DrawDropArrow(wxWindow * WXUNUSED (win),wxDC & dc,const wxRect & rect,int flags)302 wxRendererGTK::DrawDropArrow(wxWindow *WXUNUSED(win),
303 wxDC& dc,
304 const wxRect& rect,
305 int flags)
306 {
307 GtkWidget *button = GetButtonWidget();
308
309 // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
310 // a window for gtk_paint_xxx function, then it won't
311 // work for wxMemoryDC. So that is why we assume wxDC
312 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
313 // are derived from it) and use its m_window.
314 wxWindowDCImpl * const impl = wxDynamicCast(dc.GetImpl(), wxWindowDCImpl);
315 wxCHECK_RET( impl, "must have a window DC" );
316
317 GdkWindow* gdk_window = impl->GetGDKWindow();
318
319 // draw arrow so that there is even space horizontally
320 // on both sides
321 int arrowX = rect.width/4 + 1;
322 int arrowWidth = rect.width - (arrowX*2);
323
324 // scale arrow's height accoording to the width
325 int arrowHeight = rect.width/3;
326 int arrowY = (rect.height-arrowHeight)/2 +
327 ((rect.height-arrowHeight) & 1);
328
329 GtkStateType state;
330
331 if ( flags & wxCONTROL_PRESSED )
332 state = GTK_STATE_ACTIVE;
333 else if ( flags & wxCONTROL_DISABLED )
334 state = GTK_STATE_INSENSITIVE;
335 else if ( flags & wxCONTROL_CURRENT )
336 state = GTK_STATE_PRELIGHT;
337 else
338 state = GTK_STATE_NORMAL;
339
340 // draw arrow on button
341 gtk_paint_arrow
342 (
343 button->style,
344 gdk_window,
345 state,
346 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
347 NULL,
348 button,
349 "arrow",
350 GTK_ARROW_DOWN,
351 FALSE,
352 rect.x + arrowX,
353 rect.y + arrowY,
354 arrowWidth,
355 arrowHeight
356 );
357 }
358
359 void
DrawComboBoxDropButton(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)360 wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
361 wxDC& dc,
362 const wxRect& rect,
363 int flags)
364 {
365 GtkWidget *button = GetButtonWidget();
366
367 // for reason why we do this, see DrawDropArrow
368 wxWindowDCImpl * const impl = wxDynamicCast(dc.GetImpl(), wxWindowDCImpl);
369 wxCHECK_RET( impl, "must have a window DC" );
370
371 GdkWindow* gdk_window = impl->GetGDKWindow();
372
373 // draw button
374 GtkStateType state;
375
376 if ( flags & wxCONTROL_PRESSED )
377 state = GTK_STATE_ACTIVE;
378 else if ( flags & wxCONTROL_DISABLED )
379 state = GTK_STATE_INSENSITIVE;
380 else if ( flags & wxCONTROL_CURRENT )
381 state = GTK_STATE_PRELIGHT;
382 else
383 state = GTK_STATE_NORMAL;
384
385 gtk_paint_box
386 (
387 button->style,
388 gdk_window,
389 state,
390 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
391 NULL,
392 button,
393 "button",
394 rect.x, rect.y, rect.width, rect.height
395 );
396
397 // draw arrow on button
398 DrawDropArrow(win,dc,rect,flags);
399
400 }
401