]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/renderer.cpp
Always use MCHITTESTINFO of minimal size.
[wxWidgets.git] / src / gtk1 / renderer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk1/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
29 #ifndef WX_PRECOMP
30     #include "wx/window.h"
31     #include "wx/dc.h"
32 #endif
33
34 #include <gtk/gtk.h>
35 #include "wx/gtk1/win_gtk.h"
36 #include "wx/gtk1/dcclient.h"
37
38 // RR: After a correction to the orientation of the sash
39 //     this doesn't seem to be required anymore and it
40 //     seems to confuse some themes so USE_ERASE_RECT=0
41 #define USE_ERASE_RECT 0
42
43 // ----------------------------------------------------------------------------
44 // wxRendererGTK: our wxRendererNative implementation
45 // ----------------------------------------------------------------------------
46
47 class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
48 {
49 public:
50     // draw the header control button (used by wxListCtrl)
51     virtual int DrawHeaderButton(wxWindow *win,
52                                  wxDC& dc,
53                                  const wxRect& rect,
54                                  int flags = 0,
55                                  wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
56                                  wxHeaderButtonParams* params=NULL);
57
58     virtual void DrawSplitterBorder(wxWindow *win,
59                                     wxDC& dc,
60                                     const wxRect& rect,
61                                     int flags = 0);
62     virtual void DrawSplitterSash(wxWindow *win,
63                                   wxDC& dc,
64                                   const wxSize& size,
65                                   wxCoord position,
66                                   wxOrientation orient,
67                                   int flags = 0);
68
69     virtual void DrawComboBoxDropButton(wxWindow *win,
70                                         wxDC& dc,
71                                         const wxRect& rect,
72                                         int flags = 0);
73
74     virtual void DrawDropArrow(wxWindow *win,
75                                wxDC& dc,
76                                const wxRect& rect,
77                                int flags = 0);
78
79     virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
80
81 private:
82     // FIXME: shouldn't we destroy these windows somewhere?
83
84     // used by DrawHeaderButton and DrawComboBoxDropButton
85     static GtkWidget *GetButtonWidget();
86 };
87
88 // ============================================================================
89 // implementation
90 // ============================================================================
91
92 /* static */
93 wxRendererNative& wxRendererNative::GetDefault()
94 {
95     static wxRendererGTK s_rendererGTK;
96
97     return s_rendererGTK;
98 }
99
100 // ----------------------------------------------------------------------------
101 // helper functions
102 // ----------------------------------------------------------------------------
103
104 GtkWidget *
105 wxRendererGTK::GetButtonWidget()
106 {
107     static GtkWidget *s_button = NULL;
108     static GtkWidget *s_window = NULL;
109
110     if ( !s_button )
111     {
112         s_window = gtk_window_new( GTK_WINDOW_POPUP );
113         gtk_widget_realize( s_window );
114         s_button = gtk_button_new();
115         gtk_container_add( GTK_CONTAINER(s_window), s_button );
116         gtk_widget_realize( s_button );
117     }
118
119     return s_button;
120 }
121
122 // ----------------------------------------------------------------------------
123 // list/tree controls drawing
124 // ----------------------------------------------------------------------------
125
126 int
127 wxRendererGTK::DrawHeaderButton(wxWindow *win,
128                                 wxDC& dc,
129                                 const wxRect& rect,
130                                 int flags,
131                                 wxHeaderSortIconType WXUNUSED(sortArrow),
132                                 wxHeaderButtonParams* WXUNUSED(params))
133 {
134
135     GtkWidget *button = GetButtonWidget();
136
137     gtk_paint_box
138     (
139         button->style,
140         // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC.
141         //   Maybe use code similar as in DrawComboBoxDropButton below?
142         GTK_PIZZA(win->m_wxwindow)->bin_window,
143         flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
144         GTK_SHADOW_OUT,
145         NULL,
146         button,
147         "button",
148         dc.LogicalToDeviceX(rect.x) -1, rect.y -1, rect.width +2, rect.height +2
149     );
150
151     return rect.width + 2;
152 }
153
154 // ----------------------------------------------------------------------------
155 // splitter sash drawing
156 // ----------------------------------------------------------------------------
157
158 // the full sash width (should be even)
159 static const wxCoord SASH_SIZE = 8;
160
161 // margin around the sash
162 static const wxCoord SASH_MARGIN = 2;
163
164 static int GetGtkSplitterFullSize()
165 {
166     return SASH_SIZE + SASH_MARGIN;
167 }
168
169 wxSplitterRenderParams
170 wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
171 {
172     // we don't draw any border, hence 0 for the second field
173     return wxSplitterRenderParams
174            (
175                GetGtkSplitterFullSize(),
176                0,
177                false    // not
178            );
179 }
180
181 void
182 wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
183                                   wxDC& WXUNUSED(dc),
184                                   const wxRect& WXUNUSED(rect),
185                                   int WXUNUSED(flags))
186 {
187     // nothing to do
188 }
189
190 void
191 wxRendererGTK::DrawSplitterSash(wxWindow *win,
192                                 wxDC& WXUNUSED(dc),
193                                 const wxSize& size,
194                                 wxCoord position,
195                                 wxOrientation orient,
196                                 int WXUNUSED(flags))
197 {
198     if ( !win->m_wxwindow->window )
199     {
200         // window not realized yet
201         return;
202     }
203
204     wxCoord full_size = GetGtkSplitterFullSize();
205
206     // are we drawing vertical or horizontal splitter?
207     const bool isVert = orient == wxVERTICAL;
208
209     GdkRectangle rect;
210 #if USE_ERASE_RECT
211     GdkRectangle erase_rect;
212 #endif
213
214     if ( isVert )
215     {
216         int h = win->GetClientSize().GetHeight();
217
218         rect.x = position;
219         rect.y = 0;
220         rect.width = full_size;
221         rect.height = h;
222
223 #if USE_ERASE_RECT
224         erase_rect.x = position;
225         erase_rect.y = 0;
226         erase_rect.width = full_size;
227         erase_rect.height = h;
228 #endif
229     }
230     else // horz
231     {
232         int w = win->GetClientSize().GetWidth();
233
234         rect.x = 0;
235         rect.y = position;
236         rect.height = full_size;
237         rect.width = w;
238
239 #if USE_ERASE_RECT
240         erase_rect.y = position;
241         erase_rect.x = 0;
242         erase_rect.height = full_size;
243         erase_rect.width = w;
244 #endif
245     }
246
247 #if USE_ERASE_RECT
248     // we must erase everything first, otherwise the garbage
249     // from the old sash is left when dragging it
250     gtk_paint_flat_box
251     (
252         win->m_wxwindow->style,
253         GTK_PIZZA(win->m_wxwindow)->bin_window,
254         GTK_STATE_NORMAL,
255         GTK_SHADOW_NONE,
256         NULL,
257         win->m_wxwindow,
258         (char *)"viewportbin", // const_cast
259         erase_rect.x,
260         erase_rect.y,
261         erase_rect.width,
262         erase_rect.height
263     );
264 #endif
265
266
267     // leave some margin before sash itself
268     position += SASH_MARGIN / 2;
269
270     // and finally draw it using GTK paint functions
271     typedef void (*GtkPaintLineFunc)(GtkStyle *, GdkWindow *,
272                                                 GtkStateType,
273                                                 GdkRectangle *, GtkWidget *,
274                                                 gchar *,
275                                                 gint, gint, gint);
276
277     GtkPaintLineFunc func = isVert ? gtk_paint_vline : gtk_paint_hline;
278
279     (*func)
280     (
281         win->m_wxwindow->style,
282         GTK_PIZZA(win->m_wxwindow)->bin_window,
283         GTK_STATE_NORMAL,
284         NULL,
285         win->m_wxwindow,
286         (char *)"paned", // const_cast
287         0, isVert ? size.y : size.x, position + SASH_SIZE / 2 - 1
288     );
289
290     gtk_paint_box
291     (
292         win->m_wxwindow->style,
293         GTK_PIZZA(win->m_wxwindow)->bin_window,
294         GTK_STATE_NORMAL,
295         GTK_SHADOW_OUT,
296         NULL,
297         win->m_wxwindow,
298         (char *)"paned", // const_cast
299         isVert ? position : size.x - 2*SASH_SIZE,
300         isVert ? size.y - 2*SASH_SIZE : position,
301         SASH_SIZE, SASH_SIZE
302     );
303 }
304
305 void
306 wxRendererGTK::DrawDropArrow(wxWindow *WXUNUSED(win),
307                              wxDC& dc,
308                              const wxRect& rect,
309                              int flags)
310 {
311     GtkWidget *button = GetButtonWidget();
312
313     // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
314     // a window for gtk_paint_xxx function, then it won't
315     // work for wxMemoryDC. So that is why we assume wxDC
316     // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
317     // are derived from it) and use its m_window.
318     wxWindowDCImpl * const impl = wxDynamicCast(dc.GetImpl(), wxWindowDCImpl);
319     wxCHECK_RET( impl, "must have a window DC" );
320
321     GdkWindow* gdk_window = impl->GetGDKWindow();
322
323     // draw arrow so that there is even space horizontally
324     // on both sides
325     int arrowX = rect.width/4 + 1;
326     int arrowWidth = rect.width - (arrowX*2);
327
328     // scale arrow's height accoording to the width
329     int arrowHeight = rect.width/3;
330     int arrowY = (rect.height-arrowHeight)/2 +
331                  ((rect.height-arrowHeight) & 1);
332
333     GtkStateType state;
334
335     if ( flags & wxCONTROL_PRESSED )
336         state = GTK_STATE_ACTIVE;
337     else if ( flags & wxCONTROL_DISABLED )
338         state = GTK_STATE_INSENSITIVE;
339     else if ( flags & wxCONTROL_CURRENT )
340         state = GTK_STATE_PRELIGHT;
341     else
342         state = GTK_STATE_NORMAL;
343
344     // draw arrow on button
345     gtk_paint_arrow
346     (
347         button->style,
348         gdk_window,
349         state,
350         flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
351         NULL,
352         button,
353         "arrow",
354         GTK_ARROW_DOWN,
355         FALSE,
356         rect.x + arrowX,
357         rect.y + arrowY,
358         arrowWidth,
359         arrowHeight
360     );
361 }
362
363 void
364 wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
365                                       wxDC& dc,
366                                       const wxRect& rect,
367                                       int flags)
368 {
369     GtkWidget *button = GetButtonWidget();
370
371     // for reason why we do this, see DrawDropArrow
372     wxWindowDCImpl * const impl = wxDynamicCast(dc.GetImpl(), wxWindowDCImpl);
373     wxCHECK_RET( impl, "must have a window DC" );
374
375     GdkWindow* gdk_window = impl->GetGDKWindow();
376
377     // draw button
378     GtkStateType state;
379
380     if ( flags & wxCONTROL_PRESSED )
381         state = GTK_STATE_ACTIVE;
382     else if ( flags & wxCONTROL_DISABLED )
383         state = GTK_STATE_INSENSITIVE;
384     else if ( flags & wxCONTROL_CURRENT )
385         state = GTK_STATE_PRELIGHT;
386     else
387         state = GTK_STATE_NORMAL;
388
389     gtk_paint_box
390     (
391         button->style,
392         gdk_window,
393         state,
394         flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
395         NULL,
396         button,
397         "button",
398         rect.x, rect.y, rect.width, rect.height
399     );
400
401     // draw arrow on button
402     DrawDropArrow(win,dc,rect,flags);
403
404 }