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: renderer.cpp 41810 2006-10-09 16:39:34Z VZ $ 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 47class WXDLLEXPORT wxRendererGTK : public wxDelegateRendererNative 48{ 49public: 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 79private: 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 */ 91wxRendererNative& wxRendererNative::GetDefault() 92{ 93 static wxRendererGTK s_rendererGTK; 94 95 return s_rendererGTK; 96} 97 98// ---------------------------------------------------------------------------- 99// helper functions 100// ---------------------------------------------------------------------------- 101 102GtkWidget * 103wxRendererGTK::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 124void 125wxRendererGTK::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) 153static const wxCoord SASH_SIZE = 8; 154 155// margin around the sash 156static const wxCoord SASH_MARGIN = 2; 157 158static int GetGtkSplitterFullSize() 159{ 160 return SASH_SIZE + SASH_MARGIN; 161} 162 163wxSplitterRenderParams 164wxRendererGTK::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 175void 176wxRendererGTK::DrawSplitterBorder(wxWindow * WXUNUSED(win), 177 wxDC& WXUNUSED(dc), 178 const wxRect& WXUNUSED(rect), 179 int WXUNUSED(flags)) 180{ 181 // nothing to do 182} 183 184void 185wxRendererGTK::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 299void 300wxRendererGTK::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 GdkWindow* gdk_window = dc.GetGDKWindow(); 313 wxASSERT_MSG( gdk_window, 314 wxT("cannot use wxRendererNative on wxDC of this type") ); 315 316 // draw arrow so that there is even space horizontally 317 // on both sides 318 int arrowX = rect.width/4 + 1; 319 int arrowWidth = rect.width - (arrowX*2); 320 321 // scale arrow's height accoording to the width 322 int arrowHeight = rect.width/3; 323 int arrowY = (rect.height-arrowHeight)/2 + 324 ((rect.height-arrowHeight) & 1); 325 326 GtkStateType state; 327 328 if ( flags & wxCONTROL_PRESSED ) 329 state = GTK_STATE_ACTIVE; 330 else if ( flags & wxCONTROL_DISABLED ) 331 state = GTK_STATE_INSENSITIVE; 332 else if ( flags & wxCONTROL_CURRENT ) 333 state = GTK_STATE_PRELIGHT; 334 else 335 state = GTK_STATE_NORMAL; 336 337 // draw arrow on button 338 gtk_paint_arrow 339 ( 340 button->style, 341 gdk_window, 342 state, 343 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT, 344 NULL, 345 button, 346 "arrow", 347 GTK_ARROW_DOWN, 348 FALSE, 349 rect.x + arrowX, 350 rect.y + arrowY, 351 arrowWidth, 352 arrowHeight 353 ); 354} 355 356void 357wxRendererGTK::DrawComboBoxDropButton(wxWindow *win, 358 wxDC& dc, 359 const wxRect& rect, 360 int flags) 361{ 362 GtkWidget *button = GetButtonWidget(); 363 364 // for reason why we do this, see DrawDropArrow 365 GdkWindow* gdk_window = dc.GetGDKWindow(); 366 wxASSERT_MSG( gdk_window, 367 wxT("cannot use wxRendererNative on wxDC of this type") ); 368 369 // draw button 370 GtkStateType state; 371 372 if ( flags & wxCONTROL_PRESSED ) 373 state = GTK_STATE_ACTIVE; 374 else if ( flags & wxCONTROL_DISABLED ) 375 state = GTK_STATE_INSENSITIVE; 376 else if ( flags & wxCONTROL_CURRENT ) 377 state = GTK_STATE_PRELIGHT; 378 else 379 state = GTK_STATE_NORMAL; 380 381 gtk_paint_box 382 ( 383 button->style, 384 gdk_window, 385 state, 386 flags & wxCONTROL_PRESSED ? GTK_SHADOW_IN : GTK_SHADOW_OUT, 387 NULL, 388 button, 389 "button", 390 rect.x, rect.y, rect.width, rect.height 391 ); 392 393 // draw arrow on button 394 DrawDropArrow(win,dc,rect,flags); 395 396} 397