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