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