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