]> git.saurik.com Git - wxWidgets.git/blame_incremental - 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
1///////////////////////////////////////////////////////////////////////////////
2// Name: gtk/renderer.cpp
3// Purpose: implementation of wxRendererNative for wxGTK
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>
9// License: wxWindows licence
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
27#include "wx/renderer.h"
28#include <gtk/gtk.h>
29#include "wx/gtk/win_gtk.h"
30
31#include "wx/window.h"
32#include "wx/dc.h"
33#include "wx/dcclient.h"
34
35#ifdef __WXGTK20__
36 #include "wx/settings.h"
37#endif // GTK 2.0
38
39#ifdef __WXGTK20__
40 #define WXUNUSED_IN_GTK1(arg) arg
41#else
42 #define WXUNUSED_IN_GTK1(arg)
43#endif
44
45// ----------------------------------------------------------------------------
46// wxRendererGTK: our wxRendererNative implementation
47// ----------------------------------------------------------------------------
48
49class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
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);
64#endif // GTK+ 2.0
65
66 virtual void DrawSplitterBorder(wxWindow *win,
67 wxDC& dc,
68 const wxRect& rect,
69 int flags = 0);
70 virtual void DrawSplitterSash(wxWindow *win,
71 wxDC& dc,
72 const wxSize& size,
73 wxCoord position,
74 wxOrientation orient,
75 int flags = 0);
76
77 virtual void DrawComboBoxDropButton(wxWindow *win,
78 wxDC& dc,
79 const wxRect& rect,
80 int flags = 0);
81
82 virtual void DrawDropArrow(wxWindow *win,
83 wxDC& dc,
84 const wxRect& rect,
85 int flags = 0);
86
87 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
88
89private:
90 // FIXME: shouldn't we destroy these windows somewhere?
91
92 // used by DrawHeaderButton and DrawComboBoxDropButton
93 static GtkWidget *GetButtonWidget();
94
95#ifdef __WXGTK20__
96 // used by DrawTreeItemButton()
97 static GtkWidget *GetTreeWidget();
98#endif // GTK+ 2.0
99};
100
101// ============================================================================
102// implementation
103// ============================================================================
104
105/* static */
106wxRendererNative& wxRendererNative::GetDefault()
107{
108 static wxRendererGTK s_rendererGTK;
109
110 return s_rendererGTK;
111}
112
113// ----------------------------------------------------------------------------
114// helper functions
115// ----------------------------------------------------------------------------
116
117GtkWidget *
118wxRendererGTK::GetButtonWidget()
119{
120 static GtkWidget *s_button = NULL;
121 static GtkWidget *s_window = NULL;
122
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()
139{
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;
153}
154
155#endif // GTK+ 2.0
156
157// ----------------------------------------------------------------------------
158// list/tree controls drawing
159// ----------------------------------------------------------------------------
160
161void
162wxRendererGTK::DrawHeaderButton(wxWindow *win,
163 wxDC& dc,
164 const wxRect& rect,
165 int flags)
166{
167
168 GtkWidget *button = GetButtonWidget();
169
170 gtk_paint_box
171 (
172 button->style,
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?
175 GTK_PIZZA(win->m_wxwindow)->bin_window,
176 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
177 GTK_SHADOW_OUT,
178 NULL,
179 button,
180 "button",
181 dc.XLOG2DEV(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
182 );
183}
184
185#ifdef __WXGTK20__
186
187// draw a ">" or "v" button
188void
189wxRendererGTK::DrawTreeItemButton(wxWindow* win,
190 wxDC& dc, const wxRect& rect, int flags)
191{
192 GtkWidget *tree = GetTreeWidget();
193
194 GtkStateType state;
195 if ( flags & wxCONTROL_CURRENT )
196 state = GTK_STATE_PRELIGHT;
197 else
198 state = GTK_STATE_NORMAL;
199
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,
206 state,
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 );
215}
216
217#endif // GTK+ 2.0
218
219// ----------------------------------------------------------------------------
220// splitter sash drawing
221// ----------------------------------------------------------------------------
222
223#ifndef __WXGTK20__
224 // the full sash width (should be even)
225 static const wxCoord SASH_SIZE = 8;
226
227 // margin around the sash
228 static const wxCoord SASH_MARGIN = 2;
229#endif // GTK+ 2.x/1.x
230
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
247wxSplitterRenderParams
248wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
249{
250 // we don't draw any border, hence 0 for the second field
251 return wxSplitterRenderParams
252 (
253 GetGtkSplitterFullSize(),
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 );
261}
262
263void
264wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
265 wxDC& WXUNUSED(dc),
266 const wxRect& WXUNUSED(rect),
267 int WXUNUSED(flags))
268{
269 // nothing to do
270}
271
272void
273wxRendererGTK::DrawSplitterSash(wxWindow *win,
274 wxDC& dc,
275 const wxSize& size,
276 wxCoord position,
277 wxOrientation orient,
278 int WXUNUSED_IN_GTK1(flags))
279{
280 if ( !win->m_wxwindow->window )
281 {
282 // window not realized yet
283 return;
284 }
285
286 wxCoord full_size = GetGtkSplitterFullSize();
287
288 // are we drawing vertical or horizontal splitter?
289 const bool isVert = orient == wxVERTICAL;
290
291 GdkRectangle rect;
292 GdkRectangle erase_rect;
293 if ( isVert )
294 {
295 int h = win->GetClientSize().GetHeight();
296
297 rect.x = position;
298 rect.y = 0;
299 rect.width = full_size;
300 rect.height = h;
301
302 erase_rect.x = position;
303 erase_rect.y = 0;
304 erase_rect.width = full_size;
305 erase_rect.height = h;
306 }
307 else // horz
308 {
309 int w = win->GetClientSize().GetWidth();
310
311 rect.x = 0;
312 rect.y = position;
313 rect.height = full_size;
314 rect.width = w;
315
316 erase_rect.y = position;
317 erase_rect.x = 0;
318 erase_rect.height = full_size;
319 erase_rect.width = w;
320 }
321
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
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,
337 (char *)"viewportbin", // const_cast
338 erase_rect.x,
339 erase_rect.y,
340 erase_rect.width,
341 erase_rect.height
342 );
343#endif
344
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,
359 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
360 );
361#else // GTK+ 1.x
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 *,
370 gchar *,
371 gint, gint, gint);
372
373 GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
374
375 (*func)
376 (
377 win->m_wxwindow->style,
378 GTK_PIZZA(win->m_wxwindow)->bin_window,
379 GTK_STATE_NORMAL,
380 NULL,
381 win->m_wxwindow,
382 (char *)"paned", // const_cast
383 0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
384 );
385
386 gtk_paint_box
387 (
388 win->m_wxwindow->style,
389 GTK_PIZZA(win->m_wxwindow)->bin_window,
390 GTK_STATE_NORMAL,
391 GTK_SHADOW_OUT,
392 (GdkRectangle*) NULL,
393 win->m_wxwindow,
394 (char *)"paned", // const_cast
395 isVert ? position : size.x - 2*SASH_SIZE,
396 isVert ? size.y - 2*SASH_SIZE : position,
397 SASH_SIZE, SASH_SIZE
398 );
399#endif // GTK+ 2.x/1.x
400}
401
402void
403wxRendererGTK::DrawDropArrow(wxWindow *win,
404 wxDC& dc,
405 const wxRect& rect,
406 int flags)
407{
408 GtkWidget *button = GetButtonWidget();
409
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.
415 wxWindowDC& wdc = (wxWindowDC&)dc;
416
417 // only doing debug-time checking here (it should
418 // probably be enough)
419 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
420
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
431 GtkStateType state;
432
433 if ( flags & wxCONTROL_PRESSED )
434 state = GTK_STATE_ACTIVE;
435 else if ( flags & wxCONTROL_DISABLED )
436 state = GTK_STATE_INSENSITIVE;
437 else if ( flags & wxCONTROL_CURRENT )
438 state = GTK_STATE_PRELIGHT;
439 else
440 state = GTK_STATE_NORMAL;
441
442 // draw arrow on button
443 gtk_paint_arrow
444 (
445 button->style,
446 wdc.m_window,
447 state,
448 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
449 NULL,
450 button,
451 "arrow",
452 GTK_ARROW_DOWN,
453 FALSE,
454 rect.x + arrowX,
455 rect.y + arrowY,
456 arrowWidth,
457 arrowHeight
458 );
459}
460
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
476 if ( flags & wxCONTROL_PRESSED )
477 state = GTK_STATE_ACTIVE;
478 else if ( flags & wxCONTROL_DISABLED )
479 state = GTK_STATE_INSENSITIVE;
480 else if ( flags & wxCONTROL_CURRENT )
481 state = GTK_STATE_PRELIGHT;
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