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