1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/renderer.cpp 
   3 // Purpose:     implementation of wxRendererNative for wxGTK 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2003 Vadim Zeitlin <vadim@wxwindows.org> 
   9 // License:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // for compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #include "wx/renderer.h" 
  30     #include "wx/window.h" 
  32     #include "wx/dcclient.h" 
  33     #include "wx/settings.h" 
  37 #include "wx/gtk/win_gtk.h" 
  39 // RR: After a correction to the orientation of the sash 
  40 //     this doesn't seem to be required anymore and it 
  41 //     seems to confuse some themes so USE_ERASE_RECT=0 
  42 #define USE_ERASE_RECT 0 
  44 // ---------------------------------------------------------------------------- 
  45 // wxRendererGTK: our wxRendererNative implementation 
  46 // ---------------------------------------------------------------------------- 
  48 class WXDLLEXPORT wxRendererGTK 
: public wxDelegateRendererNative
 
  51     // draw the header control button (used by wxListCtrl) 
  52     virtual void DrawHeaderButton(wxWindow 
*win
, 
  57     // draw the expanded/collapsed icon for a tree control item 
  58     virtual void DrawTreeItemButton(wxWindow 
*win
, 
  63     virtual void DrawSplitterBorder(wxWindow 
*win
, 
  67     virtual void DrawSplitterSash(wxWindow 
*win
, 
  74     virtual void DrawComboBoxDropButton(wxWindow 
*win
, 
  79     virtual void DrawDropArrow(wxWindow 
*win
, 
  84     virtual void DrawCheckBox(wxWindow 
*win
, 
  89     virtual void DrawPushButton(wxWindow 
*win
, 
  94     virtual void DrawItemSelectionRect(wxWindow 
*win
, 
  99     virtual wxSplitterRenderParams 
GetSplitterParams(const wxWindow 
*win
); 
 102     // FIXME: shouldn't we destroy these windows somewhere? 
 104     // used by DrawHeaderButton and DrawPushButton 
 105     static GtkWidget 
*GetButtonWidget(); 
 107     // used by DrawTreeItemButton() 
 108     static GtkWidget 
*GetTreeWidget(); 
 110     // used by DrawCheckBox() 
 111     static GtkWidget 
*GetCheckButtonWidget(); 
 114 // ============================================================================ 
 116 // ============================================================================ 
 119 wxRendererNative
& wxRendererNative::GetDefault() 
 121     static wxRendererGTK s_rendererGTK
; 
 123     return s_rendererGTK
; 
 126 // ---------------------------------------------------------------------------- 
 128 // ---------------------------------------------------------------------------- 
 131 wxRendererGTK::GetButtonWidget() 
 133     static GtkWidget 
*s_button 
= NULL
; 
 134     static GtkWidget 
*s_window 
= NULL
; 
 138         s_window 
= gtk_window_new( GTK_WINDOW_POPUP 
); 
 139         gtk_widget_realize( s_window 
); 
 140         s_button 
= gtk_button_new(); 
 141         gtk_container_add( GTK_CONTAINER(s_window
), s_button 
); 
 142         gtk_widget_realize( s_button 
); 
 149 wxRendererGTK::GetCheckButtonWidget() 
 151     static GtkWidget 
*s_button 
= NULL
; 
 152     static GtkWidget 
*s_window 
= NULL
; 
 156         s_window 
= gtk_window_new( GTK_WINDOW_POPUP 
); 
 157         gtk_widget_realize( s_window 
); 
 158         s_button 
= gtk_check_button_new(); 
 159         gtk_container_add( GTK_CONTAINER(s_window
), s_button 
); 
 160         gtk_widget_realize( s_button 
); 
 167 wxRendererGTK::GetTreeWidget() 
 169     static GtkWidget 
*s_tree 
= NULL
; 
 170     static GtkWidget 
*s_window 
= NULL
; 
 174         s_tree 
= gtk_tree_view_new(); 
 175         s_window 
= gtk_window_new( GTK_WINDOW_POPUP 
); 
 176         gtk_widget_realize( s_window 
); 
 177         gtk_container_add( GTK_CONTAINER(s_window
), s_tree 
); 
 178         gtk_widget_realize( s_tree 
); 
 184 // ---------------------------------------------------------------------------- 
 185 // list/tree controls drawing 
 186 // ---------------------------------------------------------------------------- 
 189 wxRendererGTK::DrawHeaderButton(wxWindow 
*win
, 
 195     GtkWidget 
*button 
= GetButtonWidget(); 
 200         // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC. 
 201         //   Maybe use code similar as in DrawPushButton below? 
 202         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 203         flags 
& wxCONTROL_DISABLED 
? GTK_STATE_INSENSITIVE 
: GTK_STATE_NORMAL
, 
 208         dc
.XLOG2DEV(rect
.x
), rect
.y
, rect
.width
, rect
.height
 
 212 // draw a ">" or "v" button 
 214 wxRendererGTK::DrawTreeItemButton(wxWindow
* win
, 
 215                                   wxDC
& dc
, const wxRect
& rect
, int flags
) 
 217     GtkWidget 
*tree 
= GetTreeWidget(); 
 220     if ( flags 
& wxCONTROL_CURRENT 
) 
 221         state 
= GTK_STATE_PRELIGHT
; 
 223         state 
= GTK_STATE_NORMAL
; 
 225     // VZ: I don't know how to get the size of the expander so as to centre it 
 226     //     in the given rectangle, +2/3 below is just what looks good here... 
 230         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 235         dc
.LogicalToDeviceX(rect
.x
) + 2, 
 236         dc
.LogicalToDeviceY(rect
.y
) + 3, 
 237         flags 
& wxCONTROL_EXPANDED 
? GTK_EXPANDER_EXPANDED
 
 238                                    : GTK_EXPANDER_COLLAPSED
 
 243 // ---------------------------------------------------------------------------- 
 244 // splitter sash drawing 
 245 // ---------------------------------------------------------------------------- 
 247 static int GetGtkSplitterFullSize() 
 249     static GtkWidget 
*s_paned 
= NULL
; 
 251         s_paned 
= gtk_vpaned_new(); 
 254     gtk_widget_style_get (s_paned
, "handle_size", &handle_size
, NULL
); 
 259 wxSplitterRenderParams
 
 260 wxRendererGTK::GetSplitterParams(const wxWindow 
*WXUNUSED(win
)) 
 262     // we don't draw any border, hence 0 for the second field 
 263     return wxSplitterRenderParams
 
 265                GetGtkSplitterFullSize(), 
 267                true     // hot sensitive 
 272 wxRendererGTK::DrawSplitterBorder(wxWindow 
* WXUNUSED(win
), 
 274                                   const wxRect
& WXUNUSED(rect
), 
 281 wxRendererGTK::DrawSplitterSash(wxWindow 
*win
, 
 285                                 wxOrientation orient
, 
 288     if ( !win
->m_wxwindow
->window 
) 
 290         // window not realized yet 
 294     wxCoord full_size 
= GetGtkSplitterFullSize(); 
 296     // are we drawing vertical or horizontal splitter? 
 297     const bool isVert 
= orient 
== wxVERTICAL
; 
 301     GdkRectangle erase_rect
; 
 306         int h 
= win
->GetClientSize().GetHeight(); 
 310         rect
.width 
= full_size
; 
 314         erase_rect
.x 
= position
; 
 316         erase_rect
.width 
= full_size
; 
 317         erase_rect
.height 
= h
; 
 322         int w 
= win
->GetClientSize().GetWidth(); 
 326         rect
.height 
= full_size
; 
 330         erase_rect
.y 
= position
; 
 332         erase_rect
.height 
= full_size
; 
 333         erase_rect
.width 
= w
; 
 338     // we must erase everything first, otherwise the garbage 
 339     // from the old sash is left when dragging it 
 342         win
->m_wxwindow
->style
, 
 343         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 348         (char *)"viewportbin", // const_cast 
 358         win
->m_wxwindow
->style
, 
 359         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 360         flags 
& wxCONTROL_CURRENT 
? GTK_STATE_PRELIGHT 
: GTK_STATE_NORMAL
, 
 362         NULL 
/* no clipping */, 
 369         isVert 
? GTK_ORIENTATION_VERTICAL 
: GTK_ORIENTATION_HORIZONTAL
 
 374 wxRendererGTK::DrawDropArrow(wxWindow 
*win
, 
 379     GtkWidget 
*button 
= GetButtonWidget(); 
 381     // If we give GTK_PIZZA(win->m_wxwindow)->bin_window as 
 382     // a window for gtk_paint_xxx function, then it won't 
 383     // work for wxMemoryDC. So that is why we assume wxDC 
 384     // is wxWindowDC (wxClientDC, wxMemoryDC and wxPaintDC 
 385     // are derived from it) and use its m_window. 
 386     wxWindowDC
& wdc 
= (wxWindowDC
&)dc
; 
 388     // only doing debug-time checking here (it should 
 389     // probably be enough) 
 390     wxASSERT ( wdc
.IsKindOf(CLASSINFO(wxWindowDC
)) ); 
 392     // draw arrow so that there is even space horizontally 
 394     int arrowX 
= rect
.width
/4 + 1; 
 395     int arrowWidth 
= rect
.width 
- (arrowX
*2); 
 397     // scale arrow's height accoording to the width 
 398     int arrowHeight 
= rect
.width
/3; 
 399     int arrowY 
= (rect
.height
-arrowHeight
)/2 + 
 400                  ((rect
.height
-arrowHeight
) & 1); 
 404     if ( flags 
& wxCONTROL_PRESSED 
) 
 405         state 
= GTK_STATE_ACTIVE
; 
 406     else if ( flags 
& wxCONTROL_DISABLED 
) 
 407         state 
= GTK_STATE_INSENSITIVE
; 
 408     else if ( flags 
& wxCONTROL_CURRENT 
) 
 409         state 
= GTK_STATE_PRELIGHT
; 
 411         state 
= GTK_STATE_NORMAL
; 
 413     // draw arrow on button 
 419         flags 
& wxCONTROL_PRESSED 
? GTK_SHADOW_IN 
: GTK_SHADOW_OUT
, 
 433 wxRendererGTK::DrawComboBoxDropButton(wxWindow 
*win
, 
 438     DrawPushButton(win
,dc
,rect
,flags
); 
 439     DrawDropArrow(win
,dc
,rect
); 
 443 wxRendererGTK::DrawCheckBox(wxWindow 
*win
, 
 448     GtkWidget 
*button 
= GetCheckButtonWidget(); 
 450     // for reason why we do this, see DrawDropArrow 
 451     wxWindowDC
& wdc 
= (wxWindowDC
&)dc
; 
 452     wxASSERT ( wdc
.IsKindOf(CLASSINFO(wxWindowDC
)) ); 
 456     if ( flags 
& wxCONTROL_PRESSED 
) 
 457         state 
= GTK_STATE_ACTIVE
; 
 458     else if ( flags 
& wxCONTROL_DISABLED 
) 
 459         state 
= GTK_STATE_INSENSITIVE
; 
 460     else if ( flags 
& wxCONTROL_CURRENT 
) 
 461         state 
= GTK_STATE_PRELIGHT
; 
 463         state 
= GTK_STATE_NORMAL
; 
 470         flags 
& wxCONTROL_CHECKED 
? GTK_SHADOW_IN 
: GTK_SHADOW_OUT
, 
 474         dc
.LogicalToDeviceX(rect
.x
)+2, 
 475         dc
.LogicalToDeviceY(rect
.y
)+3, 
 481 wxRendererGTK::DrawPushButton(wxWindow 
*win
, 
 486     GtkWidget 
*button 
= GetButtonWidget(); 
 488     // for reason why we do this, see DrawDropArrow 
 489     wxWindowDC
& wdc 
= (wxWindowDC
&)dc
; 
 490     wxASSERT ( wdc
.IsKindOf(CLASSINFO(wxWindowDC
)) ); 
 495     if ( flags 
& wxCONTROL_PRESSED 
) 
 496         state 
= GTK_STATE_ACTIVE
; 
 497     else if ( flags 
& wxCONTROL_DISABLED 
) 
 498         state 
= GTK_STATE_INSENSITIVE
; 
 499     else if ( flags 
& wxCONTROL_CURRENT 
) 
 500         state 
= GTK_STATE_PRELIGHT
; 
 502         state 
= GTK_STATE_NORMAL
; 
 509         flags 
& wxCONTROL_PRESSED 
? GTK_SHADOW_IN 
: GTK_SHADOW_OUT
, 
 513         rect
.x
, rect
.y
, rect
.width
, rect
.height
 
 518 wxRendererGTK::DrawItemSelectionRect(wxWindow 
*win
, 
 523     // for reason why we do this, see DrawDropArrow 
 524     wxWindowDC
& wdc 
= (wxWindowDC
&)dc
; 
 525     wxASSERT ( wdc
.IsKindOf(CLASSINFO(wxWindowDC
)) ); 
 528     if (flags 
& wxCONTROL_SELECTED
) 
 530         if (flags 
& wxCONTROL_FOCUSED
) 
 531             state 
= GTK_STATE_SELECTED
; 
 533             state 
= GTK_STATE_INSENSITIVE
; 
 535         gtk_paint_flat_box( win
->m_wxwindow
->style
, 
 536                         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 542                         dc
.LogicalToDeviceX(rect
.x
), 
 543                         dc
.LogicalToDeviceY(rect
.y
), 
 548     if (flags 
& wxCONTROL_CURRENT
) 
 550         dc
.SetPen( *wxBLACK_PEN 
); 
 551         dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
 552         dc
.DrawRectangle( rect 
);