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