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
IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric,wxWindow)41 IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric, wxWindow)
42 #endif // wxUSE_NATIVE_STATUSBAR
43
44 BEGIN_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)
49 END_EVENT_TABLE()
50
51 // Default status border dimensions
52 #define wxTHICK_LINE_BORDER 2
53
54 void wxStatusBarGeneric::Init()
55 {
56 m_borderX = wxTHICK_LINE_BORDER;
57 m_borderY = wxTHICK_LINE_BORDER;
58 }
59
~wxStatusBarGeneric()60 wxStatusBarGeneric::~wxStatusBarGeneric()
61 {
62 }
63
Create(wxWindow * parent,wxWindowID id,long style,const wxString & name)64 bool 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
DoGetBestSize() const102 wxSize 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
SetFieldsCount(int number,const int * widths)119 void 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
SetStatusText(const wxString & text,int number)139 void 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
GetStatusText(int n) const161 wxString 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
SetStatusWidths(int n,const int widths_field[])169 void 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
OnPaint(wxPaintEvent & WXUNUSED (event))193 void 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
DrawFieldText(wxDC & dc,int i)246 void 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
DrawField(wxDC & dc,int i)274 void 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
GetFieldRect(int n,wxRect & rect) const330 bool 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
InitColours()370 void 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.
OnSysColourChanged(wxSysColourChangedEvent & event)385 void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event)
386 {
387 InitColours();
388
389 // Propagate the event to the non-top-level children
390 wxWindow::OnSysColourChanged(event);
391 }
392
SetMinHeight(int height)393 void 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
OnLeftDown(wxMouseEvent & event)407 void 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
OnRightDown(wxMouseEvent & event)454 void 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