1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/statbar.cpp
3 // Purpose:     wxStatusBarBase implementation
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     14.10.01
7 // RCS-ID:      $Id: statbar.cpp 42171 2006-10-20 14:54:14Z VS $
8 // Copyright:   (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
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 #if wxUSE_STATUSBAR
28 
29 #include "wx/statusbr.h"
30 
31 #ifndef WX_PRECOMP
32     #include "wx/frame.h"
33 #endif //WX_PRECOMP
34 
35 #include "wx/listimpl.cpp"
36 WX_DEFINE_LIST(wxListString)
37 
38 const wxChar wxStatusBarNameStr[] = wxT("statusBar");
39 
40 // ============================================================================
41 // wxStatusBarBase implementation
42 // ============================================================================
43 
IMPLEMENT_DYNAMIC_CLASS(wxStatusBar,wxWindow)44 IMPLEMENT_DYNAMIC_CLASS(wxStatusBar, wxWindow)
45 
46 // ----------------------------------------------------------------------------
47 // ctor/dtor
48 // ----------------------------------------------------------------------------
49 
50 wxStatusBarBase::wxStatusBarBase()
51 {
52     m_nFields = 0;
53 
54     InitWidths();
55     InitStacks();
56     InitStyles();
57 }
58 
~wxStatusBarBase()59 wxStatusBarBase::~wxStatusBarBase()
60 {
61     FreeWidths();
62     FreeStacks();
63     FreeStyles();
64 
65     // notify the frame that it doesn't have a status bar any longer to avoid
66     // dangling pointers
67     wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
68     if ( frame && frame->GetStatusBar() == this )
69     {
70         frame->SetStatusBar(NULL);
71     }
72 }
73 
74 // ----------------------------------------------------------------------------
75 // widths array handling
76 // ----------------------------------------------------------------------------
77 
InitWidths()78 void wxStatusBarBase::InitWidths()
79 {
80     m_statusWidths = NULL;
81 }
82 
FreeWidths()83 void wxStatusBarBase::FreeWidths()
84 {
85     delete [] m_statusWidths;
86 }
87 
88 // ----------------------------------------------------------------------------
89 // styles array handling
90 // ----------------------------------------------------------------------------
91 
InitStyles()92 void wxStatusBarBase::InitStyles()
93 {
94     m_statusStyles = NULL;
95 }
96 
FreeStyles()97 void wxStatusBarBase::FreeStyles()
98 {
99     delete [] m_statusStyles;
100 }
101 
102 // ----------------------------------------------------------------------------
103 // field widths
104 // ----------------------------------------------------------------------------
105 
SetFieldsCount(int number,const int * widths)106 void wxStatusBarBase::SetFieldsCount(int number, const int *widths)
107 {
108     wxCHECK_RET( number > 0, _T("invalid field number in SetFieldsCount") );
109 
110     bool refresh = false;
111 
112     if ( number != m_nFields )
113     {
114         // copy stacks if present
115         if(m_statusTextStacks)
116         {
117             wxListString **newStacks = new wxListString*[number];
118             size_t i, j, max = wxMin(number, m_nFields);
119 
120             // copy old stacks
121             for(i = 0; i < max; ++i)
122                 newStacks[i] = m_statusTextStacks[i];
123             // free old stacks in excess
124             for(j = i; j < (size_t)m_nFields; ++j)
125             {
126                 if(m_statusTextStacks[j])
127                 {
128                     m_statusTextStacks[j]->Clear();
129                     delete m_statusTextStacks[j];
130                 }
131             }
132             // initialize new stacks to NULL
133             for(j = i; j < (size_t)number; ++j)
134                 newStacks[j] = 0;
135 
136             m_statusTextStacks = newStacks;
137         }
138 
139         // Resize styles array
140         if (m_statusStyles)
141         {
142             int *oldStyles = m_statusStyles;
143             m_statusStyles = new int[number];
144             int i, max = wxMin(number, m_nFields);
145 
146             // copy old styles
147             for (i = 0; i < max; ++i)
148                 m_statusStyles[i] = oldStyles[i];
149 
150             // initialize new styles to wxSB_NORMAL
151             for (i = max; i < number; ++i)
152                 m_statusStyles[i] = wxSB_NORMAL;
153 
154             // free old styles
155             delete [] oldStyles;
156         }
157 
158 
159         m_nFields = number;
160 
161         ReinitWidths();
162 
163         refresh = true;
164     }
165     //else: keep the old m_statusWidths if we had them
166 
167     if ( widths )
168     {
169         SetStatusWidths(number, widths);
170 
171         // already done from SetStatusWidths()
172         refresh = false;
173     }
174 
175     if ( refresh )
176         Refresh();
177 }
178 
SetStatusWidths(int WXUNUSED_UNLESS_DEBUG (n),const int widths[])179 void wxStatusBarBase::SetStatusWidths(int WXUNUSED_UNLESS_DEBUG(n),
180                                       const int widths[])
181 {
182     wxCHECK_RET( widths, _T("NULL pointer in SetStatusWidths") );
183 
184     wxASSERT_MSG( n == m_nFields, _T("field number mismatch") );
185 
186     if ( !m_statusWidths )
187         m_statusWidths = new int[m_nFields];
188 
189     for ( int i = 0; i < m_nFields; i++ )
190     {
191         m_statusWidths[i] = widths[i];
192     }
193 
194     // update the display after the widths changed
195     Refresh();
196 }
197 
SetStatusStyles(int WXUNUSED_UNLESS_DEBUG (n),const int styles[])198 void wxStatusBarBase::SetStatusStyles(int WXUNUSED_UNLESS_DEBUG(n),
199                                       const int styles[])
200 {
201     wxCHECK_RET( styles, _T("NULL pointer in SetStatusStyles") );
202 
203     wxASSERT_MSG( n == m_nFields, _T("field number mismatch") );
204 
205     if ( !m_statusStyles )
206         m_statusStyles = new int[m_nFields];
207 
208     for ( int i = 0; i < m_nFields; i++ )
209     {
210         m_statusStyles[i] = styles[i];
211     }
212 
213     // update the display after the widths changed
214     Refresh();
215 }
216 
CalculateAbsWidths(wxCoord widthTotal) const217 wxArrayInt wxStatusBarBase::CalculateAbsWidths(wxCoord widthTotal) const
218 {
219     wxArrayInt widths;
220 
221     if ( m_statusWidths == NULL )
222     {
223         if ( m_nFields )
224         {
225             // Default: all fields have the same width. This is not always
226             // possible to do exactly (if widthTotal is not divisible by
227             // m_nFields) - if that happens, we distribute the extra pixels
228             // among all fields:
229             int widthToUse = widthTotal;
230 
231             for ( int i = m_nFields; i > 0; i-- )
232             {
233                 // divide the unassigned width evently between the
234                 // not yet processed fields:
235                 int w = widthToUse / i;
236                 widths.Add(w);
237                 widthToUse -= w;
238             }
239 
240         }
241         //else: we're empty anyhow
242     }
243     else // have explicit status widths
244     {
245         // calculate the total width of all the fixed width fields and the
246         // total number of var field widths counting with multiplicity
247         int nTotalWidth = 0,
248             nVarCount = 0,
249             i;
250         for ( i = 0; i < m_nFields; i++ )
251         {
252             if ( m_statusWidths[i] >= 0 )
253             {
254                 nTotalWidth += m_statusWidths[i];
255             }
256             else
257             {
258                 nVarCount += -m_statusWidths[i];
259             }
260         }
261 
262         // the amount of extra width we have per each var width field
263         int widthExtra = widthTotal - nTotalWidth;
264 
265         // do fill the array
266         for ( i = 0; i < m_nFields; i++ )
267         {
268             if ( m_statusWidths[i] >= 0 )
269             {
270                 widths.Add(m_statusWidths[i]);
271             }
272             else
273             {
274                 int nVarWidth = widthExtra > 0 ? (widthExtra * -m_statusWidths[i]) / nVarCount : 0;
275                 nVarCount += m_statusWidths[i];
276                 widthExtra -= nVarWidth;
277                 widths.Add(nVarWidth);
278             }
279         }
280     }
281 
282     return widths;
283 }
284 
285 // ----------------------------------------------------------------------------
286 // text stacks handling
287 // ----------------------------------------------------------------------------
288 
InitStacks()289 void wxStatusBarBase::InitStacks()
290 {
291     m_statusTextStacks = NULL;
292 }
293 
FreeStacks()294 void wxStatusBarBase::FreeStacks()
295 {
296     if ( !m_statusTextStacks )
297         return;
298 
299     for ( size_t i = 0; i < (size_t)m_nFields; ++i )
300     {
301         if ( m_statusTextStacks[i] )
302         {
303             wxListString& t = *m_statusTextStacks[i];
304             WX_CLEAR_LIST(wxListString, t);
305             delete m_statusTextStacks[i];
306         }
307     }
308 
309     delete[] m_statusTextStacks;
310 }
311 
312 // ----------------------------------------------------------------------------
313 // text stacks
314 // ----------------------------------------------------------------------------
315 
PushStatusText(const wxString & text,int number)316 void wxStatusBarBase::PushStatusText(const wxString& text, int number)
317 {
318     wxListString* st = GetOrCreateStatusStack(number);
319     // This long-winded way around avoids an internal compiler error
320     // in VC++ 6 with RTTI enabled
321     wxString tmp1(GetStatusText(number));
322     wxString* tmp = new wxString(tmp1);
323     st->Insert(tmp);
324     SetStatusText(text, number);
325 }
326 
PopStatusText(int number)327 void wxStatusBarBase::PopStatusText(int number)
328 {
329     wxListString *st = GetStatusStack(number);
330     wxCHECK_RET( st, _T("Unbalanced PushStatusText/PopStatusText") );
331     wxListString::compatibility_iterator top = st->GetFirst();
332 
333     SetStatusText(*top->GetData(), number);
334     delete top->GetData();
335     st->Erase(top);
336     if(st->GetCount() == 0)
337     {
338         delete st;
339         m_statusTextStacks[number] = 0;
340     }
341 }
342 
GetStatusStack(int i) const343 wxListString *wxStatusBarBase::GetStatusStack(int i) const
344 {
345     if(!m_statusTextStacks)
346         return 0;
347     return m_statusTextStacks[i];
348 }
349 
GetOrCreateStatusStack(int i)350 wxListString *wxStatusBarBase::GetOrCreateStatusStack(int i)
351 {
352     if(!m_statusTextStacks)
353     {
354         m_statusTextStacks = new wxListString*[m_nFields];
355 
356         size_t j;
357         for(j = 0; j < (size_t)m_nFields; ++j) m_statusTextStacks[j] = 0;
358     }
359 
360     if(!m_statusTextStacks[i])
361     {
362         m_statusTextStacks[i] = new wxListString();
363     }
364 
365     return m_statusTextStacks[i];
366 }
367 
368 #endif // wxUSE_STATUSBAR
369