]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/renderer.cpp
made wx-config work in place on systems where /bin/sh is a Bourne shell (such as...
[wxWidgets.git] / src / gtk1 / 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"
9c7f49f5 34
3dd570e5
VZ
35#ifdef __WXGTK20__
36 #include "wx/settings.h"
37#endif // GTK 2.0
38
af99040c
VZ
39#ifdef __WXGTK20__
40 #define WXUNUSED_IN_GTK1(arg) arg
41#else
42 #define WXUNUSED_IN_GTK1(arg)
43#endif
44
91af0895
WS
45// RR: After a correction to the orientation of the sash
46// this doesn't seem to be required anymore and it
47// seems to confuse some themes so USE_ERASE_RECT=0
48#define USE_ERASE_RECT 0
49
9c7f49f5 50// ----------------------------------------------------------------------------
38c4cb6a 51// wxRendererGTK: our wxRendererNative implementation
9c7f49f5
VZ
52// ----------------------------------------------------------------------------
53
38c4cb6a 54class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
9c7f49f5
VZ
55{
56public:
57 // draw the header control button (used by wxListCtrl)
58 virtual void DrawHeaderButton(wxWindow *win,
59 wxDC& dc,
60 const wxRect& rect,
61 int flags = 0);
62
63#ifdef __WXGTK20__
64 // draw the expanded/collapsed icon for a tree control item
65 virtual void DrawTreeItemButton(wxWindow *win,
66 wxDC& dc,
67 const wxRect& rect,
68 int flags = 0);
e1befae3 69#endif // GTK+ 2.0
9c7f49f5 70
d16cf3cd
VZ
71 virtual void DrawSplitterBorder(wxWindow *win,
72 wxDC& dc,
af99040c
VZ
73 const wxRect& rect,
74 int flags = 0);
95155e75
VZ
75 virtual void DrawSplitterSash(wxWindow *win,
76 wxDC& dc,
77 const wxSize& size,
d16cf3cd 78 wxCoord position,
af99040c
VZ
79 wxOrientation orient,
80 int flags = 0);
d16cf3cd 81
38511687
VZ
82 virtual void DrawComboBoxDropButton(wxWindow *win,
83 wxDC& dc,
84 const wxRect& rect,
85 int flags = 0);
86
4c85ab75
VZ
87 virtual void DrawDropArrow(wxWindow *win,
88 wxDC& dc,
89 const wxRect& rect,
90 int flags = 0);
91
af99040c 92 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
e1befae3
VZ
93
94private:
bc13e772
VZ
95 // FIXME: shouldn't we destroy these windows somewhere?
96
e1befae3 97 // used by DrawHeaderButton and DrawComboBoxDropButton
bc13e772
VZ
98 static GtkWidget *GetButtonWidget();
99
100#ifdef __WXGTK20__
101 // used by DrawTreeItemButton()
102 static GtkWidget *GetTreeWidget();
103#endif // GTK+ 2.0
9c7f49f5
VZ
104};
105
106// ============================================================================
107// implementation
108// ============================================================================
109
110/* static */
f0244295 111wxRendererNative& wxRendererNative::GetDefault()
9c7f49f5
VZ
112{
113 static wxRendererGTK s_rendererGTK;
114
115 return s_rendererGTK;
116}
117
a4622f29 118// ----------------------------------------------------------------------------
bc13e772 119// helper functions
a4622f29
VZ
120// ----------------------------------------------------------------------------
121
bc13e772
VZ
122GtkWidget *
123wxRendererGTK::GetButtonWidget()
124{
125 static GtkWidget *s_button = NULL;
126 static GtkWidget *s_window = NULL;
a4622f29 127
bc13e772
VZ
128 if ( !s_button )
129 {
130 s_window = gtk_window_new( GTK_WINDOW_POPUP );
131 gtk_widget_realize( s_window );
132 s_button = gtk_button_new();
133 gtk_container_add( GTK_CONTAINER(s_window), s_button );
134 gtk_widget_realize( s_button );
135 }
136
137 return s_button;
138}
139
140#ifdef __WXGTK20__
141
142GtkWidget *
143wxRendererGTK::GetTreeWidget()
a4622f29 144{
bc13e772
VZ
145 static GtkWidget *s_tree = NULL;
146 static GtkWidget *s_window = NULL;
147
148 if ( !s_tree )
149 {
150 s_tree = gtk_tree_view_new();
151 s_window = gtk_window_new( GTK_WINDOW_POPUP );
152 gtk_widget_realize( s_window );
153 gtk_container_add( GTK_CONTAINER(s_window), s_tree );
154 gtk_widget_realize( s_tree );
155 }
156
157 return s_tree;
a4622f29
VZ
158}
159
bc13e772
VZ
160#endif // GTK+ 2.0
161
d16cf3cd
VZ
162// ----------------------------------------------------------------------------
163// list/tree controls drawing
164// ----------------------------------------------------------------------------
165
9c7f49f5
VZ
166void
167wxRendererGTK::DrawHeaderButton(wxWindow *win,
168 wxDC& dc,
169 const wxRect& rect,
170 int flags)
171{
9b311923 172
bc13e772 173 GtkWidget *button = GetButtonWidget();
9b311923 174
9c7f49f5
VZ
175 gtk_paint_box
176 (
bc13e772 177 button->style,
a4622f29
VZ
178 // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC.
179 // Maybe use code similar as in DrawComboBoxDropButton below?
9c7f49f5
VZ
180 GTK_PIZZA(win->m_wxwindow)->bin_window,
181 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
182 GTK_SHADOW_OUT,
38511687 183 NULL,
bc13e772 184 button,
9b311923
RR
185 "button",
186 dc.XLOG2DEV(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
9c7f49f5
VZ
187 );
188}
189
190#ifdef __WXGTK20__
191
192// draw a ">" or "v" button
9c7f49f5 193void
f8b043e7 194wxRendererGTK::DrawTreeItemButton(wxWindow* win,
9a0b7e33 195 wxDC& dc, const wxRect& rect, int flags)
9c7f49f5 196{
bc13e772 197 GtkWidget *tree = GetTreeWidget();
f8b043e7 198
885dd597
RR
199 GtkStateType state;
200 if ( flags & wxCONTROL_CURRENT )
201 state = GTK_STATE_PRELIGHT;
202 else
203 state = GTK_STATE_NORMAL;
91af0895 204
bc13e772
VZ
205 // VZ: I don't know how to get the size of the expander so as to centre it
206 // in the given rectangle, +2/3 below is just what looks good here...
207 gtk_paint_expander
208 (
209 tree->style,
210 GTK_PIZZA(win->m_wxwindow)->bin_window,
885dd597 211 state,
bc13e772
VZ
212 NULL,
213 tree,
214 "treeview",
215 dc.LogicalToDeviceX(rect.x) + 2,
216 dc.LogicalToDeviceY(rect.y) + 3,
217 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
218 : GTK_EXPANDER_COLLAPSED
219 );
9c7f49f5
VZ
220}
221
bc13e772 222#endif // GTK+ 2.0
9c7f49f5 223
d16cf3cd
VZ
224// ----------------------------------------------------------------------------
225// splitter sash drawing
226// ----------------------------------------------------------------------------
227
38418827 228#ifndef __WXGTK20__
af99040c 229 // the full sash width (should be even)
35468934 230 static const wxCoord SASH_SIZE = 8;
af99040c
VZ
231
232 // margin around the sash
35468934 233 static const wxCoord SASH_MARGIN = 2;
af99040c 234#endif // GTK+ 2.x/1.x
d16cf3cd 235
38418827
RR
236static int GetGtkSplitterFullSize()
237{
238#ifdef __WXGTK20__
239 static GtkWidget *s_paned = NULL;
240 if (s_paned == NULL)
241 s_paned = gtk_vpaned_new();
242
243 gint handle_size;
244 gtk_widget_style_get (s_paned, "handle_size", &handle_size, NULL);
91af0895 245
38418827
RR
246 return handle_size;
247#else
248 return SASH_SIZE + SASH_MARGIN;
249#endif
250}
251
af99040c 252wxSplitterRenderParams
38418827 253wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
d16cf3cd 254{
af99040c
VZ
255 // we don't draw any border, hence 0 for the second field
256 return wxSplitterRenderParams
257 (
38418827 258 GetGtkSplitterFullSize(),
af99040c
VZ
259 0,
260#ifdef __WXGTK20__
261 true // hot sensitive
262#else // GTK+ 1.x
263 false // not
264#endif // GTK+ 2.x/1.x
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
VZ
282 wxOrientation orient,
283 int WXUNUSED_IN_GTK1(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#ifdef __WXGTK20__
354 gtk_paint_handle
355 (
356 win->m_wxwindow->style,
357 GTK_PIZZA(win->m_wxwindow)->bin_window,
358 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
359 GTK_SHADOW_NONE,
360 NULL /* no clipping */,
361 win->m_wxwindow,
362 "paned",
363 rect.x,
364 rect.y,
365 rect.width,
366 rect.height,
38418827 367 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
af99040c
VZ
368 );
369#else // GTK+ 1.x
d16cf3cd
VZ
370
371 // leave some margin before sash itself
372 position += SASH_MARGIN / 2;
373
374 // and finally draw it using GTK paint functions
375 typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
376 GtkStateType,
377 GdkRectangle *, GtkWidget *,
ef9bfb71 378 gchar *,
ef9bfb71 379 gint, gint, gint);
d16cf3cd
VZ
380
381 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
382
383 (*func)
95155e75
VZ
384 (
385 win->m_wxwindow->style,
d16cf3cd 386 GTK_PIZZA(win->m_wxwindow)->bin_window,
95155e75 387 GTK_STATE_NORMAL,
d16cf3cd 388 NULL,
95155e75 389 win->m_wxwindow,
d16cf3cd
VZ
390 (char *)"paned", // const_cast
391 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
95155e75
VZ
392 );
393
394 gtk_paint_box
395 (
396 win->m_wxwindow->style,
d16cf3cd 397 GTK_PIZZA(win->m_wxwindow)->bin_window,
95155e75
VZ
398 GTK_STATE_NORMAL,
399 GTK_SHADOW_OUT,
d16cf3cd 400 (GdkRectangle*) NULL,
95155e75
VZ
401 win->m_wxwindow,
402 (char *)"paned", // const_cast
d16cf3cd
VZ
403 isVert ? position : size.x - 2*SASH_SIZE,
404 isVert ? size.y - 2*SASH_SIZE : position,
405 SASH_SIZE, SASH_SIZE
95155e75 406 );
af99040c 407#endif // GTK+ 2.x/1.x
95155e75
VZ
408}
409
4c85ab75
VZ
410void
411wxRendererGTK::DrawDropArrow(wxWindow *win,
412 wxDC& dc,
413 const wxRect& rect,
414 int flags)
38511687 415{
bc13e772 416 GtkWidget *button = GetButtonWidget();
38511687 417
4c85ab75
VZ
418 // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
419 // a window for gtk_paint_xxx function, then it won't
420 // work for wxMemoryDC. So that is why we assume wxDC
421 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
422 // are derived from it) and use its m_window.
a4622f29
VZ
423 wxWindowDC& wdc = (wxWindowDC&)dc;
424
4c85ab75
VZ
425 // only doing debug-time checking here (it should
426 // probably be enough)
a4622f29
VZ
427 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
428
4c85ab75
VZ
429 // draw arrow so that there is even space horizontally
430 // on both sides
431 int arrowX = rect.width/4 + 1;
432 int arrowWidth = rect.width - (arrowX*2);
433
434 // scale arrow's height accoording to the width
435 int arrowHeight = rect.width/3;
436 int arrowY = (rect.height-arrowHeight)/2 +
437 ((rect.height-arrowHeight) & 1);
438
e1befae3 439 GtkStateType state;
a4622f29 440
3203621a
JS
441 if ( flags & wxCONTROL_PRESSED )
442 state = GTK_STATE_ACTIVE;
a4622f29
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;
e1befae3
VZ
447 else
448 state = GTK_STATE_NORMAL;
a4622f29 449
a4622f29 450 // draw arrow on button
a4622f29
VZ
451 gtk_paint_arrow
452 (
bc13e772 453 button->style,
a4622f29
VZ
454 wdc.m_window,
455 state,
e1befae3 456 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
a4622f29 457 NULL,
bc13e772 458 button,
a4622f29
VZ
459 "arrow",
460 GTK_ARROW_DOWN,
a8ac548e 461 FALSE,
4c85ab75
VZ
462 rect.x + arrowX,
463 rect.y + arrowY,
464 arrowWidth,
465 arrowHeight
a4622f29 466 );
38511687
VZ
467}
468
4c85ab75
VZ
469void
470wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
471 wxDC& dc,
472 const wxRect& rect,
473 int flags)
474{
475 GtkWidget *button = GetButtonWidget();
476
477 // for reason why we do this, see DrawDropArrow
478 wxWindowDC& wdc = (wxWindowDC&)dc;
479 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
480
481 // draw button
482 GtkStateType state;
483
3203621a
JS
484 if ( flags & wxCONTROL_PRESSED )
485 state = GTK_STATE_ACTIVE;
4c85ab75
VZ
486 else if ( flags & wxCONTROL_DISABLED )
487 state = GTK_STATE_INSENSITIVE;
3203621a
JS
488 else if ( flags & wxCONTROL_CURRENT )
489 state = GTK_STATE_PRELIGHT;
4c85ab75
VZ
490 else
491 state = GTK_STATE_NORMAL;
492
493 gtk_paint_box
494 (
495 button->style,
496 wdc.m_window,
497 state,
498 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
499 NULL,
500 button,
501 "button",
502 rect.x, rect.y, rect.width, rect.height
503 );
504
505 // draw arrow on button
506 DrawDropArrow(win,dc,rect,flags);
507
508}
509