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" 
  31     #include "wx/dcclient.h" 
  32     #include "wx/settings.h" 
  36 #include "wx/gtk/win_gtk.h" 
  38 // ---------------------------------------------------------------------------- 
  39 // wxRendererGTK: our wxRendererNative implementation 
  40 // ---------------------------------------------------------------------------- 
  42 class WXDLLEXPORT wxRendererGTK 
: public wxDelegateRendererNative
 
  45     // draw the header control button (used by wxListCtrl) 
  46     virtual void DrawHeaderButton(wxWindow 
*win
, 
  50                                   wxHeaderSortIconType sortArrow 
= wxHDR_SORT_ICON_NONE
, 
  51                                   wxHeaderButtonParams
* params 
= NULL
); 
  53     // draw the expanded/collapsed icon for a tree control item 
  54     virtual void DrawTreeItemButton(wxWindow 
*win
, 
  59     virtual void DrawSplitterBorder(wxWindow 
*win
, 
  63     virtual void DrawSplitterSash(wxWindow 
*win
, 
  70     virtual void DrawComboBoxDropButton(wxWindow 
*win
, 
  75     virtual void DrawDropArrow(wxWindow 
*win
, 
  80     virtual void DrawCheckBox(wxWindow 
*win
, 
  85     virtual void DrawPushButton(wxWindow 
*win
, 
  90     virtual void DrawItemSelectionRect(wxWindow 
*win
, 
  95     virtual wxSplitterRenderParams 
GetSplitterParams(const wxWindow 
*win
); 
  98     // FIXME: shouldn't we destroy these windows somewhere? 
 100     // used by DrawHeaderButton and DrawPushButton 
 101     static GtkWidget 
*GetButtonWidget(); 
 103     // used by DrawTreeItemButton() 
 104     static GtkWidget 
*GetTreeWidget(); 
 106     // used by DrawCheckBox() 
 107     static GtkWidget 
*GetCheckButtonWidget(); 
 110 // ============================================================================ 
 112 // ============================================================================ 
 115 wxRendererNative
& wxRendererNative::GetDefault() 
 117     static wxRendererGTK s_rendererGTK
; 
 119     return s_rendererGTK
; 
 122 // ---------------------------------------------------------------------------- 
 124 // ---------------------------------------------------------------------------- 
 127 wxRendererGTK::GetButtonWidget() 
 129     static GtkWidget 
*s_button 
= NULL
; 
 130     static GtkWidget 
*s_window 
= NULL
; 
 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 
); 
 145 wxRendererGTK::GetCheckButtonWidget() 
 147     static GtkWidget 
*s_button 
= NULL
; 
 148     static GtkWidget 
*s_window 
= NULL
; 
 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 
); 
 163 wxRendererGTK::GetTreeWidget() 
 165     static GtkWidget 
*s_tree 
= NULL
; 
 166     static GtkWidget 
*s_window 
= NULL
; 
 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 
); 
 180 // ---------------------------------------------------------------------------- 
 181 // list/tree controls drawing 
 182 // ---------------------------------------------------------------------------- 
 185 wxRendererGTK::DrawHeaderButton(wxWindow 
*win
, 
 189                                 wxHeaderSortIconType sortArrow
, 
 190                                 wxHeaderButtonParams
* params
) 
 193     GtkWidget 
*button 
= GetButtonWidget(); 
 196     if (win
->GetLayoutDirection() == wxLayout_RightToLeft
) 
 202         // FIXME: I suppose GTK_PIZZA(win->m_wxwindow)->bin_window doesn't work with wxMemoryDC. 
 203         //   Maybe use code similar as in DrawPushButton below? 
 204         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 205         flags 
& wxCONTROL_DISABLED 
? GTK_STATE_INSENSITIVE 
: GTK_STATE_NORMAL
, 
 210         dc
.LogicalToDeviceX(rect
.x
) - x_diff
, rect
.y
, rect
.width
, rect
.height
 
 213     DrawHeaderButtonContents(win
, dc
, rect
, flags
, sortArrow
, params
); 
 216 // draw a ">" or "v" button 
 218 wxRendererGTK::DrawTreeItemButton(wxWindow
* win
, 
 219                                   wxDC
& dc
, const wxRect
& rect
, int flags
) 
 221     GtkWidget 
*tree 
= GetTreeWidget(); 
 224     if ( flags 
& wxCONTROL_CURRENT 
) 
 225         state 
= GTK_STATE_PRELIGHT
; 
 227         state 
= GTK_STATE_NORMAL
; 
 230     if (win
->GetLayoutDirection() == wxLayout_RightToLeft
) 
 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... 
 238         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 243         dc
.LogicalToDeviceX(rect
.x
) + 2 - x_diff
, 
 244         dc
.LogicalToDeviceY(rect
.y
) + 3, 
 245         flags 
& wxCONTROL_EXPANDED 
? GTK_EXPANDER_EXPANDED
 
 246                                    : GTK_EXPANDER_COLLAPSED
 
 251 // ---------------------------------------------------------------------------- 
 252 // splitter sash drawing 
 253 // ---------------------------------------------------------------------------- 
 255 static int GetGtkSplitterFullSize() 
 257     static GtkWidget 
*s_paned 
= NULL
; 
 259         s_paned 
= gtk_vpaned_new(); 
 262     gtk_widget_style_get (s_paned
, "handle_size", &handle_size
, NULL
); 
 267 wxSplitterRenderParams
 
 268 wxRendererGTK::GetSplitterParams(const wxWindow 
*WXUNUSED(win
)) 
 270     // we don't draw any border, hence 0 for the second field 
 271     return wxSplitterRenderParams
 
 273                GetGtkSplitterFullSize(), 
 275                true     // hot sensitive 
 280 wxRendererGTK::DrawSplitterBorder(wxWindow 
* WXUNUSED(win
), 
 282                                   const wxRect
& WXUNUSED(rect
), 
 289 wxRendererGTK::DrawSplitterSash(wxWindow 
*win
, 
 293                                 wxOrientation orient
, 
 296     if ( !win
->m_wxwindow
->window 
) 
 298         // window not realized yet 
 302     wxCoord full_size 
= GetGtkSplitterFullSize(); 
 304     // are we drawing vertical or horizontal splitter? 
 305     const bool isVert 
= orient 
== wxVERTICAL
; 
 311         int h 
= win
->GetClientSize().GetHeight(); 
 315         rect
.width 
= full_size
; 
 320         int w 
= win
->GetClientSize().GetWidth(); 
 324         rect
.height 
= full_size
; 
 329     if (win
->GetLayoutDirection() == wxLayout_RightToLeft
) 
 334         win
->m_wxwindow
->style
, 
 335         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 336         flags 
& wxCONTROL_CURRENT 
? GTK_STATE_PRELIGHT 
: GTK_STATE_NORMAL
, 
 338         NULL 
/* no clipping */, 
 341         dc
.LogicalToDeviceX(rect
.x
) - x_diff
, 
 342         dc
.LogicalToDeviceY(rect
.y
), 
 345         isVert 
? GTK_ORIENTATION_VERTICAL 
: GTK_ORIENTATION_HORIZONTAL
 
 350 wxRendererGTK::DrawDropArrow(wxWindow 
*win
, 
 355     GtkWidget 
*button 
= GetButtonWidget(); 
 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. 
 362     wxWindowDC
& wdc 
= (wxWindowDC
&)dc
; 
 364     // only doing debug-time checking here (it should 
 365     // probably be enough) 
 366     wxASSERT ( wdc
.IsKindOf(CLASSINFO(wxWindowDC
)) ); 
 368     // draw arrow so that there is even space horizontally 
 370     int arrowX 
= rect
.width
/4 + 1; 
 371     int arrowWidth 
= rect
.width 
- (arrowX
*2); 
 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); 
 380     if ( flags 
& wxCONTROL_PRESSED 
) 
 381         state 
= GTK_STATE_ACTIVE
; 
 382     else if ( flags 
& wxCONTROL_DISABLED 
) 
 383         state 
= GTK_STATE_INSENSITIVE
; 
 384     else if ( flags 
& wxCONTROL_CURRENT 
) 
 385         state 
= GTK_STATE_PRELIGHT
; 
 387         state 
= GTK_STATE_NORMAL
; 
 389     // draw arrow on button 
 395         flags 
& wxCONTROL_PRESSED 
? GTK_SHADOW_IN 
: GTK_SHADOW_OUT
, 
 409 wxRendererGTK::DrawComboBoxDropButton(wxWindow 
*win
, 
 414     DrawPushButton(win
,dc
,rect
,flags
); 
 415     DrawDropArrow(win
,dc
,rect
); 
 419 wxRendererGTK::DrawCheckBox(wxWindow 
*win
, 
 424     GtkWidget 
*button 
= GetCheckButtonWidget(); 
 426     // for reason why we do this, see DrawDropArrow 
 427     wxWindowDC
& wdc 
= (wxWindowDC
&)dc
; 
 428     wxASSERT ( wdc
.IsKindOf(CLASSINFO(wxWindowDC
)) ); 
 432     if ( flags 
& wxCONTROL_PRESSED 
) 
 433         state 
= GTK_STATE_ACTIVE
; 
 434     else if ( flags 
& wxCONTROL_DISABLED 
) 
 435         state 
= GTK_STATE_INSENSITIVE
; 
 436     else if ( flags 
& wxCONTROL_CURRENT 
) 
 437         state 
= GTK_STATE_PRELIGHT
; 
 439         state 
= GTK_STATE_NORMAL
; 
 446         flags 
& wxCONTROL_CHECKED 
? GTK_SHADOW_IN 
: GTK_SHADOW_OUT
, 
 450         dc
.LogicalToDeviceX(rect
.x
)+2, 
 451         dc
.LogicalToDeviceY(rect
.y
)+3, 
 457 wxRendererGTK::DrawPushButton(wxWindow 
*win
, 
 462     GtkWidget 
*button 
= GetButtonWidget(); 
 464     // for reason why we do this, see DrawDropArrow 
 465     wxWindowDC
& wdc 
= (wxWindowDC
&)dc
; 
 466     wxASSERT ( wdc
.IsKindOf(CLASSINFO(wxWindowDC
)) ); 
 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
; 
 478         state 
= GTK_STATE_NORMAL
; 
 485         flags 
& wxCONTROL_PRESSED 
? GTK_SHADOW_IN 
: GTK_SHADOW_OUT
, 
 489         rect
.x
, rect
.y
, rect
.width
, rect
.height
 
 494 wxRendererGTK::DrawItemSelectionRect(wxWindow 
*win
, 
 500     if (flags 
& wxCONTROL_SELECTED
) 
 502         if (flags 
& wxCONTROL_FOCUSED
) 
 503             state 
= GTK_STATE_SELECTED
; 
 505             state 
= GTK_STATE_INSENSITIVE
; 
 507         gtk_paint_flat_box( win
->m_wxwindow
->style
, 
 508                         GTK_PIZZA(win
->m_wxwindow
)->bin_window
, 
 514                         dc
.LogicalToDeviceX(rect
.x
), 
 515                         dc
.LogicalToDeviceY(rect
.y
), 
 520     if (flags 
& wxCONTROL_CURRENT
) 
 522         dc
.SetPen( *wxBLACK_PEN 
); 
 523         dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
 524         dc
.DrawRectangle( rect 
);