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