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