1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/statbar.cpp
3 // Purpose:     wxStatusBarBase implementation
4 // Author:      Vadim Zeitlin
5 // Modified by: Francesco Montorsi
6 // Created:     14.10.01
7 // Copyright:   (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 
23 #if wxUSE_STATUSBAR
24 
25 #include "wx/statusbr.h"
26 
27 #ifndef WX_PRECOMP
28     #include "wx/frame.h"
29 #endif //WX_PRECOMP
30 
31 const char wxStatusBarNameStr[] = "statusBar";
32 
33 // ============================================================================
34 // wxStatusBarPane implementation
35 // ============================================================================
36 
SetText(const wxString & text)37 bool wxStatusBarPane::SetText(const wxString& text)
38 {
39     if ( text == m_text )
40         return false;
41 
42     /*
43         If we have a message to restore on the stack, we update it to
44         correspond to the current one so that a sequence of calls such as
45 
46         1. SetStatusText("foo")
47         2. PushStatusText("bar")
48         3. SetStatusText("new foo")
49         4. PopStatusText()
50 
51         doesn't overwrite the "new foo" which should be shown at the end with
52         the old value "foo". This would be unexpected and hard to avoid,
53         especially when PushStatusText() is used internally by wxWidgets
54         without knowledge of the user program, as it is for showing the menu
55         and toolbar help strings.
56 
57         By updating the top of the stack we ensure that the next call to
58         PopStatusText() basically becomes a NOP without breaking the balance
59         between the calls to push and pop as we would have done if we really
60         called PopStatusText() here.
61      */
62     if ( !m_arrStack.empty() )
63     {
64         m_arrStack.back() = text;
65     }
66 
67     m_text = text;
68 
69     return true;
70 }
71 
PushText(const wxString & text)72 bool wxStatusBarPane::PushText(const wxString& text)
73 {
74     // save the currently shown text
75     m_arrStack.push_back(m_text);
76 
77     // and update the new one if necessary
78     if ( text == m_text )
79         return false;
80 
81     m_text = text;
82 
83     return true;
84 }
85 
PopText()86 bool wxStatusBarPane::PopText()
87 {
88     wxCHECK_MSG( !m_arrStack.empty(), false, "no status message to pop" );
89 
90     const wxString text = m_arrStack.back();
91 
92     m_arrStack.pop_back();
93 
94     if ( text == m_text )
95         return false;
96 
97     m_text = text;
98 
99     return true;
100 }
101 
102 // ============================================================================
103 // wxStatusBarBase implementation
104 // ============================================================================
105 
106 wxIMPLEMENT_DYNAMIC_CLASS(wxStatusBar, wxWindow);
107 
108 #include "wx/arrimpl.cpp" // This is a magic incantation which must be done!
WX_DEFINE_EXPORTED_OBJARRAY(wxStatusBarPaneArray)109 WX_DEFINE_EXPORTED_OBJARRAY(wxStatusBarPaneArray)
110 
111 
112 // ----------------------------------------------------------------------------
113 // ctor/dtor
114 // ----------------------------------------------------------------------------
115 
116 wxStatusBarBase::wxStatusBarBase()
117 {
118     m_bSameWidthForAllPanes = true;
119 }
120 
~wxStatusBarBase()121 wxStatusBarBase::~wxStatusBarBase()
122 {
123     // notify the frame that it doesn't have a status bar any longer to avoid
124     // dangling pointers
125     wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
126     if ( frame && frame->GetStatusBar() == this )
127         frame->SetStatusBar(NULL);
128 }
129 
130 // ----------------------------------------------------------------------------
131 // field widths
132 // ----------------------------------------------------------------------------
133 
SetFieldsCount(int number,const int * widths)134 void wxStatusBarBase::SetFieldsCount(int number, const int *widths)
135 {
136     wxCHECK_RET( number > 0, wxT("invalid field number in SetFieldsCount") );
137 
138     if ( (size_t)number > m_panes.GetCount() )
139     {
140         wxStatusBarPane newPane;
141 
142         // add more entries with the default style and zero width
143         // (this will be set later)
144         for (size_t i = m_panes.GetCount(); i < (size_t)number; ++i)
145             m_panes.Add(newPane);
146     }
147     else if ( (size_t)number < m_panes.GetCount() )
148     {
149         // remove entries in excess
150         m_panes.RemoveAt(number, m_panes.GetCount()-number);
151     }
152 
153     // SetStatusWidths will automatically refresh
154     SetStatusWidths(number, widths);
155 }
156 
SetStatusWidths(int WXUNUSED_UNLESS_DEBUG (n),const int widths[])157 void wxStatusBarBase::SetStatusWidths(int WXUNUSED_UNLESS_DEBUG(n),
158                                     const int widths[])
159 {
160     wxASSERT_MSG( (size_t)n == m_panes.GetCount(), wxT("field number mismatch") );
161 
162     if (widths == NULL)
163     {
164         // special value meaning: override explicit pane widths and make them all
165         // of the same size
166         m_bSameWidthForAllPanes = true;
167     }
168     else
169     {
170         for ( size_t i = 0; i < m_panes.GetCount(); i++ )
171             m_panes[i].SetWidth(widths[i]);
172 
173         m_bSameWidthForAllPanes = false;
174     }
175 
176     // update the display after the widths changed
177     Refresh();
178 }
179 
SetStatusStyles(int WXUNUSED_UNLESS_DEBUG (n),const int styles[])180 void wxStatusBarBase::SetStatusStyles(int WXUNUSED_UNLESS_DEBUG(n),
181                                     const int styles[])
182 {
183     wxCHECK_RET( styles, wxT("NULL pointer in SetStatusStyles") );
184 
185     wxASSERT_MSG( (size_t)n == m_panes.GetCount(), wxT("field number mismatch") );
186 
187     for ( size_t i = 0; i < m_panes.GetCount(); i++ )
188         m_panes[i].SetStyle(styles[i]);
189 
190     // update the display after the widths changed
191     Refresh();
192 }
193 
CalculateAbsWidths(wxCoord widthTotal) const194 wxArrayInt wxStatusBarBase::CalculateAbsWidths(wxCoord widthTotal) const
195 {
196     wxArrayInt widths;
197 
198     if ( m_bSameWidthForAllPanes )
199     {
200         // Default: all fields have the same width. This is not always
201         // possible to do exactly (if widthTotal is not divisible by
202         // m_panes.GetCount()) - if that happens, we distribute the extra
203         // pixels among all fields:
204         int widthToUse = widthTotal;
205 
206         for ( size_t i = m_panes.GetCount(); i > 0; i-- )
207         {
208             // divide the unassigned width evently between the
209             // not yet processed fields:
210             int w = widthToUse / i;
211             widths.Add(w);
212             widthToUse -= w;
213         }
214     }
215     else // do not override explicit pane widths
216     {
217         // calculate the total width of all the fixed width fields and the
218         // total number of var field widths counting with multiplicity
219         size_t nTotalWidth = 0,
220             nVarCount = 0,
221             i;
222 
223         for ( i = 0; i < m_panes.GetCount(); i++ )
224         {
225             if ( m_panes[i].GetWidth() >= 0 )
226                 nTotalWidth += m_panes[i].GetWidth();
227             else
228                 nVarCount += -m_panes[i].GetWidth();
229         }
230 
231         // the amount of extra width we have per each var width field
232         int widthExtra = widthTotal - nTotalWidth;
233 
234         // do fill the array
235         for ( i = 0; i < m_panes.GetCount(); i++ )
236         {
237             if ( m_panes[i].GetWidth() >= 0 )
238                 widths.Add(m_panes[i].GetWidth());
239             else
240             {
241                 int nVarWidth = widthExtra > 0 ? (widthExtra * (-m_panes[i].GetWidth())) / nVarCount : 0;
242                 nVarCount += m_panes[i].GetWidth();
243                 widthExtra -= nVarWidth;
244                 widths.Add(nVarWidth);
245             }
246         }
247     }
248 
249     return widths;
250 }
251 
252 // ----------------------------------------------------------------------------
253 // setting/getting status text
254 // ----------------------------------------------------------------------------
255 
SetStatusText(const wxString & text,int number)256 void wxStatusBarBase::SetStatusText(const wxString& text, int number)
257 {
258     wxCHECK_RET( (unsigned)number < m_panes.size(),
259                     "invalid status bar field index" );
260 
261     if ( m_panes[number].SetText(text) )
262         DoUpdateStatusText(number);
263 }
264 
GetStatusText(int number) const265 wxString wxStatusBarBase::GetStatusText(int number) const
266 {
267     wxCHECK_MSG( (unsigned)number < m_panes.size(), wxString(),
268                     "invalid status bar field index" );
269 
270     return m_panes[number].GetText();
271 }
272 
SetEllipsizedFlag(int number,bool isEllipsized)273 void wxStatusBarBase::SetEllipsizedFlag(int number, bool isEllipsized)
274 {
275     wxCHECK_RET( (unsigned)number < m_panes.size(),
276                     "invalid status bar field index" );
277 
278     m_panes[number].SetIsEllipsized(isEllipsized);
279 }
280 
281 // ----------------------------------------------------------------------------
282 // pushing/popping status text
283 // ----------------------------------------------------------------------------
284 
PushStatusText(const wxString & text,int number)285 void wxStatusBarBase::PushStatusText(const wxString& text, int number)
286 {
287     wxCHECK_RET( (unsigned)number < m_panes.size(),
288                     "invalid status bar field index" );
289 
290     if ( m_panes[number].PushText(text) )
291         DoUpdateStatusText(number);
292 }
293 
PopStatusText(int number)294 void wxStatusBarBase::PopStatusText(int number)
295 {
296     wxCHECK_RET( (unsigned)number < m_panes.size(),
297                     "invalid status bar field index" );
298 
299     if ( m_panes[number].PopText() )
300         DoUpdateStatusText(number);
301 }
302 
303 #endif // wxUSE_STATUSBAR
304