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