]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/renderer.cpp
Rearrange code to fix some problems
[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)
c97c9952 46 virtual int DrawHeaderButton(wxWindow *win,
9c7f49f5
VZ
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
6d789987
JS
95 virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
96
af99040c 97 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
e1befae3
VZ
98
99private:
bc13e772
VZ
100 // FIXME: shouldn't we destroy these windows somewhere?
101
621ed8af 102 // used by DrawPushButton and DrawDropArrow
bc13e772
VZ
103 static GtkWidget *GetButtonWidget();
104
bc13e772
VZ
105 // used by DrawTreeItemButton()
106 static GtkWidget *GetTreeWidget();
90b903c2
WS
107
108 // used by DrawCheckBox()
862d8041 109 static GtkWidget *GetCheckButtonWidget();
621ed8af
RD
110
111 // Used by DrawHeaderButton
112 static GtkWidget *GetHeaderButtonWidget();
9c7f49f5
VZ
113};
114
115// ============================================================================
116// implementation
117// ============================================================================
118
119/* static */
f0244295 120wxRendererNative& wxRendererNative::GetDefault()
9c7f49f5
VZ
121{
122 static wxRendererGTK s_rendererGTK;
123
124 return s_rendererGTK;
125}
126
a4622f29 127// ----------------------------------------------------------------------------
bc13e772 128// helper functions
a4622f29
VZ
129// ----------------------------------------------------------------------------
130
bc13e772
VZ
131GtkWidget *
132wxRendererGTK::GetButtonWidget()
133{
134 static GtkWidget *s_button = NULL;
135 static GtkWidget *s_window = NULL;
a4622f29 136
bc13e772
VZ
137 if ( !s_button )
138 {
139 s_window = gtk_window_new( GTK_WINDOW_POPUP );
140 gtk_widget_realize( s_window );
141 s_button = gtk_button_new();
142 gtk_container_add( GTK_CONTAINER(s_window), s_button );
143 gtk_widget_realize( s_button );
144 }
145
146 return s_button;
147}
148
862d8041
RR
149GtkWidget *
150wxRendererGTK::GetCheckButtonWidget()
151{
152 static GtkWidget *s_button = NULL;
153 static GtkWidget *s_window = NULL;
154
155 if ( !s_button )
156 {
157 s_window = gtk_window_new( GTK_WINDOW_POPUP );
158 gtk_widget_realize( s_window );
159 s_button = gtk_check_button_new();
160 gtk_container_add( GTK_CONTAINER(s_window), s_button );
161 gtk_widget_realize( s_button );
162 }
163
164 return s_button;
165}
166
bc13e772
VZ
167GtkWidget *
168wxRendererGTK::GetTreeWidget()
a4622f29 169{
bc13e772
VZ
170 static GtkWidget *s_tree = NULL;
171 static GtkWidget *s_window = NULL;
172
173 if ( !s_tree )
174 {
175 s_tree = gtk_tree_view_new();
176 s_window = gtk_window_new( GTK_WINDOW_POPUP );
177 gtk_widget_realize( s_window );
178 gtk_container_add( GTK_CONTAINER(s_window), s_tree );
179 gtk_widget_realize( s_tree );
180 }
181
182 return s_tree;
a4622f29
VZ
183}
184
621ed8af 185
c7a757aa
RD
186// This one just gets the button used by the column header. Although it's
187// still a gtk_button the themes will typically differentiate and draw them
188// differently if the button is in a treeview.
621ed8af
RD
189GtkWidget *
190wxRendererGTK::GetHeaderButtonWidget()
191{
192 static GtkWidget *s_button = NULL;
6d789987 193
621ed8af
RD
194 if ( !s_button )
195 {
c7a757aa
RD
196 // Get the dummy tree widget, give it a column, and then use the
197 // widget in the column header for the rendering code.
621ed8af 198 GtkWidget* treewidget = GetTreeWidget();
c7a757aa
RD
199 GtkTreeViewColumn* column = gtk_tree_view_column_new();
200 gtk_tree_view_append_column(GTK_TREE_VIEW(treewidget), column);
201 s_button = column->button;
621ed8af
RD
202 }
203
204 return s_button;
205}
206
d16cf3cd
VZ
207// ----------------------------------------------------------------------------
208// list/tree controls drawing
209// ----------------------------------------------------------------------------
210
c97c9952 211int
9c7f49f5
VZ
212wxRendererGTK::DrawHeaderButton(wxWindow *win,
213 wxDC& dc,
214 const wxRect& rect,
4b94ddc4 215 int flags,
80752b57 216 wxHeaderSortIconType sortArrow,
4b94ddc4 217 wxHeaderButtonParams* params)
9c7f49f5 218{
9b311923 219
621ed8af 220 GtkWidget *button = GetHeaderButtonWidget();
6d789987 221
2e992e06
VZ
222 GdkWindow* gdk_window = dc.GetGDKWindow();
223 wxASSERT_MSG( gdk_window,
224 wxT("cannot use wxRendererNative on wxDC of this type") );
225
5eefe029
RR
226 int x_diff = 0;
227 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
228 x_diff = rect.width;
f4322df6 229
9c7f49f5
VZ
230 gtk_paint_box
231 (
bc13e772 232 button->style,
2e992e06 233 gdk_window,
9c7f49f5
VZ
234 flags & wxCONTROL_DISABLED ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL,
235 GTK_SHADOW_OUT,
38511687 236 NULL,
bc13e772 237 button,
9b311923 238 "button",
5eefe029 239 dc.LogicalToDeviceX(rect.x) - x_diff, rect.y, rect.width, rect.height
9c7f49f5 240 );
4b94ddc4 241
c97c9952 242 return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
9c7f49f5
VZ
243}
244
9c7f49f5 245// draw a ">" or "v" button
9c7f49f5 246void
f8b043e7 247wxRendererGTK::DrawTreeItemButton(wxWindow* win,
9a0b7e33 248 wxDC& dc, const wxRect& rect, int flags)
9c7f49f5 249{
bc13e772 250 GtkWidget *tree = GetTreeWidget();
f8b043e7 251
2e992e06
VZ
252 GdkWindow* gdk_window = dc.GetGDKWindow();
253 wxASSERT_MSG( gdk_window,
254 wxT("cannot use wxRendererNative on wxDC of this type") );
255
885dd597
RR
256 GtkStateType state;
257 if ( flags & wxCONTROL_CURRENT )
258 state = GTK_STATE_PRELIGHT;
259 else
260 state = GTK_STATE_NORMAL;
91af0895 261
428f4657
RR
262 int x_diff = 0;
263 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
264 x_diff = rect.width;
2e992e06 265
bc13e772
VZ
266 // VZ: I don't know how to get the size of the expander so as to centre it
267 // in the given rectangle, +2/3 below is just what looks good here...
268 gtk_paint_expander
269 (
270 tree->style,
2e992e06 271 gdk_window,
885dd597 272 state,
bc13e772
VZ
273 NULL,
274 tree,
275 "treeview",
11012f47 276 dc.LogicalToDeviceX(rect.x) + 6 - x_diff,
bc13e772
VZ
277 dc.LogicalToDeviceY(rect.y) + 3,
278 flags & wxCONTROL_EXPANDED ? GTK_EXPANDER_EXPANDED
279 : GTK_EXPANDER_COLLAPSED
280 );
9c7f49f5
VZ
281}
282
9c7f49f5 283
d16cf3cd
VZ
284// ----------------------------------------------------------------------------
285// splitter sash drawing
286// ----------------------------------------------------------------------------
287
38418827
RR
288static int GetGtkSplitterFullSize()
289{
38418827
RR
290 static GtkWidget *s_paned = NULL;
291 if (s_paned == NULL)
292 s_paned = gtk_vpaned_new();
293
294 gint handle_size;
295 gtk_widget_style_get (s_paned, "handle_size", &handle_size, NULL);
91af0895 296
38418827 297 return handle_size;
38418827
RR
298}
299
af99040c 300wxSplitterRenderParams
38418827 301wxRendererGTK::GetSplitterParams(const wxWindow *WXUNUSED(win))
d16cf3cd 302{
af99040c
VZ
303 // we don't draw any border, hence 0 for the second field
304 return wxSplitterRenderParams
305 (
38418827 306 GetGtkSplitterFullSize(),
af99040c 307 0,
af99040c 308 true // hot sensitive
af99040c 309 );
d16cf3cd
VZ
310}
311
312void
313wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win),
314 wxDC& WXUNUSED(dc),
af99040c
VZ
315 const wxRect& WXUNUSED(rect),
316 int WXUNUSED(flags))
d16cf3cd
VZ
317{
318 // nothing to do
319}
95155e75 320
95155e75
VZ
321void
322wxRendererGTK::DrawSplitterSash(wxWindow *win,
323 wxDC& dc,
324 const wxSize& size,
d16cf3cd 325 wxCoord position,
af99040c 326 wxOrientation orient,
68567a96 327 int flags)
95155e75
VZ
328{
329 if ( !win->m_wxwindow->window )
330 {
0100b858 331 // window not realized yet
95155e75
VZ
332 return;
333 }
91af0895 334
2e992e06
VZ
335 GdkWindow* gdk_window = dc.GetGDKWindow();
336 wxASSERT_MSG( gdk_window,
337 wxT("cannot use wxRendererNative on wxDC of this type") );
338
38418827 339 wxCoord full_size = GetGtkSplitterFullSize();
95155e75 340
d16cf3cd
VZ
341 // are we drawing vertical or horizontal splitter?
342 const bool isVert = orient == wxVERTICAL;
343
d16cf3cd 344 GdkRectangle rect;
91af0895 345
d16cf3cd
VZ
346 if ( isVert )
347 {
0100b858 348 int h = win->GetClientSize().GetHeight();
e1befae3 349
d16cf3cd 350 rect.x = position;
0100b858 351 rect.y = 0;
38418827 352 rect.width = full_size;
0100b858 353 rect.height = h;
d16cf3cd
VZ
354 }
355 else // horz
356 {
0100b858 357 int w = win->GetClientSize().GetWidth();
e1befae3 358
0100b858 359 rect.x = 0;
d16cf3cd 360 rect.y = position;
38418827 361 rect.height = full_size;
0100b858 362 rect.width = w;
d16cf3cd 363 }
f4322df6 364
847dfdb4
RR
365 int x_diff = 0;
366 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
367 x_diff = rect.width;
35468934 368
af99040c
VZ
369 gtk_paint_handle
370 (
371 win->m_wxwindow->style,
2e992e06 372 gdk_window,
af99040c
VZ
373 flags & wxCONTROL_CURRENT ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
374 GTK_SHADOW_NONE,
375 NULL /* no clipping */,
376 win->m_wxwindow,
377 "paned",
847dfdb4
RR
378 dc.LogicalToDeviceX(rect.x) - x_diff,
379 dc.LogicalToDeviceY(rect.y),
af99040c
VZ
380 rect.width,
381 rect.height,
38418827 382 isVert ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL
af99040c 383 );
95155e75
VZ
384}
385
4c85ab75 386void
2e992e06 387wxRendererGTK::DrawDropArrow(wxWindow *WXUNUSED(win),
4c85ab75
VZ
388 wxDC& dc,
389 const wxRect& rect,
390 int flags)
38511687 391{
bc13e772 392 GtkWidget *button = GetButtonWidget();
38511687 393
4c85ab75
VZ
394 // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as
395 // a window for gtk_paint_xxx function, then it won't
396 // work for wxMemoryDC. So that is why we assume wxDC
397 // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC
398 // are derived from it) and use its m_window.
2e992e06
VZ
399 GdkWindow* gdk_window = dc.GetGDKWindow();
400 wxASSERT_MSG( gdk_window,
401 wxT("cannot use wxRendererNative on wxDC of this type") );
a4622f29 402
4c85ab75
VZ
403 // draw arrow so that there is even space horizontally
404 // on both sides
405 int arrowX = rect.width/4 + 1;
406 int arrowWidth = rect.width - (arrowX*2);
407
408 // scale arrow's height accoording to the width
409 int arrowHeight = rect.width/3;
410 int arrowY = (rect.height-arrowHeight)/2 +
411 ((rect.height-arrowHeight) & 1);
412
e1befae3 413 GtkStateType state;
a4622f29 414
3203621a
JS
415 if ( flags & wxCONTROL_PRESSED )
416 state = GTK_STATE_ACTIVE;
a4622f29
VZ
417 else if ( flags & wxCONTROL_DISABLED )
418 state = GTK_STATE_INSENSITIVE;
3203621a
JS
419 else if ( flags & wxCONTROL_CURRENT )
420 state = GTK_STATE_PRELIGHT;
e1befae3
VZ
421 else
422 state = GTK_STATE_NORMAL;
a4622f29 423
a4622f29 424 // draw arrow on button
a4622f29
VZ
425 gtk_paint_arrow
426 (
bc13e772 427 button->style,
2e992e06 428 gdk_window,
a4622f29 429 state,
e1befae3 430 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
a4622f29 431 NULL,
bc13e772 432 button,
a4622f29
VZ
433 "arrow",
434 GTK_ARROW_DOWN,
a8ac548e 435 FALSE,
4c85ab75
VZ
436 rect.x + arrowX,
437 rect.y + arrowY,
438 arrowWidth,
439 arrowHeight
a4622f29 440 );
38511687
VZ
441}
442
4c85ab75
VZ
443void
444wxRendererGTK::DrawComboBoxDropButton(wxWindow *win,
445 wxDC& dc,
446 const wxRect& rect,
447 int flags)
448{
2209baae
RR
449 DrawPushButton(win,dc,rect,flags);
450 DrawDropArrow(win,dc,rect);
451}
452
cdccdfab 453void
2e992e06 454wxRendererGTK::DrawCheckBox(wxWindow *WXUNUSED(win),
90b903c2
WS
455 wxDC& dc,
456 const wxRect& rect,
457 int flags )
2209baae
RR
458{
459 GtkWidget *button = GetCheckButtonWidget();
4c85ab75
VZ
460
461 // for reason why we do this, see DrawDropArrow
2e992e06
VZ
462 GdkWindow* gdk_window = dc.GetGDKWindow();
463 wxASSERT_MSG( gdk_window,
464 wxT("cannot use wxRendererNative on wxDC of this type") );
90b903c2 465
4c85ab75
VZ
466 GtkStateType state;
467
3203621a
JS
468 if ( flags & wxCONTROL_PRESSED )
469 state = GTK_STATE_ACTIVE;
4c85ab75
VZ
470 else if ( flags & wxCONTROL_DISABLED )
471 state = GTK_STATE_INSENSITIVE;
3203621a
JS
472 else if ( flags & wxCONTROL_CURRENT )
473 state = GTK_STATE_PRELIGHT;
4c85ab75
VZ
474 else
475 state = GTK_STATE_NORMAL;
90b903c2 476
2209baae 477 gtk_paint_check
4c85ab75
VZ
478 (
479 button->style,
2e992e06 480 gdk_window,
4c85ab75 481 state,
2209baae 482 flags & wxCONTROL_CHECKED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
4c85ab75
VZ
483 NULL,
484 button,
2209baae 485 "cellcheck",
cdccdfab
WS
486 dc.LogicalToDeviceX(rect.x)+2,
487 dc.LogicalToDeviceY(rect.y)+3,
506d54a3 488 13, 13
4c85ab75 489 );
4c85ab75
VZ
490}
491
2209baae 492void
2e992e06 493wxRendererGTK::DrawPushButton(wxWindow *WXUNUSED(win),
2209baae
RR
494 wxDC& dc,
495 const wxRect& rect,
496 int flags)
862d8041 497{
2209baae 498 GtkWidget *button = GetButtonWidget();
862d8041
RR
499
500 // for reason why we do this, see DrawDropArrow
2e992e06
VZ
501 GdkWindow* gdk_window = dc.GetGDKWindow();
502 wxASSERT_MSG( gdk_window,
503 wxT("cannot use wxRendererNative on wxDC of this type") );
2209baae
RR
504
505 // draw button
862d8041
RR
506 GtkStateType state;
507
508 if ( flags & wxCONTROL_PRESSED )
509 state = GTK_STATE_ACTIVE;
510 else if ( flags & wxCONTROL_DISABLED )
511 state = GTK_STATE_INSENSITIVE;
512 else if ( flags & wxCONTROL_CURRENT )
513 state = GTK_STATE_PRELIGHT;
514 else
515 state = GTK_STATE_NORMAL;
2209baae
RR
516
517 gtk_paint_box
862d8041
RR
518 (
519 button->style,
2e992e06 520 gdk_window,
862d8041 521 state,
2209baae 522 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
862d8041
RR
523 NULL,
524 button,
2209baae
RR
525 "button",
526 rect.x, rect.y, rect.width, rect.height
862d8041
RR
527 );
528}
daebb44c 529
cdccdfab 530void
daebb44c 531wxRendererGTK::DrawItemSelectionRect(wxWindow *win,
cdccdfab
WS
532 wxDC& dc,
533 const wxRect& rect,
534 int flags )
daebb44c 535{
2e992e06
VZ
536 GdkWindow* gdk_window = dc.GetGDKWindow();
537 wxASSERT_MSG( gdk_window,
538 wxT("cannot use wxRendererNative on wxDC of this type") );
539
08f57d21
RR
540 int x_diff = 0;
541 if (win->GetLayoutDirection() == wxLayout_RightToLeft)
542 x_diff = rect.width;
543
daebb44c 544 GtkStateType state;
90b903c2 545 if (flags & wxCONTROL_SELECTED)
daebb44c 546 {
05d97538
RR
547 // the wxCONTROL_FOCUSED state is deduced
548 // directly from the m_wxwindow by GTK+
549 state = GTK_STATE_SELECTED;
daebb44c 550
05d97538 551 gtk_paint_flat_box( win->m_widget->style,
2e992e06 552 gdk_window,
daebb44c
RR
553 state,
554 GTK_SHADOW_NONE,
cdccdfab 555 NULL,
daebb44c 556 win->m_wxwindow,
05d97538 557 "cell_even",
08f57d21 558 dc.LogicalToDeviceX(rect.x) - x_diff,
daebb44c
RR
559 dc.LogicalToDeviceY(rect.y),
560 rect.width,
561 rect.height );
562 }
72be9a3a
VZ
563 else // !wxCONTROL_SELECTED
564 {
565 state = GTK_STATE_NORMAL;
566 }
90b903c2 567
daebb44c
RR
568 if (flags & wxCONTROL_CURRENT)
569 {
f4322df6 570 gtk_paint_focus( win->m_widget->style,
05d97538 571 gdk_window,
72be9a3a 572 state,
05d97538
RR
573 NULL,
574 win->m_wxwindow,
575 "treeview",
576 dc.LogicalToDeviceX(rect.x),
577 dc.LogicalToDeviceY(rect.y),
578 rect.width,
579 rect.height );
daebb44c
RR
580 }
581}
6d789987
JS
582
583void wxRendererGTK::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
584{
585 GdkWindow* gdk_window = dc.GetGDKWindow();
586 wxASSERT_MSG( gdk_window,
587 wxT("cannot use wxRendererNative on wxDC of this type") );
588
589 GtkStateType state;
590 if (flags & wxCONTROL_SELECTED)
591 state = GTK_STATE_SELECTED;
592 else
593 state = GTK_STATE_NORMAL;
594
595 gtk_paint_focus( win->m_widget->style,
596 gdk_window,
597 state,
598 NULL,
599 win->m_wxwindow,
600 NULL,
601 dc.LogicalToDeviceX(rect.x),
602 dc.LogicalToDeviceY(rect.y),
603 rect.width,
604 rect.height );
605}