]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/renderer.cpp
added refcounting to wxCharBuffer to fix passing of wxCharBuffer to printf-like functions
[wxWidgets.git] / src / gtk / renderer.cpp
... / ...
CommitLineData
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 #include "wx/module.h"
34#endif
35
36#include "wx/gtk/dc.h"
37#include "wx/gtk/private.h"
38
39#include <gtk/gtk.h>
40
41// ----------------------------------------------------------------------------
42// wxRendererGTK: our wxRendererNative implementation
43// ----------------------------------------------------------------------------
44
45class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
46{
47public:
48 // draw the header control button (used by wxListCtrl)
49 virtual int DrawHeaderButton(wxWindow *win,
50 wxDC& dc,
51 const wxRect& rect,
52 int flags = 0,
53 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
54 wxHeaderButtonParams* params = NULL);
55
56 // draw the expanded/collapsed icon for a tree control item
57 virtual void DrawTreeItemButton(wxWindow *win,
58 wxDC& dc,
59 const wxRect& rect,
60 int flags = 0);
61
62 virtual void DrawSplitterBorder(wxWindow *win,
63 wxDC& dc,
64 const wxRect& rect,
65 int flags = 0);
66 virtual void DrawSplitterSash(wxWindow *win,
67 wxDC& dc,
68 const wxSize& size,
69 wxCoord position,
70 wxOrientation orient,
71 int flags = 0);
72
73 virtual void DrawComboBoxDropButton(wxWindow *win,
74 wxDC& dc,
75 const wxRect& rect,
76 int flags = 0);
77
78 virtual void DrawDropArrow(wxWindow *win,
79 wxDC& dc,
80 const wxRect& rect,
81 int flags = 0);
82
83 virtual void DrawCheckBox(wxWindow *win,
84 wxDC& dc,
85 const wxRect& rect,
86 int flags = 0);
87
88 virtual void DrawPushButton(wxWindow *win,
89 wxDC& dc,
90 const wxRect& rect,
91 int flags = 0);
92
93 virtual void DrawItemSelectionRect(wxWindow *win,
94 wxDC& dc,
95 const wxRect& rect,
96 int flags = 0);
97
98 virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
99
100 virtual wxSize GetCheckBoxSize(wxWindow *win);
101
102 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
103};
104
105// ============================================================================
106// implementation
107// ============================================================================
108
109/* static */
110wxRendererNative& wxRendererNative::GetDefault()
111{
112 static wxRendererGTK s_rendererGTK;
113
114 return s_rendererGTK;
115}
116
117// ----------------------------------------------------------------------------
118// list/tree controls drawing
119// ----------------------------------------------------------------------------
120
121int
122wxRendererGTK::DrawHeaderButton(wxWindow *win,
123 wxDC& dc,
124 const wxRect& rect,
125 int flags,
126 wxHeaderSortIconType sortArrow,
127 wxHeaderButtonParams* params)
128{
129
130 GtkWidget *button = wxGTKPrivate::GetHeaderButtonWidget();
131
132 GdkWindow* gdk_window = NULL;
133#if wxUSE_NEW_DC
134 wxDCImpl *impl = dc.GetImpl();
135 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
136 if (gtk_impl)
137 gdk_window = gtk_impl->GetGDKWindow();
138#else
139 gdk_window = dc.GetGDKWindow();
140#endif
141 wxASSERT_MSG( gdk_window,
142 wxT("cannot use wxRendererNative on wxDC of this type") );
143
144 int x_diff = 0;
145 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
146 x_diff = rect.width;
147
148 GtkStateType state = GTK_STATE_NORMAL;
149 if (flags & wxCONTROL_DISABLED)
150 state = GTK_STATE_INSENSITIVE;
151 else
152 {
153 if (flags & wxCONTROL_CURRENT)
154 state = GTK_STATE_PRELIGHT;
155 }
156
157 gtk_paint_box
158 (
159 button->style,
160 gdk_window,
161 state,
162 GTK_SHADOW_OUT,
163 NULL,
164 button,
165 "button",
166 dc.LogicalToDeviceX(rect.x) - x_diff, rect.y, rect.width, rect.height
167 );
168
169 return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
170}
171
172// draw a ">" or "v" button
173void
174wxRendererGTK::DrawTreeItemButton(wxWindow* win,
175 wxDC& dc, const wxRect& rect, int flags)
176{
177 GtkWidget *tree = wxGTKPrivate::GetTreeWidget();
178
179 GdkWindow* gdk_window = NULL;
180#if wxUSE_NEW_DC
181 wxDCImpl *impl = dc.GetImpl();
182 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
183 if (gtk_impl)
184 gdk_window = gtk_impl->GetGDKWindow();
185#else
186 gdk_window = dc.GetGDKWindow();
187#endif
188 wxASSERT_MSG( gdk_window,
189 wxT("cannot use wxRendererNative on wxDC of this type") );
190
191 GtkStateType state;
192 if ( flags & wxCONTROL_CURRENT )
193 state = GTK_STATE_PRELIGHT;
194 else
195 state = GTK_STATE_NORMAL;
196
197 int x_diff = 0;
198 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
199 x_diff = rect.width;
200
201 // VZ: I don't know how to get the size of the expander so as to centre it
202 // in the given rectangle, +2/3 below is just what looks good here...
203 gtk_paint_expander
204 (
205 tree->style,
206 gdk_window,
207 state,
208 NULL,
209 tree,
210 "treeview",
211 dc.LogicalToDeviceX(rect.x) + 6 - x_diff,
212 dc.LogicalToDeviceY(rect.y) + 3,
213 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
214 : GTK_EXPANDER_COLLAPSED
215 );
216}
217
218
219// ----------------------------------------------------------------------------
220// splitter sash drawing
221// ----------------------------------------------------------------------------
222
223static int GetGtkSplitterFullSize(GtkWidget* widget)
224{
225 gint handle_size;
226 gtk_widget_style_get(widget, "handle_size", &handle_size, NULL);
227
228 return handle_size;
229}
230
231wxSplitterRenderParams
232wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
233{
234 // we don't draw any border, hence 0 for the second field
235 return wxSplitterRenderParams
236 (
237 GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget()),
238 0,
239 true // hot sensitive
240 );
241}
242
243void
244wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
245 wxDC& WXUNUSED(dc),
246 const wxRect& WXUNUSED(rect),
247 int WXUNUSED(flags))
248{
249 // nothing to do
250}
251
252void
253wxRendererGTK::DrawSplitterSash(wxWindow *win,
254 wxDC& dc,
255 const wxSize& size,
256 wxCoord position,
257 wxOrientation orient,
258 int flags)
259{
260 if ( !win->m_wxwindow->window )
261 {
262 // window not realized yet
263 return;
264 }
265
266 GdkWindow* gdk_window = NULL;
267#if wxUSE_NEW_DC
268 wxDCImpl *impl = dc.GetImpl();
269 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
270 if (gtk_impl)
271 gdk_window = gtk_impl->GetGDKWindow();
272#else
273 gdk_window = dc.GetGDKWindow();
274#endif
275 wxASSERT_MSG( gdk_window,
276 wxT("cannot use wxRendererNative on wxDC of this type") );
277
278 wxCoord full_size = GetGtkSplitterFullSize(wxGTKPrivate::GetSplitterWidget());
279
280 // are we drawing vertical or horizontal splitter?
281 const bool isVert = orient == wxVERTICAL;
282
283 GdkRectangle rect;
284
285 if ( isVert )
286 {
287 rect.x = position;
288 rect.y = 0;
289 rect.width = full_size;
290 rect.height = size.y;
291 }
292 else // horz
293 {
294 rect.x = 0;
295 rect.y = position;
296 rect.height = full_size;
297 rect.width = size.x;
298 }
299
300 int x_diff = 0;
301 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
302 x_diff = rect.width;
303
304 gtk_paint_handle
305 (
306 win->m_wxwindow->style,
307 gdk_window,
308 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
309 GTK_SHADOW_NONE,
310 NULL /* no clipping */,
311 win->m_wxwindow,
312 "paned",
313 dc.LogicalToDeviceX(rect.x) - x_diff,
314 dc.LogicalToDeviceY(rect.y),
315 rect.width,
316 rect.height,
317 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
318 );
319}
320
321void
322wxRendererGTK::DrawDropArrow(wxWindow *WXUNUSED(win),
323 wxDC& dc,
324 const wxRect& rect,
325 int flags)
326{
327 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
328
329 // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
330 // a window for gtk_paint_xxx function, then it won't
331 // work for wxMemoryDC. So that is why we assume wxDC
332 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
333 // are derived from it) and use its m_window.
334 GdkWindow* gdk_window = NULL;
335#if wxUSE_NEW_DC
336 wxDCImpl *impl = dc.GetImpl();
337 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
338 if (gtk_impl)
339 gdk_window = gtk_impl->GetGDKWindow();
340#else
341 gdk_window = dc.GetGDKWindow();
342#endif
343 wxASSERT_MSG( gdk_window,
344 wxT("cannot use wxRendererNative on wxDC of this type") );
345
346 // draw arrow so that there is even space horizontally
347 // on both sides
348 int arrowX = rect.width/4 + 1;
349 int arrowWidth = rect.width - (arrowX*2);
350
351 // scale arrow's height accoording to the width
352 int arrowHeight = rect.width/3;
353 int arrowY = (rect.height-arrowHeight)/2 +
354 ((rect.height-arrowHeight) & 1);
355
356 GtkStateType state;
357
358 if ( flags & wxCONTROL_PRESSED )
359 state = GTK_STATE_ACTIVE;
360 else if ( flags & wxCONTROL_DISABLED )
361 state = GTK_STATE_INSENSITIVE;
362 else if ( flags & wxCONTROL_CURRENT )
363 state = GTK_STATE_PRELIGHT;
364 else
365 state = GTK_STATE_NORMAL;
366
367 // draw arrow on button
368 gtk_paint_arrow
369 (
370 button->style,
371 gdk_window,
372 state,
373 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
374 NULL,
375 button,
376 "arrow",
377 GTK_ARROW_DOWN,
378 FALSE,
379 rect.x + arrowX,
380 rect.y + arrowY,
381 arrowWidth,
382 arrowHeight
383 );
384}
385
386void
387wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
388 wxDC& dc,
389 const wxRect& rect,
390 int flags)
391{
392 DrawPushButton(win,dc,rect,flags);
393 DrawDropArrow(win,dc,rect);
394}
395
396wxSize
397wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win))
398{
399 gint indicator_size, indicator_spacing;
400 gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(),
401 "indicator_size", &indicator_size,
402 "indicator_spacing", &indicator_spacing,
403 NULL);
404
405 int size = indicator_size + indicator_spacing * 2;
406 return wxSize(size, size);
407}
408
409void
410wxRendererGTK::DrawCheckBox(wxWindow *WXUNUSED(win),
411 wxDC& dc,
412 const wxRect& rect,
413 int flags )
414{
415 GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget();
416
417 GdkWindow* gdk_window = NULL;
418#if wxUSE_NEW_DC
419 wxDCImpl *impl = dc.GetImpl();
420 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
421 if (gtk_impl)
422 gdk_window = gtk_impl->GetGDKWindow();
423#else
424 gdk_window = dc.GetGDKWindow();
425#endif
426 wxASSERT_MSG( gdk_window,
427 wxT("cannot use wxRendererNative on wxDC of this type") );
428
429 gint indicator_size, indicator_spacing;
430 gtk_widget_style_get(button,
431 "indicator_size", &indicator_size,
432 "indicator_spacing", &indicator_spacing,
433 NULL);
434
435 GtkStateType state;
436
437 if ( flags & wxCONTROL_PRESSED )
438 state = GTK_STATE_ACTIVE;
439 else if ( flags & wxCONTROL_DISABLED )
440 state = GTK_STATE_INSENSITIVE;
441 else if ( flags & wxCONTROL_CURRENT )
442 state = GTK_STATE_PRELIGHT;
443 else
444 state = GTK_STATE_NORMAL;
445
446 gtk_paint_check
447 (
448 button->style,
449 gdk_window,
450 state,
451 flags & wxCONTROL_CHECKED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
452 NULL,
453 button,
454 "cellcheck",
455 dc.LogicalToDeviceX(rect.x) + indicator_spacing,
456 dc.LogicalToDeviceY(rect.y) + indicator_spacing,
457 indicator_size, indicator_size
458 );
459}
460
461void
462wxRendererGTK::DrawPushButton(wxWindow *WXUNUSED(win),
463 wxDC& dc,
464 const wxRect& rect,
465 int flags)
466{
467 GtkWidget *button = wxGTKPrivate::GetButtonWidget();
468
469 GdkWindow* gdk_window = NULL;
470#if wxUSE_NEW_DC
471 wxDCImpl *impl = dc.GetImpl();
472 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
473 if (gtk_impl)
474 gdk_window = gtk_impl->GetGDKWindow();
475#else
476 gdk_window = dc.GetGDKWindow();
477#endif
478 wxASSERT_MSG( gdk_window,
479 wxT("cannot use wxRendererNative on wxDC of this type") );
480
481 // draw button
482 GtkStateType state;
483
484 if ( flags & wxCONTROL_PRESSED )
485 state = GTK_STATE_ACTIVE;
486 else if ( flags & wxCONTROL_DISABLED )
487 state = GTK_STATE_INSENSITIVE;
488 else if ( flags & wxCONTROL_CURRENT )
489 state = GTK_STATE_PRELIGHT;
490 else
491 state = GTK_STATE_NORMAL;
492
493 gtk_paint_box
494 (
495 button->style,
496 gdk_window,
497 state,
498 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
499 NULL,
500 button,
501 "button",
502 rect.x, rect.y, rect.width, rect.height
503 );
504}
505
506void
507wxRendererGTK::DrawItemSelectionRect(wxWindow *win,
508 wxDC& dc,
509 const wxRect& rect,
510 int flags )
511{
512 GdkWindow* gdk_window = NULL;
513#if wxUSE_NEW_DC
514 wxDCImpl *impl = dc.GetImpl();
515 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
516 if (gtk_impl)
517 gdk_window = gtk_impl->GetGDKWindow();
518#else
519 gdk_window = dc.GetGDKWindow();
520#endif
521 wxASSERT_MSG( gdk_window,
522 wxT("cannot use wxRendererNative on wxDC of this type") );
523
524 int x_diff = 0;
525 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
526 x_diff = rect.width;
527
528 GtkStateType state;
529 if (flags & wxCONTROL_SELECTED)
530 {
531 // the wxCONTROL_FOCUSED state is deduced
532 // directly from the m_wxwindow by GTK+
533 state = GTK_STATE_SELECTED;
534
535 gtk_paint_flat_box( win->m_widget->style,
536 gdk_window,
537 state,
538 GTK_SHADOW_NONE,
539 NULL,
540 win->m_wxwindow,
541 "cell_even",
542 dc.LogicalToDeviceX(rect.x) - x_diff,
543 dc.LogicalToDeviceY(rect.y),
544 rect.width,
545 rect.height );
546 }
547 else // !wxCONTROL_SELECTED
548 {
549 state = GTK_STATE_NORMAL;
550 }
551
552 if ((flags & wxCONTROL_CURRENT) && (flags & wxCONTROL_FOCUSED))
553 {
554 gtk_paint_focus( win->m_widget->style,
555 gdk_window,
556 state,
557 NULL,
558 win->m_wxwindow,
559 // Detail "treeview" causes warning with GTK+ 2.12 Clearlooks theme:
560 // "... no property named `row-ending-details'"
561 // Using "treeview-middle" would fix the warning, but the right
562 // edge of the focus rect is not getting erased properly either.
563 // Better to not specify this detail unless the drawing is fixed.
564 NULL,
565 dc.LogicalToDeviceX(rect.x),
566 dc.LogicalToDeviceY(rect.y),
567 rect.width,
568 rect.height );
569 }
570}
571
572void wxRendererGTK::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
573{
574 GdkWindow* gdk_window = NULL;
575#if wxUSE_NEW_DC
576 wxDCImpl *impl = dc.GetImpl();
577 wxGTKDCImpl *gtk_impl = wxDynamicCast( impl, wxGTKDCImpl );
578 if (gtk_impl)
579 gdk_window = gtk_impl->GetGDKWindow();
580#else
581 gdk_window = dc.GetGDKWindow();
582#endif
583 wxASSERT_MSG( gdk_window,
584 wxT("cannot use wxRendererNative on wxDC of this type") );
585
586 GtkStateType state;
587 if (flags & wxCONTROL_SELECTED)
588 state = GTK_STATE_SELECTED;
589 else
590 state = GTK_STATE_NORMAL;
591
592 gtk_paint_focus( win->m_widget->style,
593 gdk_window,
594 state,
595 NULL,
596 win->m_wxwindow,
597 NULL,
598 dc.LogicalToDeviceX(rect.x),
599 dc.LogicalToDeviceY(rect.y),
600 rect.width,
601 rect.height );
602}