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