Preserve prior StatusBar contents when adding removing fields
[wxWidgets.git] / src / generic / statusbr.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: generic/statusbr.cpp
3 // Purpose: wxStatusBarGeneric class implementation
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "statusbr.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #if wxUSE_STATUSBAR
24
25 #ifndef WX_PRECOMP
26 #include "wx/setup.h"
27 #include "wx/frame.h"
28 #include "wx/settings.h"
29 #include "wx/dcclient.h"
30 #endif
31
32 #include "wx/statusbr.h"
33
34 // we only have to do it here when we use wxStatusBarGeneric in addition to the
35 // standard wxStatusBar class, if wxStatusBarGeneric is the same as
36 // wxStatusBar, then the corresponding IMPLEMENT_DYNAMIC_CLASS is already in
37 // common/statbar.cpp
38 #if defined(__WXMAC__) || \
39 (defined(wxUSE_NATIVE_STATUSBAR) && wxUSE_NATIVE_STATUSBAR)
40 #include "wx/generic/statusbr.h"
41
42 IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric, wxWindow)
43 #endif // wxUSE_NATIVE_STATUSBAR
44
45 BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow)
46 EVT_PAINT(wxStatusBarGeneric::OnPaint)
47 EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged)
48 END_EVENT_TABLE()
49
50 // Default status border dimensions
51 #define wxTHICK_LINE_BORDER 2
52 #define wxTHICK_LINE_WIDTH 1
53
54 wxStatusBarGeneric::wxStatusBarGeneric()
55 {
56 m_borderX = wxTHICK_LINE_BORDER;
57 m_borderY = wxTHICK_LINE_BORDER;
58 }
59
60 wxStatusBarGeneric::~wxStatusBarGeneric()
61 {
62 # ifdef __WXMSW__
63 SetFont(wxNullFont);
64 # endif // MSW
65 }
66
67 bool wxStatusBarGeneric::Create(wxWindow *parent,
68 wxWindowID id,
69 long style,
70 const wxString& name)
71 {
72 // If create is ever meant to be re-entrant over the life of
73 // an object we should:
74 // m_statusStrings.Empty();
75
76 m_borderX = wxTHICK_LINE_BORDER;
77 m_borderY = wxTHICK_LINE_BORDER;
78
79 bool success = wxWindow::Create(parent, id,
80 wxDefaultPosition, wxDefaultSize,
81 style | wxTAB_TRAVERSAL, name);
82
83 // The status bar should have a themed background
84 SetThemeEnabled( TRUE );
85
86 // Don't wish this to be found as a child
87 #ifndef __WXMAC__
88 parent->GetChildren().DeleteObject(this);
89 #endif
90 InitColours();
91
92 SetFont(m_defaultStatusBarFont);
93
94 // Set the height according to the font and the border size
95 wxClientDC dc(this);
96 dc.SetFont(GetFont());
97
98 wxCoord y;
99 dc.GetTextExtent(_T("X"), NULL, &y );
100
101 int height = (int)( (11*y)/10 + 2*GetBorderY());
102
103 SetSize(-1, -1, -1, height);
104
105 return success;
106 }
107
108 void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths)
109 {
110 wxASSERT_MSG( number >= 0,
111 _T("Yes, number should be a size_t and less than no fields is silly.") );
112
113 // if( number > m_nFields )
114
115 for( int i = m_nFields; i < number; ++i )
116 m_statusStrings.Add( wxEmptyString );
117
118 // if( number < m_nFields )
119
120 for (int i = m_nFields - 1; i >= number; --i)
121 m_statusStrings.Remove(i);
122
123 m_nFields = number;
124
125 wxASSERT_MSG( m_nFields == (int)m_statusStrings.GetCount(),
126 _T("This really should never happen, can we do away with m_nFields here?") );
127
128 SetStatusWidths(number, widths);
129 }
130
131 void wxStatusBarGeneric::SetStatusText(const wxString& text, int number)
132 {
133 wxCHECK_RET( (number >= 0) && (number < m_nFields),
134 _T("invalid status bar field index") );
135
136 m_statusStrings[number] = text;
137
138 wxRect rect;
139 GetFieldRect(number, rect);
140
141 Refresh( TRUE, &rect );
142 }
143
144 wxString wxStatusBarGeneric::GetStatusText(int n) const
145 {
146 wxCHECK_MSG( (n >= 0) && (n < m_nFields), wxEmptyString,
147 _T("invalid status bar field index") );
148
149 return m_statusStrings[n];
150 }
151
152 void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[])
153 {
154 // only set status widths, when n == number of statuswindows
155 wxCHECK_RET( n == m_nFields, _T("status bar field count mismatch") );
156
157 // delete the old widths in any case - this function may be used to reset
158 // the widths to the default (all equal)
159 // MBN: this is incompatible with at least wxMSW and wxMAC and not
160 // documented, but let's keep it for now
161 ReinitWidths();
162
163 if ( !widths_field )
164 {
165 // not an error, see the comment above
166 Refresh();
167 return;
168 }
169
170 wxStatusBarBase::SetStatusWidths(n, widths_field);
171 }
172
173 void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) )
174 {
175 wxPaintDC dc(this);
176
177
178 int i;
179 if ( GetFont().Ok() )
180 dc.SetFont(GetFont());
181 dc.SetBackgroundMode(wxTRANSPARENT);
182
183 #ifdef __WXPM__
184 wxColour vColor;
185
186 vColor.InitFromName("LIGHT GREY");
187 ::WinFillRect(dc.m_hPS, &dc.m_vRclPaint, vColor.GetPixel());
188 #endif
189
190 for ( i = 0; i < m_nFields; i ++ )
191 DrawField(dc, i);
192
193 #ifdef __WXMSW__
194 dc.SetFont(wxNullFont);
195 #endif // MSW
196 }
197
198 void wxStatusBarGeneric::DrawFieldText(wxDC& dc, int i)
199 {
200 int leftMargin = 2;
201
202 wxRect rect;
203 GetFieldRect(i, rect);
204
205 wxString text(GetStatusText(i));
206
207 long x, y;
208
209 dc.GetTextExtent(text, &x, &y);
210
211 int xpos = rect.x + leftMargin;
212 int ypos = (int) (((rect.height - y) / 2 ) + rect.y + 0.5) ;
213
214 #if defined( __WXGTK__ ) || defined(__WXMAC__)
215 xpos++;
216 ypos++;
217 #endif
218
219 dc.SetClippingRegion(rect.x, rect.y, rect.width, rect.height);
220
221 dc.DrawText(text, xpos, ypos);
222
223 dc.DestroyClippingRegion();
224 }
225
226 void wxStatusBarGeneric::DrawField(wxDC& dc, int i)
227 {
228 wxRect rect;
229 GetFieldRect(i, rect);
230
231 // Draw border
232 // Have grey background, plus 3-d border -
233 // One black rectangle.
234 // Inside this, left and top sides - dark grey. Bottom and right -
235 // white.
236
237 dc.SetPen(m_hilightPen);
238
239 #ifndef __WXPM__
240
241 // Right and bottom white lines
242 dc.DrawLine(rect.x + rect.width, rect.y,
243 rect.x + rect.width, rect.y + rect.height);
244 dc.DrawLine(rect.x + rect.width, rect.y + rect.height,
245 rect.x, rect.y + rect.height);
246
247 dc.SetPen(m_mediumShadowPen);
248
249 // Left and top grey lines
250 dc.DrawLine(rect.x, rect.y + rect.height,
251 rect.x, rect.y);
252 dc.DrawLine(rect.x, rect.y,
253 rect.x + rect.width, rect.y);
254 #else
255 // Right
256 dc.DrawLine(rect.x + rect.width, rect.y,
257 rect.x + rect.width, rect.y + rect.height + 2);
258 dc.SetPen(m_mediumShadowPen);
259 dc.DrawLine(rect.x + rect.width + 1, rect.y,
260 rect.x + rect.width + 1, rect.y + rect.height + 2);
261 dc.DrawLine(rect.x + rect.width + 2, rect.y,
262 rect.x + rect.width + 2, rect.y + rect.height + 2);
263 // Top
264 dc.DrawLine(rect.x + rect.width + 2, rect.y,
265 rect.x - 2, rect.y);
266 dc.DrawLine(rect.x + rect.width + 1, rect.y - 1,
267 rect.x - 2, rect.y - 1);
268 dc.SetPen(m_hilightPen);
269 dc.DrawLine(rect.x + rect.width, rect.y - 2,
270 rect.x - 2, rect.y - 2);
271
272 #endif
273
274 DrawFieldText(dc, i);
275 }
276
277 // Get the position and size of the field's internal bounding rectangle
278 bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const
279 {
280 wxCHECK_MSG( (n >= 0) && (n < m_nFields), FALSE,
281 _T("invalid status bar field index") );
282
283 int width, height;
284 #ifdef __WXPM__
285 GetSize(&width, &height);
286 #else
287 GetClientSize(&width, &height);
288 #endif
289
290 int i;
291 int sum_of_nonvar = 0;
292 int num_of_var = 0;
293 bool do_same_width = FALSE;
294
295 int fieldWidth = 0;
296 int fieldPosition = 0;
297
298 if (m_statusWidths)
299 {
300 // if sum(not variable Windows) > c_width - (20 points per variable_window)
301 // then do_same_width = TRUE;
302 for (i = 0; i < m_nFields; i++)
303 {
304 if (m_statusWidths[i] > 0) sum_of_nonvar += m_statusWidths[i];
305 else num_of_var++;
306 }
307 if (sum_of_nonvar > (width - 20*num_of_var)) do_same_width = TRUE;
308 }
309 else do_same_width = TRUE;
310 if (do_same_width)
311 {
312 for (i = 0; i < m_nFields; i++)
313 {
314 fieldWidth = (int)(width/m_nFields);
315 fieldPosition = i*fieldWidth;
316 if ( i == n )
317 break;
318 }
319 }
320 else // no_same_width
321 {
322 int *tempwidth = new int[m_nFields];
323 int temppos = 0;
324 for (i = 0; i < m_nFields; i++)
325 {
326 if (m_statusWidths[i] > 0) tempwidth[i] = m_statusWidths[i];
327 else tempwidth[i] = (width - sum_of_nonvar) / num_of_var;
328 }
329 for (i = 0; i < m_nFields; i++)
330 {
331 fieldWidth = tempwidth[i];
332 fieldPosition = temppos;
333
334 temppos += tempwidth[i];
335
336 if ( i == n )
337 break;
338 }
339 delete [] tempwidth;
340 }
341
342 rect.x = fieldPosition + wxTHICK_LINE_BORDER;
343 rect.y = wxTHICK_LINE_BORDER;
344
345 rect.width = fieldWidth - 2 * wxTHICK_LINE_BORDER ;
346 rect.height = height - 2 * wxTHICK_LINE_BORDER ;
347
348 return TRUE;
349 }
350
351 // Initialize colours
352 void wxStatusBarGeneric::InitColours()
353 {
354 // Shadow colours
355 #if defined(__WIN95__)
356 wxColour mediumShadowColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW));
357 m_mediumShadowPen = wxPen(mediumShadowColour, 1, wxSOLID);
358
359 wxColour hilightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT));
360 m_hilightPen = wxPen(hilightColour, 1, wxSOLID);
361 #elif defined(__WXPM__)
362 m_mediumShadowPen = wxPen("DARK GREY", 1, wxSOLID);
363 m_hilightPen = wxPen("WHITE", 1, wxSOLID);
364
365 wxColour vColour;
366
367 vColour.Set(wxString("LIGHT GREY"));
368 SetBackgroundColour(vColour);
369 vColour.Set(wxString("BLACK"));
370 SetForegroundColour(vColour);
371 m_defaultStatusBarFont = *wxSMALL_FONT;
372 #else
373 m_mediumShadowPen = wxPen("GREY", 1, wxSOLID);
374 m_hilightPen = wxPen("WHITE", 1, wxSOLID);
375 #endif
376
377 #ifndef __WXPM__
378 m_defaultStatusBarFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
379 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
380 #endif
381 }
382
383 // Responds to colour changes, and passes event on to children.
384 void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event)
385 {
386 InitColours();
387 Refresh();
388
389 // Propagate the event to the non-top-level children
390 wxWindow::OnSysColourChanged(event);
391 }
392
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( _T("X"), NULL, &y );
400
401 if ( height > (11*y)/10 )
402 {
403 SetSize(-1, -1, -1, height + 2*m_borderY);
404 }
405 }
406
407 #endif // wxUSE_STATUSBAR
408
409 // vi:sts=4:sw=4:et