]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/renderer.cpp
Committed Jaako's renderer patch
[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 #include "wx/dcclient.h"
34 #include "wx/settings.h"
35
36 // RR: After a correction to the orientation of the sash
37 // this doesn't seem to be required anymore and it
38 // seems to confuse some themes so USE_ERASE_RECT=0
39 #define USE_ERASE_RECT 0
40
41 // ----------------------------------------------------------------------------
42 // wxRendererGTK: our wxRendererNative implementation
43 // ----------------------------------------------------------------------------
44
45 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
46 {
47 public:
48 // draw the header control button (used by wxListCtrl)
49 virtual void DrawHeaderButton(wxWindow *win,
50 wxDC& dc,
51 const wxRect& rect,
52 int flags = 0);
53
54 // draw the expanded/collapsed icon for a tree control item
55 virtual void DrawTreeItemButton(wxWindow *win,
56 wxDC& dc,
57 const wxRect& rect,
58 int flags = 0);
59
60 virtual void DrawSplitterBorder(wxWindow *win,
61 wxDC& dc,
62 const wxRect& rect,
63 int flags = 0);
64 virtual void DrawSplitterSash(wxWindow *win,
65 wxDC& dc,
66 const wxSize& size,
67 wxCoord position,
68 wxOrientation orient,
69 int flags = 0);
70
71 virtual void DrawComboBoxDropButton(wxWindow *win,
72 wxDC& dc,
73 const wxRect& rect,
74 int flags = 0);
75
76 virtual void DrawDropArrow(wxWindow *win,
77 wxDC& dc,
78 const wxRect& rect,
79 int flags = 0);
80
81 virtual void DrawCheckButton(wxWindow *win,
82 wxDC& dc,
83 const wxRect& rect,
84 int flags = 0);
85
86 virtual void DrawPushButton(wxWindow *win,
87 wxDC& dc,
88 const wxRect& rect,
89 int flags = 0);
90
91 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
92
93 private:
94 // FIXME: shouldn't we destroy these windows somewhere?
95
96 // used by DrawHeaderButton and DrawPushButton
97 static GtkWidget *GetButtonWidget();
98
99 // used by DrawTreeItemButton()
100 static GtkWidget *GetTreeWidget();
101
102 // used by DrawCheckButton()
103 static GtkWidget *GetCheckButtonWidget();
104 };
105
106 // ============================================================================
107 // implementation
108 // ============================================================================
109
110 /* static */
111 wxRendererNative& wxRendererNative::GetDefault()
112 {
113 static wxRendererGTK s_rendererGTK;
114
115 return s_rendererGTK;
116 }
117
118 // ----------------------------------------------------------------------------
119 // helper functions
120 // ----------------------------------------------------------------------------
121
122 GtkWidget *
123 wxRendererGTK::GetButtonWidget()
124 {
125 static GtkWidget *s_button = NULL;
126 static GtkWidget *s_window = NULL;
127
128 if ( !s_button )
129 {
130 s_window = gtk_window_new( GTK_WINDOW_POPUP );
131 gtk_widget_realize( s_window );
132 s_button = gtk_button_new();
133 gtk_container_add( GTK_CONTAINER(s_window), s_button );
134 gtk_widget_realize( s_button );
135 }
136
137 return s_button;
138 }
139
140 GtkWidget *
141 wxRendererGTK::GetCheckButtonWidget()
142 {
143 static GtkWidget *s_button = NULL;
144 static GtkWidget *s_window = NULL;
145
146 if ( !s_button )
147 {
148 s_window = gtk_window_new( GTK_WINDOW_POPUP );
149 gtk_widget_realize( s_window );
150 s_button = gtk_check_button_new();
151 gtk_container_add( GTK_CONTAINER(s_window), s_button );
152 gtk_widget_realize( s_button );
153 }
154
155 return s_button;
156 }
157
158 GtkWidget *
159 wxRendererGTK::GetTreeWidget()
160 {
161 static GtkWidget *s_tree = NULL;
162 static GtkWidget *s_window = NULL;
163
164 if ( !s_tree )
165 {
166 s_tree = gtk_tree_view_new();
167 s_window = gtk_window_new( GTK_WINDOW_POPUP );
168 gtk_widget_realize( s_window );
169 gtk_container_add( GTK_CONTAINER(s_window), s_tree );
170 gtk_widget_realize( s_tree );
171 }
172
173 return s_tree;
174 }
175
176 // ----------------------------------------------------------------------------
177 // list/tree controls drawing
178 // ----------------------------------------------------------------------------
179
180 void
181 wxRendererGTK::DrawHeaderButton(wxWindow *win,
182 wxDC& dc,
183 const wxRect& rect,
184 int flags)
185 {
186
187 GtkWidget *button = GetButtonWidget();
188
189 gtk_paint_box
190 (
191 button->style,
192 // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC.
193 // Maybe use code similar as in DrawPushButton below?
194 GTK_PIZZA(win->m_wxwindow)->bin_window,
195 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
196 GTK_SHADOW_OUT,
197 NULL,
198 button,
199 "button",
200 dc.XLOG2DEV(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
201 );
202 }
203
204 // draw a ">" or "v" button
205 void
206 wxRendererGTK::DrawTreeItemButton(wxWindow* win,
207 wxDC& dc, const wxRect& rect, int flags)
208 {
209 GtkWidget *tree = GetTreeWidget();
210
211 GtkStateType state;
212 if ( flags & wxCONTROL_CURRENT )
213 state = GTK_STATE_PRELIGHT;
214 else
215 state = GTK_STATE_NORMAL;
216
217 // VZ: I don't know how to get the size of the expander so as to centre it
218 // in the given rectangle, +2/3 below is just what looks good here...
219 gtk_paint_expander
220 (
221 tree->style,
222 GTK_PIZZA(win->m_wxwindow)->bin_window,
223 state,
224 NULL,
225 tree,
226 "treeview",
227 dc.LogicalToDeviceX(rect.x) + 2,
228 dc.LogicalToDeviceY(rect.y) + 3,
229 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
230 : GTK_EXPANDER_COLLAPSED
231 );
232 }
233
234
235 // ----------------------------------------------------------------------------
236 // splitter sash drawing
237 // ----------------------------------------------------------------------------
238
239 static int GetGtkSplitterFullSize()
240 {
241 static GtkWidget *s_paned = NULL;
242 if (s_paned == NULL)
243 s_paned = gtk_vpaned_new();
244
245 gint handle_size;
246 gtk_widget_style_get (s_paned, "handle_size", &handle_size, NULL);
247
248 return handle_size;
249 }
250
251 wxSplitterRenderParams
252 wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
253 {
254 // we don't draw any border, hence 0 for the second field
255 return wxSplitterRenderParams
256 (
257 GetGtkSplitterFullSize(),
258 0,
259 true // hot sensitive
260 );
261 }
262
263 void
264 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
265 wxDC& WXUNUSED(dc),
266 const wxRect& WXUNUSED(rect),
267 int WXUNUSED(flags))
268 {
269 // nothing to do
270 }
271
272 void
273 wxRendererGTK::DrawSplitterSash(wxWindow *win,
274 wxDC& dc,
275 const wxSize& size,
276 wxCoord position,
277 wxOrientation orient,
278 int flags)
279 {
280 if ( !win->m_wxwindow->window )
281 {
282 // window not realized yet
283 return;
284 }
285
286 wxCoord full_size = GetGtkSplitterFullSize();
287
288 // are we drawing vertical or horizontal splitter?
289 const bool isVert = orient == wxVERTICAL;
290
291 GdkRectangle rect;
292 #if USE_ERASE_RECT
293 GdkRectangle erase_rect;
294 #endif
295
296 if ( isVert )
297 {
298 int h = win->GetClientSize().GetHeight();
299
300 rect.x = position;
301 rect.y = 0;
302 rect.width = full_size;
303 rect.height = h;
304
305 #if USE_ERASE_RECT
306 erase_rect.x = position;
307 erase_rect.y = 0;
308 erase_rect.width = full_size;
309 erase_rect.height = h;
310 #endif
311 }
312 else // horz
313 {
314 int w = win->GetClientSize().GetWidth();
315
316 rect.x = 0;
317 rect.y = position;
318 rect.height = full_size;
319 rect.width = w;
320
321 #if USE_ERASE_RECT
322 erase_rect.y = position;
323 erase_rect.x = 0;
324 erase_rect.height = full_size;
325 erase_rect.width = w;
326 #endif
327 }
328
329 #if USE_ERASE_RECT
330 // we must erase everything first, otherwise the garbage
331 // from the old sash is left when dragging it
332 gtk_paint_flat_box
333 (
334 win->m_wxwindow->style,
335 GTK_PIZZA(win->m_wxwindow)->bin_window,
336 GTK_STATE_NORMAL,
337 GTK_SHADOW_NONE,
338 NULL,
339 win->m_wxwindow,
340 (char *)"viewportbin", // const_cast
341 erase_rect.x,
342 erase_rect.y,
343 erase_rect.width,
344 erase_rect.height
345 );
346 #endif
347
348 gtk_paint_handle
349 (
350 win->m_wxwindow->style,
351 GTK_PIZZA(win->m_wxwindow)->bin_window,
352 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
353 GTK_SHADOW_NONE,
354 NULL /* no clipping */,
355 win->m_wxwindow,
356 "paned",
357 rect.x,
358 rect.y,
359 rect.width,
360 rect.height,
361 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
362 );
363 }
364
365 void
366 wxRendererGTK::DrawDropArrow(wxWindow *win,
367 wxDC& dc,
368 const wxRect& rect,
369 int flags)
370 {
371 GtkWidget *button = GetButtonWidget();
372
373 // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
374 // a window for gtk_paint_xxx function, then it won't
375 // work for wxMemoryDC. So that is why we assume wxDC
376 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
377 // are derived from it) and use its m_window.
378 wxWindowDC& wdc = (wxWindowDC&)dc;
379
380 // only doing debug-time checking here (it should
381 // probably be enough)
382 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
383
384 // draw arrow so that there is even space horizontally
385 // on both sides
386 int arrowX = rect.width/4 + 1;
387 int arrowWidth = rect.width - (arrowX*2);
388
389 // scale arrow's height accoording to the width
390 int arrowHeight = rect.width/3;
391 int arrowY = (rect.height-arrowHeight)/2 +
392 ((rect.height-arrowHeight) & 1);
393
394 GtkStateType state;
395
396 if ( flags & wxCONTROL_PRESSED )
397 state = GTK_STATE_ACTIVE;
398 else if ( flags & wxCONTROL_DISABLED )
399 state = GTK_STATE_INSENSITIVE;
400 else if ( flags & wxCONTROL_CURRENT )
401 state = GTK_STATE_PRELIGHT;
402 else
403 state = GTK_STATE_NORMAL;
404
405 // draw arrow on button
406 gtk_paint_arrow
407 (
408 button->style,
409 wdc.m_window,
410 state,
411 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
412 NULL,
413 button,
414 "arrow",
415 GTK_ARROW_DOWN,
416 FALSE,
417 rect.x + arrowX,
418 rect.y + arrowY,
419 arrowWidth,
420 arrowHeight
421 );
422 }
423
424 void
425 wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
426 wxDC& dc,
427 const wxRect& rect,
428 int flags)
429 {
430 DrawPushButton(win,dc,rect,flags);
431 DrawDropArrow(win,dc,rect);
432 }
433
434 void
435 wxRendererGTK::DrawCheckButton(wxWindow *win,
436 wxDC& dc,
437 const wxRect& rect,
438 int flags )
439 {
440 GtkWidget *button = GetCheckButtonWidget();
441
442 // for reason why we do this, see DrawDropArrow
443 wxWindowDC& wdc = (wxWindowDC&)dc;
444 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
445
446 GtkStateType state;
447
448 if ( flags & wxCONTROL_PRESSED )
449 state = GTK_STATE_ACTIVE;
450 else if ( flags & wxCONTROL_DISABLED )
451 state = GTK_STATE_INSENSITIVE;
452 else if ( flags & wxCONTROL_CURRENT )
453 state = GTK_STATE_PRELIGHT;
454 else
455 state = GTK_STATE_NORMAL;
456
457 gtk_paint_check
458 (
459 button->style,
460 wdc.m_window,
461 state,
462 flags & wxCONTROL_CHECKED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
463 NULL,
464 button,
465 "cellcheck",
466 rect.x, rect.y, 13, 13
467 );
468 }
469
470 void
471 wxRendererGTK::DrawPushButton(wxWindow *win,
472 wxDC& dc,
473 const wxRect& rect,
474 int flags)
475 {
476 GtkWidget *button = GetButtonWidget();
477
478 // for reason why we do this, see DrawDropArrow
479 wxWindowDC& wdc = (wxWindowDC&)dc;
480 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
481
482 // draw button
483 GtkStateType state;
484
485 if ( flags & wxCONTROL_PRESSED )
486 state = GTK_STATE_ACTIVE;
487 else if ( flags & wxCONTROL_DISABLED )
488 state = GTK_STATE_INSENSITIVE;
489 else if ( flags & wxCONTROL_CURRENT )
490 state = GTK_STATE_PRELIGHT;
491 else
492 state = GTK_STATE_NORMAL;
493
494 gtk_paint_box
495 (
496 button->style,
497 wdc.m_window,
498 state,
499 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
500 NULL,
501 button,
502 "button",
503 rect.x, rect.y, rect.width, rect.height
504 );
505 }