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