1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/univ/statusbr.cpp
3// Purpose:     wxStatusBar implementation
4// Author:      Vadim Zeitlin
5// Modified by:
6// Created:     14.10.01
7// RCS-ID:      $Id: statusbr.cpp 42404 2006-10-25 18:14:08Z VS $
8// Copyright:   (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23    #pragma hdrstop
24#endif
25
26#if wxUSE_STATUSBAR
27
28#include "wx/statusbr.h"
29
30#ifndef WX_PRECOMP
31    #include "wx/settings.h"
32    #include "wx/dcclient.h"
33    #include "wx/toplevel.h"
34#endif
35
36#include "wx/univ/renderer.h"
37
38// ============================================================================
39// implementation
40// ============================================================================
41
42BEGIN_EVENT_TABLE(wxStatusBarUniv, wxStatusBarBase)
43    EVT_SIZE(wxStatusBarUniv::OnSize)
44
45    WX_EVENT_TABLE_INPUT_CONSUMER(wxStatusBarUniv)
46END_EVENT_TABLE()
47
48WX_FORWARD_TO_INPUT_CONSUMER(wxStatusBarUniv)
49
50// ----------------------------------------------------------------------------
51// creation
52// ----------------------------------------------------------------------------
53
54void wxStatusBarUniv::Init()
55{
56}
57
58bool wxStatusBarUniv::Create(wxWindow *parent,
59                             wxWindowID id,
60                             long style,
61                             const wxString& name)
62{
63    if ( !wxWindow::Create(parent, id,
64                           wxDefaultPosition, wxDefaultSize,
65                           style, name) )
66    {
67        return false;
68    }
69
70    SetFieldsCount(1);
71
72    CreateInputHandler(wxINP_HANDLER_STATUSBAR);
73
74    SetSize(DoGetBestSize());
75
76    return true;
77}
78
79// ----------------------------------------------------------------------------
80// drawing
81// ----------------------------------------------------------------------------
82
83wxRect wxStatusBarUniv::GetTotalFieldRect(wxCoord *borderBetweenFields)
84{
85    wxRect rect = GetClientRect();
86
87    // no, don't do this - the borders are meant to be inside this rect
88    // wxSize sizeBorders =
89    if ( borderBetweenFields )
90        *borderBetweenFields = m_renderer->GetStatusBarBorderBetweenFields();
91    //rect.Deflate(sizeBorders.x, sizeBorders.y);
92
93    // recalc the field widths if needed
94    if ( m_widthsAbs.IsEmpty() )
95    {
96        // the total width for the fields doesn't include the borders between
97        // them
98        m_widthsAbs = CalculateAbsWidths(rect.width -
99                                         *borderBetweenFields*(m_nFields - 1));
100    }
101
102    return rect;
103}
104
105void wxStatusBarUniv::DoDraw(wxControlRenderer *renderer)
106{
107    // get the fields rect
108    wxCoord borderBetweenFields;
109    wxRect rect = GetTotalFieldRect(&borderBetweenFields);
110
111    // prepare the DC
112    wxDC& dc = renderer->GetDC();
113    dc.SetFont(GetFont());
114    dc.SetTextForeground(GetForegroundColour());
115
116    // do draw the fields
117    int flags = IsEnabled() ? 0 : (int)wxCONTROL_DISABLED;
118    for ( int n = 0; n < m_nFields; n++ )
119    {
120        rect.width = m_widthsAbs[n];
121
122        if ( IsExposed(rect) )
123        {
124            wxTopLevelWindow *parentTLW = wxDynamicCast(GetParent(), wxTopLevelWindow);
125
126            // the size grip may be drawn only on the last field and only if we
127            // have the corresponding style and even then only if we really can
128            // resize this frame
129            if ( n == m_nFields - 1 &&
130                 HasFlag(wxST_SIZEGRIP) &&
131                 GetParent()->HasFlag(wxRESIZE_BORDER) &&
132                 parentTLW && !parentTLW->IsMaximized() )
133            {
134                flags |= wxCONTROL_SIZEGRIP;
135            }
136
137            int style;
138            if (m_statusStyles)
139                style = m_statusStyles[n];
140            else
141                style = wxSB_NORMAL;
142            m_renderer->DrawStatusField(dc, rect, m_statusText[n], flags, style);
143        }
144
145        rect.x += rect.width + borderBetweenFields;
146    }
147}
148
149void wxStatusBarUniv::RefreshField(int i)
150{
151    wxRect rect;
152    if ( GetFieldRect(i, rect) )
153    {
154        RefreshRect(rect);
155    }
156}
157
158// ----------------------------------------------------------------------------
159// fields text
160// ----------------------------------------------------------------------------
161
162void wxStatusBarUniv::SetStatusText(const wxString& text, int number)
163{
164    wxCHECK_RET( number >= 0 && number < m_nFields,
165                 _T("invalid status bar field index in SetStatusText()") );
166
167    if ( text == m_statusText[number] )
168    {
169        // nothing changed
170        return;
171    }
172
173    m_statusText[number] = text;
174
175    RefreshField(number);
176}
177
178wxString wxStatusBarUniv::GetStatusText(int number) const
179{
180    wxCHECK_MSG( number >= 0 && number < m_nFields, wxEmptyString,
181                 _T("invalid status bar field index") );
182
183    return m_statusText[number];
184}
185
186// ----------------------------------------------------------------------------
187// fields count/widths
188// ----------------------------------------------------------------------------
189
190void wxStatusBarUniv::SetFieldsCount(int number, const int *widths)
191{
192    m_statusText.SetCount(number);
193    wxStatusBarBase::SetFieldsCount(number, widths);
194    m_widthsAbs.Empty();
195}
196
197void wxStatusBarUniv::SetStatusWidths(int n, const int widths[])
198{
199    wxStatusBarBase::SetStatusWidths(n, widths);
200
201    m_widthsAbs.Empty();
202}
203
204// ----------------------------------------------------------------------------
205// geometry
206// ----------------------------------------------------------------------------
207
208void wxStatusBarUniv::OnSize(wxSizeEvent& event)
209{
210    // we don't need to refresh the fields whose width didn't change, so find
211    // the first field whose width did change and refresh starting from it
212    int field;
213    if ( m_statusWidths )
214    {
215        for ( field = 0; field < m_nFields; field++ )
216        {
217            if ( m_statusWidths[field] < 0 )
218            {
219                // var width field
220                break;
221            }
222        }
223    }
224    else // all fields have the same width
225    {
226        // hence all fields widths have changed
227        field = 0;
228    }
229
230    if ( field < m_nFields )
231    {
232        // call this before invalidating the old widths as we want to use them,
233        // not the new ones
234        wxRect rect = DoGetFieldRect(field);
235
236        // invalidate the widths, we'll have to recalc them
237        m_widthsAbs.Empty();
238
239        // refresh everything after the first invalid field
240        rect.y = 0;
241        rect.SetRight(event.GetSize().x);
242        rect.height = event.GetSize().y;
243        RefreshRect(rect);
244    }
245
246    event.Skip();
247}
248
249bool wxStatusBarUniv::GetFieldRect(int n, wxRect& rect) const
250{
251    wxCHECK_MSG( n >= 0 && n < m_nFields, false,
252                 _T("invalid field index in GetFieldRect()") );
253
254    // this is a fix for a bug exhibited by the statbar sample: if
255    // GetFieldRect() is called from the derived class OnSize() handler, then
256    // our geometry info is wrong as our OnSize() didn't invalidate m_widthsAbs
257    // yet - so recalc it just in case
258    wxConstCast(this, wxStatusBarUniv)->m_widthsAbs.Empty();
259
260    rect = DoGetFieldRect(n);
261
262    return true;
263}
264
265wxRect wxStatusBarUniv::DoGetFieldRect(int n) const
266{
267    wxStatusBarUniv *self = wxConstCast(this, wxStatusBarUniv);
268
269    wxCoord borderBetweenFields;
270    wxRect rect = self->GetTotalFieldRect(&borderBetweenFields);
271
272    // it's the caller responsability to check this, if unsure - call
273    // GetFieldRect() instead
274    wxCHECK_MSG( !m_widthsAbs.IsEmpty(), rect,
275                 _T("can't be called if we don't have the widths") );
276
277    for ( int i = 0; i <= n; i++ )
278    {
279        rect.width = m_widthsAbs[i];
280
281        if ( i < n )
282            rect.x += rect.width + borderBetweenFields;
283    }
284
285    return rect;
286}
287
288wxCoord wxStatusBarUniv::GetHeight() const
289{
290    return GetCharHeight() + 2*GetBorderY();
291}
292
293wxSize wxStatusBarUniv::DoGetBestSize() const
294{
295    return wxSize(100, GetHeight());
296}
297
298void wxStatusBarUniv::DoSetSize(int x, int y,
299                                int width, int WXUNUSED(height),
300                                int sizeFlags)
301{
302    wxStatusBarBase::DoSetSize(x, y, width, GetHeight(), sizeFlags);
303}
304
305// ----------------------------------------------------------------------------
306// misc
307// ----------------------------------------------------------------------------
308
309void wxStatusBarUniv::SetMinHeight(int WXUNUSED(height))
310{
311    // nothing to do here, we don't support it - and why would we?
312}
313
314int wxStatusBarUniv::GetBorderX() const
315{
316    return m_renderer->GetStatusBarBorders().x +
317           m_renderer->GetStatusBarFieldMargins().x;
318}
319
320int wxStatusBarUniv::GetBorderY() const
321{
322    return m_renderer->GetStatusBarBorders().y +
323           m_renderer->GetStatusBarFieldMargins().y;
324}
325
326#endif // wxUSE_STATUSBAR
327