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