]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/renderer.cpp
Fix scrolling bug where client size was reported wrong
[wxWidgets.git] / src / gtk / renderer.cpp
CommitLineData
9c7f49f5 1///////////////////////////////////////////////////////////////////////////////
90b903c2 2// Name: src/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"
cdccdfab
WS
28
29#ifndef WX_PRECOMP
30 #include "wx/window.h"
ed4b0fdc 31 #include "wx/dcclient.h"
9eddec69 32 #include "wx/settings.h"
cdccdfab
WS
33#endif
34
9c7f49f5
VZ
35#include <gtk/gtk.h>
36#include "wx/gtk/win_gtk.h"
37
9c7f49f5 38// ----------------------------------------------------------------------------
38c4cb6a 39// wxRendererGTK: our wxRendererNative implementation
9c7f49f5
VZ
40// ----------------------------------------------------------------------------
41
38c4cb6a 42class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative
9c7f49f5
VZ
43{
44public:
45 // draw the header control button (used by wxListCtrl)
46 virtual void DrawHeaderButton(wxWindow *win,
47 wxDC& dc,
48 const wxRect& rect,
4b94ddc4 49 int flags = 0,
80752b57 50 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
4b94ddc4 51 wxHeaderButtonParams* params = NULL);
9c7f49f5 52
9c7f49f5
VZ
53 // draw the expanded/collapsed icon for a tree control item
54 virtual void DrawTreeItemButton(wxWindow *win,
55 wxDC& dc,
56 const wxRect& rect,
57 int flags = 0);
9c7f49f5 58
d16cf3cd
VZ
59 virtual void DrawSplitterBorder(wxWindow *win,
60 wxDC& dc,
af99040c
VZ
61 const wxRect& rect,
62 int flags = 0);
95155e75
VZ
63 virtual void DrawSplitterSash(wxWindow *win,
64 wxDC& dc,
65 const wxSize& size,
d16cf3cd 66 wxCoord position,
af99040c
VZ
67 wxOrientation orient,
68 int flags = 0);
d16cf3cd 69
38511687
VZ
70 virtual void DrawComboBoxDropButton(wxWindow *win,
71 wxDC& dc,
72 const wxRect& rect,
73 int flags = 0);
74
4c85ab75
VZ
75 virtual void DrawDropArrow(wxWindow *win,
76 wxDC& dc,
77 const wxRect& rect,
78 int flags = 0);
79
90b903c2
WS
80 virtual void DrawCheckBox(wxWindow *win,
81 wxDC& dc,
82 const wxRect& rect,
83 int flags = 0);
2209baae
RR
84
85 virtual void DrawPushButton(wxWindow *win,
86 wxDC& dc,
87 const wxRect& rect,
88 int flags = 0);
89
daebb44c
RR
90 virtual void DrawItemSelectionRect(wxWindow *win,
91 wxDC& dc,
92 const wxRect& rect,
93 int flags = 0);
90b903c2 94
af99040c 95 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
e1befae3
VZ
96
97private:
bc13e772
VZ
98 // FIXME: shouldn't we destroy these windows somewhere?
99
2209baae 100 // used by DrawHeaderButton and DrawPushButton
bc13e772
VZ
101 static GtkWidget *GetButtonWidget();
102
bc13e772
VZ
103 // used by DrawTreeItemButton()
104 static GtkWidget *GetTreeWidget();
90b903c2
WS
105
106 // used by DrawCheckBox()
862d8041 107 static GtkWidget *GetCheckButtonWidget();
9c7f49f5
VZ
108};
109
110// ============================================================================
111// implementation
112// ============================================================================
113
114/* static */
f0244295 115wxRendererNative& wxRendererNative::GetDefault()
9c7f49f5
VZ
116{
117 static wxRendererGTK s_rendererGTK;
118
119 return s_rendererGTK;
120}
121
a4622f29 122// ----------------------------------------------------------------------------
bc13e772 123// helper functions
a4622f29
VZ
124// ----------------------------------------------------------------------------
125
bc13e772
VZ
126GtkWidget *
127wxRendererGTK::GetButtonWidget()
128{
129 static GtkWidget *s_button = NULL;
130 static GtkWidget *s_window = NULL;
a4622f29 131
bc13e772
VZ
132 if ( !s_button )
133 {
134 s_window = gtk_window_new( GTK_WINDOW_POPUP );
135 gtk_widget_realize( s_window );
136 s_button = gtk_button_new();
137 gtk_container_add( GTK_CONTAINER(s_window), s_button );
138 gtk_widget_realize( s_button );
139 }
140
141 return s_button;
142}
143
862d8041
RR
144GtkWidget *
145wxRendererGTK::GetCheckButtonWidget()
146{
147 static GtkWidget *s_button = NULL;
148 static GtkWidget *s_window = NULL;
149
150 if ( !s_button )
151 {
152 s_window = gtk_window_new( GTK_WINDOW_POPUP );
153 gtk_widget_realize( s_window );
154 s_button = gtk_check_button_new();
155 gtk_container_add( GTK_CONTAINER(s_window), s_button );
156 gtk_widget_realize( s_button );
157 }
158
159 return s_button;
160}
161
bc13e772
VZ
162GtkWidget *
163wxRendererGTK::GetTreeWidget()
a4622f29 164{
bc13e772
VZ
165 static GtkWidget *s_tree = NULL;
166 static GtkWidget *s_window = NULL;
167
168 if ( !s_tree )
169 {
170 s_tree = gtk_tree_view_new();
171 s_window = gtk_window_new( GTK_WINDOW_POPUP );
172 gtk_widget_realize( s_window );
173 gtk_container_add( GTK_CONTAINER(s_window), s_tree );
174 gtk_widget_realize( s_tree );
175 }
176
177 return s_tree;
a4622f29
VZ
178}
179
d16cf3cd
VZ
180// ----------------------------------------------------------------------------
181// list/tree controls drawing
182// ----------------------------------------------------------------------------
183
9c7f49f5
VZ
184void
185wxRendererGTK::DrawHeaderButton(wxWindow *win,
186 wxDC& dc,
187 const wxRect& rect,
4b94ddc4 188 int flags,
80752b57 189 wxHeaderSortIconType sortArrow,
4b94ddc4 190 wxHeaderButtonParams* params)
9c7f49f5 191{
9b311923 192
bc13e772 193 GtkWidget *button = GetButtonWidget();
9b311923 194
5eefe029
RR
195 int x_diff = 0;
196 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
197 x_diff = rect.width;
198
9c7f49f5
VZ
199 gtk_paint_box
200 (
bc13e772 201 button->style,
a4622f29 202 // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC.
2209baae 203 // Maybe use code similar as in DrawPushButton below?
9c7f49f5
VZ
204 GTK_PIZZA(win->m_wxwindow)->bin_window,
205 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
206 GTK_SHADOW_OUT,
38511687 207 NULL,
bc13e772 208 button,
9b311923 209 "button",
5eefe029 210 dc.LogicalToDeviceX(rect.x) - x_diff, rect.y, rect.width, rect.height
9c7f49f5 211 );
4b94ddc4 212
80752b57 213 DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
9c7f49f5
VZ
214}
215
9c7f49f5 216// draw a ">" or "v" button
9c7f49f5 217void
f8b043e7 218wxRendererGTK::DrawTreeItemButton(wxWindow* win,
9a0b7e33 219 wxDC& dc, const wxRect& rect, int flags)
9c7f49f5 220{
bc13e772 221 GtkWidget *tree = GetTreeWidget();
f8b043e7 222
885dd597
RR
223 GtkStateType state;
224 if ( flags & wxCONTROL_CURRENT )
225 state = GTK_STATE_PRELIGHT;
226 else
227 state = GTK_STATE_NORMAL;
91af0895 228
428f4657
RR
229 int x_diff = 0;
230 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
231 x_diff = rect.width;
232
bc13e772
VZ
233 // VZ: I don't know how to get the size of the expander so as to centre it
234 // in the given rectangle, +2/3 below is just what looks good here...
235 gtk_paint_expander
236 (
237 tree->style,
238 GTK_PIZZA(win->m_wxwindow)->bin_window,
885dd597 239 state,
bc13e772
VZ
240 NULL,
241 tree,
242 "treeview",
428f4657 243 dc.LogicalToDeviceX(rect.x) + 2 - x_diff,
bc13e772
VZ
244 dc.LogicalToDeviceY(rect.y) + 3,
245 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
246 : GTK_EXPANDER_COLLAPSED
247 );
9c7f49f5
VZ
248}
249
9c7f49f5 250
d16cf3cd
VZ
251// ----------------------------------------------------------------------------
252// splitter sash drawing
253// ----------------------------------------------------------------------------
254
38418827
RR
255static int GetGtkSplitterFullSize()
256{
38418827
RR
257 static GtkWidget *s_paned = NULL;
258 if (s_paned == NULL)
259 s_paned = gtk_vpaned_new();
260
261 gint handle_size;
262 gtk_widget_style_get (s_paned, "handle_size", &handle_size, NULL);
91af0895 263
38418827 264 return handle_size;
38418827
RR
265}
266
af99040c 267wxSplitterRenderParams
38418827 268wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
d16cf3cd 269{
af99040c
VZ
270 // we don't draw any border, hence 0 for the second field
271 return wxSplitterRenderParams
272 (
38418827 273 GetGtkSplitterFullSize(),
af99040c 274 0,
af99040c 275 true // hot sensitive
af99040c 276 );
d16cf3cd
VZ
277}
278
279void
280wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
281 wxDC& WXUNUSED(dc),
af99040c
VZ
282 const wxRect& WXUNUSED(rect),
283 int WXUNUSED(flags))
d16cf3cd
VZ
284{
285 // nothing to do
286}
95155e75 287
95155e75
VZ
288void
289wxRendererGTK::DrawSplitterSash(wxWindow *win,
290 wxDC& dc,
291 const wxSize& size,
d16cf3cd 292 wxCoord position,
af99040c 293 wxOrientation orient,
68567a96 294 int flags)
95155e75
VZ
295{
296 if ( !win->m_wxwindow->window )
297 {
0100b858 298 // window not realized yet
95155e75
VZ
299 return;
300 }
91af0895 301
38418827 302 wxCoord full_size = GetGtkSplitterFullSize();
95155e75 303
d16cf3cd
VZ
304 // are we drawing vertical or horizontal splitter?
305 const bool isVert = orient == wxVERTICAL;
306
d16cf3cd 307 GdkRectangle rect;
91af0895 308
d16cf3cd
VZ
309 if ( isVert )
310 {
0100b858 311 int h = win->GetClientSize().GetHeight();
e1befae3 312
d16cf3cd 313 rect.x = position;
0100b858 314 rect.y = 0;
38418827 315 rect.width = full_size;
0100b858 316 rect.height = h;
d16cf3cd
VZ
317 }
318 else // horz
319 {
0100b858 320 int w = win->GetClientSize().GetWidth();
e1befae3 321
0100b858 322 rect.x = 0;
d16cf3cd 323 rect.y = position;
38418827 324 rect.height = full_size;
0100b858 325 rect.width = w;
d16cf3cd 326 }
847dfdb4
RR
327
328 int x_diff = 0;
329 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
330 x_diff = rect.width;
35468934 331
af99040c
VZ
332 gtk_paint_handle
333 (
334 win->m_wxwindow->style,
335 GTK_PIZZA(win->m_wxwindow)->bin_window,
336 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
337 GTK_SHADOW_NONE,
338 NULL /* no clipping */,
339 win->m_wxwindow,
340 "paned",
847dfdb4
RR
341 dc.LogicalToDeviceX(rect.x) - x_diff,
342 dc.LogicalToDeviceY(rect.y),
af99040c
VZ
343 rect.width,
344 rect.height,
38418827 345 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
af99040c 346 );
95155e75
VZ
347}
348
4c85ab75
VZ
349void
350wxRendererGTK::DrawDropArrow(wxWindow *win,
351 wxDC& dc,
352 const wxRect& rect,
353 int flags)
38511687 354{
bc13e772 355 GtkWidget *button = GetButtonWidget();
38511687 356
4c85ab75
VZ
357 // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
358 // a window for gtk_paint_xxx function, then it won't
359 // work for wxMemoryDC. So that is why we assume wxDC
360 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
361 // are derived from it) and use its m_window.
a4622f29
VZ
362 wxWindowDC& wdc = (wxWindowDC&)dc;
363
4c85ab75
VZ
364 // only doing debug-time checking here (it should
365 // probably be enough)
a4622f29
VZ
366 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
367
4c85ab75
VZ
368 // draw arrow so that there is even space horizontally
369 // on both sides
370 int arrowX = rect.width/4 + 1;
371 int arrowWidth = rect.width - (arrowX*2);
372
373 // scale arrow's height accoording to the width
374 int arrowHeight = rect.width/3;
375 int arrowY = (rect.height-arrowHeight)/2 +
376 ((rect.height-arrowHeight) & 1);
377
e1befae3 378 GtkStateType state;
a4622f29 379
3203621a
JS
380 if ( flags & wxCONTROL_PRESSED )
381 state = GTK_STATE_ACTIVE;
a4622f29
VZ
382 else if ( flags & wxCONTROL_DISABLED )
383 state = GTK_STATE_INSENSITIVE;
3203621a
JS
384 else if ( flags & wxCONTROL_CURRENT )
385 state = GTK_STATE_PRELIGHT;
e1befae3
VZ
386 else
387 state = GTK_STATE_NORMAL;
a4622f29 388
a4622f29 389 // draw arrow on button
a4622f29
VZ
390 gtk_paint_arrow
391 (
bc13e772 392 button->style,
a4622f29
VZ
393 wdc.m_window,
394 state,
e1befae3 395 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
a4622f29 396 NULL,
bc13e772 397 button,
a4622f29
VZ
398 "arrow",
399 GTK_ARROW_DOWN,
a8ac548e 400 FALSE,
4c85ab75
VZ
401 rect.x + arrowX,
402 rect.y + arrowY,
403 arrowWidth,
404 arrowHeight
a4622f29 405 );
38511687
VZ
406}
407
4c85ab75
VZ
408void
409wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
410 wxDC& dc,
411 const wxRect& rect,
412 int flags)
413{
2209baae
RR
414 DrawPushButton(win,dc,rect,flags);
415 DrawDropArrow(win,dc,rect);
416}
417
cdccdfab 418void
90b903c2
WS
419wxRendererGTK::DrawCheckBox(wxWindow *win,
420 wxDC& dc,
421 const wxRect& rect,
422 int flags )
2209baae
RR
423{
424 GtkWidget *button = GetCheckButtonWidget();
4c85ab75
VZ
425
426 // for reason why we do this, see DrawDropArrow
427 wxWindowDC& wdc = (wxWindowDC&)dc;
428 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
90b903c2 429
4c85ab75
VZ
430 GtkStateType state;
431
3203621a
JS
432 if ( flags & wxCONTROL_PRESSED )
433 state = GTK_STATE_ACTIVE;
4c85ab75
VZ
434 else if ( flags & wxCONTROL_DISABLED )
435 state = GTK_STATE_INSENSITIVE;
3203621a
JS
436 else if ( flags & wxCONTROL_CURRENT )
437 state = GTK_STATE_PRELIGHT;
4c85ab75
VZ
438 else
439 state = GTK_STATE_NORMAL;
90b903c2 440
2209baae 441 gtk_paint_check
4c85ab75
VZ
442 (
443 button->style,
444 wdc.m_window,
445 state,
2209baae 446 flags & wxCONTROL_CHECKED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
4c85ab75
VZ
447 NULL,
448 button,
2209baae 449 "cellcheck",
cdccdfab
WS
450 dc.LogicalToDeviceX(rect.x)+2,
451 dc.LogicalToDeviceY(rect.y)+3,
506d54a3 452 13, 13
4c85ab75 453 );
4c85ab75
VZ
454}
455
2209baae
RR
456void
457wxRendererGTK::DrawPushButton(wxWindow *win,
458 wxDC& dc,
459 const wxRect& rect,
460 int flags)
862d8041 461{
2209baae 462 GtkWidget *button = GetButtonWidget();
862d8041
RR
463
464 // for reason why we do this, see DrawDropArrow
465 wxWindowDC& wdc = (wxWindowDC&)dc;
466 wxASSERT ( wdc.IsKindOf(CLASSINFO(wxWindowDC)) );
2209baae
RR
467
468 // draw button
862d8041
RR
469 GtkStateType state;
470
471 if ( flags & wxCONTROL_PRESSED )
472 state = GTK_STATE_ACTIVE;
473 else if ( flags & wxCONTROL_DISABLED )
474 state = GTK_STATE_INSENSITIVE;
475 else if ( flags & wxCONTROL_CURRENT )
476 state = GTK_STATE_PRELIGHT;
477 else
478 state = GTK_STATE_NORMAL;
2209baae
RR
479
480 gtk_paint_box
862d8041
RR
481 (
482 button->style,
483 wdc.m_window,
484 state,
2209baae 485 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
862d8041
RR
486 NULL,
487 button,
2209baae
RR
488 "button",
489 rect.x, rect.y, rect.width, rect.height
862d8041
RR
490 );
491}
daebb44c 492
cdccdfab 493void
daebb44c 494wxRendererGTK::DrawItemSelectionRect(wxWindow *win,
cdccdfab
WS
495 wxDC& dc,
496 const wxRect& rect,
497 int flags )
daebb44c 498{
daebb44c 499 GtkStateType state;
90b903c2 500 if (flags & wxCONTROL_SELECTED)
daebb44c
RR
501 {
502 if (flags & wxCONTROL_FOCUSED)
90b903c2 503 state = GTK_STATE_SELECTED;
daebb44c 504 else
90b903c2 505 state = GTK_STATE_INSENSITIVE;
daebb44c
RR
506
507 gtk_paint_flat_box( win->m_wxwindow->style,
508 GTK_PIZZA(win->m_wxwindow)->bin_window,
509 state,
510 GTK_SHADOW_NONE,
cdccdfab 511 NULL,
daebb44c
RR
512 win->m_wxwindow,
513 "treeview",
514 dc.LogicalToDeviceX(rect.x),
515 dc.LogicalToDeviceY(rect.y),
516 rect.width,
517 rect.height );
518 }
90b903c2 519
daebb44c
RR
520 if (flags & wxCONTROL_CURRENT)
521 {
522 dc.SetPen( *wxBLACK_PEN );
523 dc.SetBrush( *wxTRANSPARENT_BRUSH );
524 dc.DrawRectangle( rect );
525 }
526}