1///////////////////////////////////////////////////////////////////////////// 2// Name: src/generic/statusbr.cpp 3// Purpose: wxStatusBarGeneric class implementation 4// Author: Julian Smart 5// Modified by: 6// Created: 01/02/97 7// RCS-ID: $Id: statusbr.cpp 57542 2008-12-25 13:03:24Z VZ $ 8// Copyright: (c) Julian Smart 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// For compilers that support precompilation, includes "wx.h". 13#include "wx/wxprec.h" 14 15#ifdef __BORLANDC__ 16 #pragma hdrstop 17#endif 18 19#if wxUSE_STATUSBAR 20 21#include "wx/statusbr.h" 22 23#ifndef WX_PRECOMP 24 #include "wx/settings.h" 25 #include "wx/dcclient.h" 26#endif 27 28#ifdef __WXGTK20__ 29 #include <gtk/gtk.h> 30 #include "wx/gtk/win_gtk.h" 31#endif 32 33// we only have to do it here when we use wxStatusBarGeneric in addition to the 34// standard wxStatusBar class, if wxStatusBarGeneric is the same as 35// wxStatusBar, then the corresponding IMPLEMENT_DYNAMIC_CLASS is already in 36// common/statbar.cpp 37#if defined(__WXMAC__) || \ 38 (defined(wxUSE_NATIVE_STATUSBAR) && wxUSE_NATIVE_STATUSBAR) 39 #include "wx/generic/statusbr.h" 40 41 IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric, wxWindow) 42#endif // wxUSE_NATIVE_STATUSBAR 43 44BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow) 45 EVT_PAINT(wxStatusBarGeneric::OnPaint) 46 EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown) 47 EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown) 48 EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged) 49END_EVENT_TABLE() 50 51// Default status border dimensions 52#define wxTHICK_LINE_BORDER 2 53 54void wxStatusBarGeneric::Init() 55{ 56 m_borderX = wxTHICK_LINE_BORDER; 57 m_borderY = wxTHICK_LINE_BORDER; 58} 59 60wxStatusBarGeneric::~wxStatusBarGeneric() 61{ 62} 63 64bool wxStatusBarGeneric::Create(wxWindow *parent, 65 wxWindowID id, 66 long style, 67 const wxString& name) 68{ 69 style |= wxTAB_TRAVERSAL | wxFULL_REPAINT_ON_RESIZE; 70 if ( !wxWindow::Create(parent, id, 71 wxDefaultPosition, wxDefaultSize, 72 style, name) ) 73 return false; 74 75 // The status bar should have a themed background 76 SetThemeEnabled( true ); 77 78 InitColours(); 79 80#ifdef __WXPM__ 81 SetFont(*wxSMALL_FONT); 82#endif 83 84 wxCoord y; 85 { 86 // Set the height according to the font and the border size 87 wxClientDC dc(this); 88 dc.SetFont(GetFont()); 89 90 dc.GetTextExtent(_T("X"), NULL, &y ); 91 } 92 int height = (int)( (11*y)/10 + 2*GetBorderY()); 93 94 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height); 95 96 SetFieldsCount(1); 97 98 return true; 99} 100 101 102wxSize wxStatusBarGeneric::DoGetBestSize() const 103{ 104 int width, height; 105 106 // best width is the width of the parent 107 GetParent()->GetClientSize(&width, NULL); 108 109 // best height is as calculated above in Create 110 wxClientDC dc((wxWindow*)this); 111 dc.SetFont(GetFont()); 112 wxCoord y; 113 dc.GetTextExtent(_T("X"), NULL, &y ); 114 height = (int)( (11*y)/10 + 2*GetBorderY()); 115 116 return wxSize(width, height); 117} 118 119void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths) 120{ 121 wxASSERT_MSG( number >= 0, _T("negative number of fields in wxStatusBar?") ); 122 123 int i; 124 for(i = m_nFields; i < number; ++i) 125 m_statusStrings.Add( wxEmptyString ); 126 127 for (i = m_nFields - 1; i >= number; --i) 128 m_statusStrings.RemoveAt(i); 129 130 // forget the old cached pixel widths 131 m_widthsAbs.Empty(); 132 133 wxStatusBarBase::SetFieldsCount(number, widths); 134 135 wxASSERT_MSG( m_nFields == (int)m_statusStrings.GetCount(), 136 _T("This really should never happen, can we do away with m_nFields here?") ); 137} 138 139void wxStatusBarGeneric::SetStatusText(const wxString& text, int number) 140{ 141 wxCHECK_RET( (number >= 0) && (number < m_nFields), 142 _T("invalid status bar field index") ); 143 144 wxString oldText = m_statusStrings[number]; 145 if (oldText != text) 146 { 147 m_statusStrings[number] = text; 148 149 wxRect rect; 150 GetFieldRect(number, rect); 151 152 Refresh(true, &rect); 153 154 // it's common to show some text in the status bar before starting a 155 // relatively lengthy operation, ensure that the text is shown to the 156 // user immediately and not after the lengthy operation end 157 Update(); 158 } 159} 160 161wxString wxStatusBarGeneric::GetStatusText(int n) const 162{ 163 wxCHECK_MSG( (n >= 0) && (n < m_nFields), wxEmptyString, 164 _T("invalid status bar field index") ); 165 166 return m_statusStrings[n]; 167} 168 169void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[]) 170{ 171 // only set status widths, when n == number of statuswindows 172 wxCHECK_RET( n == m_nFields, _T("status bar field count mismatch") ); 173 174 // delete the old widths in any case - this function may be used to reset 175 // the widths to the default (all equal) 176 // MBN: this is incompatible with at least wxMSW and wxMAC and not 177 // documented, but let's keep it for now 178 ReinitWidths(); 179 180 // forget the old cached pixel widths 181 m_widthsAbs.Empty(); 182 183 if ( !widths_field ) 184 { 185 // not an error, see the comment above 186 Refresh(); 187 return; 188 } 189 190 wxStatusBarBase::SetStatusWidths(n, widths_field); 191} 192 193void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) ) 194{ 195 wxPaintDC dc(this); 196 197 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); 198#ifdef __WXGTK20__ 199 // Draw grip first 200 if (HasFlag( wxST_SIZEGRIP )) 201 { 202 int width, height; 203 GetClientSize(&width, &height); 204 205 if (GetLayoutDirection() == wxLayout_RightToLeft) 206 { 207 gtk_paint_resize_grip( m_widget->style, 208 GTK_PIZZA(m_wxwindow)->bin_window, 209 (GtkStateType) GTK_WIDGET_STATE (m_widget), 210 NULL, 211 m_widget, 212 "statusbar", 213 GDK_WINDOW_EDGE_SOUTH_WEST, 214 2, 2, height-2, height-4 ); 215 } 216 else 217 { 218 gtk_paint_resize_grip( m_widget->style, 219 GTK_PIZZA(m_wxwindow)->bin_window, 220 (GtkStateType) GTK_WIDGET_STATE (m_widget), 221 NULL, 222 m_widget, 223 "statusbar", 224 GDK_WINDOW_EDGE_SOUTH_EAST, 225 width-height-2, 2, height-2, height-4 ); 226 } 227 } 228#endif 229 230 if (GetFont().Ok()) 231 dc.SetFont(GetFont()); 232 233 dc.SetBackgroundMode(wxTRANSPARENT); 234 235#ifdef __WXPM__ 236 wxColour vColor; 237 238 vColor = wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR); 239 ::WinFillRect(dc.m_hPS, &dc.m_vRclPaint, vColor.GetPixel()); 240#endif 241 242 for (int i = 0; i < m_nFields; i ++) 243 DrawField(dc, i); 244} 245 246void wxStatusBarGeneric::DrawFieldText(wxDC& dc, int i) 247{ 248 int leftMargin = 2; 249 250 wxRect rect; 251 GetFieldRect(i, rect); 252 253 wxString text(GetStatusText(i)); 254 255 long x = 0, y = 0; 256 257 dc.GetTextExtent(text, &x, &y); 258 259 int xpos = rect.x + leftMargin; 260 int ypos = (int) (((rect.height - y) / 2 ) + rect.y + 0.5) ; 261 262#if defined( __WXGTK__ ) || defined(__WXMAC__) 263 xpos++; 264 ypos++; 265#endif 266 267 dc.SetClippingRegion(rect.x, rect.y, rect.width, rect.height); 268 269 dc.DrawText(text, xpos, ypos); 270 271 dc.DestroyClippingRegion(); 272} 273 274void wxStatusBarGeneric::DrawField(wxDC& dc, int i) 275{ 276 wxRect rect; 277 GetFieldRect(i, rect); 278 279 int style = wxSB_NORMAL; 280 if (m_statusStyles) 281 style = m_statusStyles[i]; 282 283 if (style != wxSB_FLAT) 284 { 285 // Draw border 286 // For wxSB_NORMAL: 287 // Have grey background, plus 3-d border - 288 // One black rectangle. 289 // Inside this, left and top sides - dark grey. Bottom and right - 290 // white. 291 // Reverse it for wxSB_RAISED 292 293 dc.SetPen((style == wxSB_RAISED) ? m_mediumShadowPen : m_hilightPen); 294 295 #ifndef __WXPM__ 296 297 // Right and bottom lines 298 dc.DrawLine(rect.x + rect.width, rect.y, 299 rect.x + rect.width, rect.y + rect.height); 300 dc.DrawLine(rect.x + rect.width, rect.y + rect.height, 301 rect.x, rect.y + rect.height); 302 303 dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen); 304 305 // Left and top lines 306 dc.DrawLine(rect.x, rect.y + rect.height, 307 rect.x, rect.y); 308 dc.DrawLine(rect.x, rect.y, 309 rect.x + rect.width, rect.y); 310 #else 311 312 dc.DrawLine(rect.x + rect.width, rect.height + 2, 313 rect.x, rect.height + 2); 314 dc.DrawLine(rect.x + rect.width, rect.y, 315 rect.x + rect.width, rect.y + rect.height); 316 317 dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen); 318 dc.DrawLine(rect.x, rect.y, 319 rect.x + rect.width, rect.y); 320 dc.DrawLine(rect.x, rect.y + rect.height, 321 rect.x, rect.y); 322 323#endif 324 } 325 326 DrawFieldText(dc, i); 327} 328 329 // Get the position and size of the field's internal bounding rectangle 330bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const 331{ 332 wxCHECK_MSG( (n >= 0) && (n < m_nFields), false, 333 _T("invalid status bar field index") ); 334 335 // FIXME: workarounds for OS/2 bugs have nothing to do here (VZ) 336 int width, height; 337#ifdef __WXPM__ 338 GetSize(&width, &height); 339#else 340 GetClientSize(&width, &height); 341#endif 342 343 // we cache m_widthsAbs between calls and recompute it if client 344 // width has changed (or when it is initially empty) 345 if ( m_widthsAbs.IsEmpty() || (m_lastClientWidth != width) ) 346 { 347 wxConstCast(this, wxStatusBarGeneric)-> 348 m_widthsAbs = CalculateAbsWidths(width); 349 // remember last width for which we have recomputed the widths in pixels 350 wxConstCast(this, wxStatusBarGeneric)-> 351 m_lastClientWidth = width; 352 } 353 354 rect.x = 0; 355 for ( int i = 0; i < n; i++ ) 356 { 357 rect.x += m_widthsAbs[i]; 358 } 359 360 rect.x += m_borderX; 361 rect.y = m_borderY; 362 363 rect.width = m_widthsAbs[n] - 2*m_borderX; 364 rect.height = height - 2*m_borderY; 365 366 return true; 367} 368 369// Initialize colours 370void wxStatusBarGeneric::InitColours() 371{ 372#if defined(__WXPM__) 373 m_mediumShadowPen = wxPen(wxColour(127, 127, 127), 1, wxSOLID); 374 m_hilightPen = *wxWHITE_PEN; 375 376 SetBackgroundColour(*wxLIGHT_GREY); 377 SetForegroundColour(*wxBLACK); 378#else // !__WXPM__ 379 m_mediumShadowPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)); 380 m_hilightPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT)); 381#endif // __WXPM__/!__WXPM__ 382} 383 384// Responds to colour changes, and passes event on to children. 385void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event) 386{ 387 InitColours(); 388 389 // Propagate the event to the non-top-level children 390 wxWindow::OnSysColourChanged(event); 391} 392 393void wxStatusBarGeneric::SetMinHeight(int height) 394{ 395 // check that this min height is not less than minimal height for the 396 // current font 397 wxClientDC dc(this); 398 wxCoord y; 399 dc.GetTextExtent( wxT("X"), NULL, &y ); 400 401 if ( height > (11*y)/10 ) 402 { 403 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height + 2*m_borderY); 404 } 405} 406 407void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event) 408{ 409#ifdef __WXGTK20__ 410 int width, height; 411 GetClientSize(&width, &height); 412 413 if (HasFlag( wxST_SIZEGRIP ) && (event.GetX() > width-height)) 414 { 415 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget ); 416 417 if (!GTK_IS_WINDOW (ancestor)) 418 return; 419 420 GdkWindow *source = GTK_PIZZA(m_wxwindow)->bin_window; 421 422 int org_x = 0; 423 int org_y = 0; 424 gdk_window_get_origin( source, &org_x, &org_y ); 425 426 if (GetLayoutDirection() == wxLayout_RightToLeft) 427 { 428 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor), 429 GDK_WINDOW_EDGE_SOUTH_WEST, 430 1, 431 org_x - event.GetX() + GetSize().x , 432 org_y + event.GetY(), 433 0); 434 } 435 else 436 { 437 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor), 438 GDK_WINDOW_EDGE_SOUTH_EAST, 439 1, 440 org_x + event.GetX(), 441 org_y + event.GetY(), 442 0); 443 } 444 } 445 else 446 { 447 event.Skip( true ); 448 } 449#else 450 event.Skip( true ); 451#endif 452} 453 454void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event) 455{ 456#ifdef __WXGTK20__ 457 int width, height; 458 GetClientSize(&width, &height); 459 460 if (HasFlag( wxST_SIZEGRIP ) && (event.GetX() > width-height)) 461 { 462 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget ); 463 464 if (!GTK_IS_WINDOW (ancestor)) 465 return; 466 467 GdkWindow *source = GTK_PIZZA(m_wxwindow)->bin_window; 468 469 int org_x = 0; 470 int org_y = 0; 471 gdk_window_get_origin( source, &org_x, &org_y ); 472 473 gtk_window_begin_move_drag (GTK_WINDOW (ancestor), 474 2, 475 org_x + event.GetX(), 476 org_y + event.GetY(), 477 0); 478 } 479 else 480 { 481 event.Skip( true ); 482 } 483#else 484 event.Skip( true ); 485#endif 486} 487 488#endif // wxUSE_STATUSBAR 489