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