]> git.saurik.com Git - wxWidgets.git/blame - src/generic/statusbr.cpp
allow the user to set the contents of the status fields
[wxWidgets.git] / src / generic / statusbr.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
a71d815b 2// Name: src/generic/statusbr.cpp
ed791986 3// Purpose: wxStatusBarGeneric class implementation
c801d85f
KB
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
6aa89a22 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
c801d85f
KB
10/////////////////////////////////////////////////////////////////////////////
11
c801d85f
KB
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
76b49cf4 16 #pragma hdrstop
c801d85f
KB
17#endif
18
1e6feb95 19#if wxUSE_STATUSBAR
ed791986 20
3304646d
WS
21#include "wx/statusbr.h"
22
c801d85f 23#ifndef WX_PRECOMP
76b49cf4
WS
24 #include "wx/settings.h"
25 #include "wx/dcclient.h"
a0125cfc 26 #include "wx/toplevel.h"
c801d85f
KB
27#endif
28
2b5f62a0 29#ifdef __WXGTK20__
53b6d7a2 30 #include <gtk/gtk.h>
2b5f62a0
VZ
31#endif
32
84f68c21
VZ
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)
b64a8473 39 #include "wx/generic/statusbr.h"
c801d85f 40
b64a8473
VZ
41 IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric, wxWindow)
42#endif // wxUSE_NATIVE_STATUSBAR
ed791986 43
7b6fefbe
FM
44// Default status border dimensions
45#define wxTHICK_LINE_BORDER 2
46
47
48// ----------------------------------------------------------------------------
49// wxStatusBarGeneric
50// ----------------------------------------------------------------------------
51
ed791986
VZ
52BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow)
53 EVT_PAINT(wxStatusBarGeneric::OnPaint)
2b5f62a0
VZ
54 EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown)
55 EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown)
ed791986 56 EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged)
c801d85f 57END_EVENT_TABLE()
c801d85f 58
390015c0 59void wxStatusBarGeneric::Init()
c801d85f 60{
48f7ffbe
WS
61 m_borderX = wxTHICK_LINE_BORDER;
62 m_borderY = wxTHICK_LINE_BORDER;
c801d85f
KB
63}
64
ed791986 65wxStatusBarGeneric::~wxStatusBarGeneric()
c801d85f 66{
c801d85f
KB
67}
68
ed791986 69bool wxStatusBarGeneric::Create(wxWindow *parent,
76880b87
RL
70 wxWindowID id,
71 long style,
72 const wxString& name)
c801d85f 73{
53b6d7a2 74 style |= wxTAB_TRAVERSAL | wxFULL_REPAINT_ON_RESIZE;
48f7ffbe
WS
75 if ( !wxWindow::Create(parent, id,
76 wxDefaultPosition, wxDefaultSize,
53b6d7a2 77 style, name) )
48f7ffbe 78 return false;
c801d85f 79
48f7ffbe
WS
80 // The status bar should have a themed background
81 SetThemeEnabled( true );
82
83 InitColours();
f90566f5 84
1ca21594 85#ifdef __WXPM__
48f7ffbe 86 SetFont(*wxSMALL_FONT);
1ca21594 87#endif
c801d85f 88
7422d7c4
VZ
89 wxCoord y;
90 {
91 // Set the height according to the font and the border size
92 wxClientDC dc(this);
93 dc.SetFont(GetFont());
94
95 dc.GetTextExtent(_T("X"), NULL, &y );
96 }
48f7ffbe 97 int height = (int)( (11*y)/10 + 2*GetBorderY());
71e03035 98
48f7ffbe 99 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height);
71e03035 100
48f7ffbe 101 SetFieldsCount(1);
8aa2cea1 102
48f7ffbe 103 return true;
c801d85f
KB
104}
105
595a9493
RD
106wxSize wxStatusBarGeneric::DoGetBestSize() const
107{
108 int width, height;
9a6aafe0 109 wxCoord y;
595a9493
RD
110
111 // best width is the width of the parent
112 GetParent()->GetClientSize(&width, NULL);
113
9a6aafe0 114 // best height is as calculated above in Create()
595a9493
RD
115 wxClientDC dc((wxWindow*)this);
116 dc.SetFont(GetFont());
9a6aafe0
FM
117 dc.GetTextExtent(_T("X"), NULL, &y);
118 height = (int)((11*y)/10 + 2*GetBorderY());
595a9493
RD
119
120 return wxSize(width, height);
ca65c044 121}
595a9493 122
cc56206f 123void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths)
c801d85f 124{
390015c0 125 wxASSERT_MSG( number >= 0, _T("negative number of fields in wxStatusBar?") );
76880b87 126
7b6fefbe
FM
127 // enlarge the m_statusStrings array if needed:
128 for (size_t i = m_panes.GetCount(); i < (size_t)number; ++i)
76880b87
RL
129 m_statusStrings.Add( wxEmptyString );
130
7b6fefbe
FM
131 // shrink the m_statusStrings array if needed:
132 for (int j = (int)m_panes.GetCount() - 1; j >= number; --j)
133 m_statusStrings.RemoveAt(j);
76880b87 134
f9a961e1
DS
135 // forget the old cached pixel widths
136 m_widthsAbs.Empty();
137
d64b1c76
DS
138 wxStatusBarBase::SetFieldsCount(number, widths);
139
7b6fefbe
FM
140 wxASSERT_MSG( m_panes.GetCount() == m_statusStrings.GetCount(),
141 _T("This really should never happen, can we do away with m_panes.GetCount() here?") );
c801d85f
KB
142}
143
ed791986 144void wxStatusBarGeneric::SetStatusText(const wxString& text, int number)
c801d85f 145{
7b6fefbe 146 wxCHECK_RET( (number >= 0) && ((size_t)number < m_panes.GetCount()),
633d67bb 147 _T("invalid status bar field index") );
c801d85f 148
87ff599d
JS
149 wxString oldText = m_statusStrings[number];
150 if (oldText != text)
151 {
152 m_statusStrings[number] = text;
c801d85f 153
87ff599d
JS
154 wxRect rect;
155 GetFieldRect(number, rect);
e715f4e7 156
e5e0c727
VZ
157 Refresh(true, &rect);
158
159 // it's common to show some text in the status bar before starting a
160 // relatively lengthy operation, ensure that the text is shown to the
161 // user immediately and not after the lengthy operation end
162 Update();
87ff599d 163 }
c801d85f
KB
164}
165
ed791986 166wxString wxStatusBarGeneric::GetStatusText(int n) const
c801d85f 167{
7b6fefbe 168 wxCHECK_MSG( (n >= 0) && ((size_t)n < m_panes.GetCount()), wxEmptyString,
ed791986
VZ
169 _T("invalid status bar field index") );
170
c801d85f
KB
171 return m_statusStrings[n];
172}
173
ed791986 174void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[])
c801d85f 175{
7b6fefbe
FM
176 // only set status widths when n == number of statuswindows
177 wxCHECK_RET( (size_t)n == m_panes.GetCount(), _T("status bar field count mismatch") );
633d67bb 178
390015c0
VZ
179 // forget the old cached pixel widths
180 m_widthsAbs.Empty();
181
1f361cdd 182 wxStatusBarBase::SetStatusWidths(n, widths_field);
c801d85f
KB
183}
184
7422d7c4
VZ
185bool wxStatusBarGeneric::ShowsSizeGrip() const
186{
187 if ( !HasFlag(wxST_SIZEGRIP) )
188 return false;
189
190 wxTopLevelWindow * const
191 tlw = wxDynamicCast(wxGetTopLevelParent(GetParent()), wxTopLevelWindow);
192 return tlw && !tlw->IsMaximized() && tlw->HasFlag(wxRESIZE_BORDER);
193}
194
ed791986 195void wxStatusBarGeneric::DrawFieldText(wxDC& dc, int i)
c801d85f 196{
48f7ffbe 197 int leftMargin = 2;
c801d85f 198
48f7ffbe
WS
199 wxRect rect;
200 GetFieldRect(i, rect);
c801d85f 201
48f7ffbe 202 wxString text(GetStatusText(i));
c801d85f 203
01399dcd 204 wxCoord x = 0, y = 0;
48f7ffbe 205 dc.GetTextExtent(text, &x, &y);
c801d85f 206
48f7ffbe 207 int xpos = rect.x + leftMargin;
9a6aafe0 208 int ypos = (int) (((rect.height - y) / 2 ) + rect.y + 0.5);
ed791986 209
7c74e7fe 210#if defined( __WXGTK__ ) || defined(__WXMAC__)
48f7ffbe
WS
211 xpos++;
212 ypos++;
92976ab6 213#endif
c801d85f 214
48f7ffbe 215 dc.SetClippingRegion(rect.x, rect.y, rect.width, rect.height);
c801d85f 216
48f7ffbe 217 dc.DrawText(text, xpos, ypos);
c801d85f 218
48f7ffbe 219 dc.DestroyClippingRegion();
c801d85f
KB
220}
221
ed791986 222void wxStatusBarGeneric::DrawField(wxDC& dc, int i)
c801d85f 223{
2b5f62a0
VZ
224 wxRect rect;
225 GetFieldRect(i, rect);
c801d85f 226
7b6fefbe 227 int style = m_panes[i].nStyle;
c2919ab3
VZ
228 if (style != wxSB_FLAT)
229 {
230 // Draw border
231 // For wxSB_NORMAL:
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 // Reverse it for wxSB_RAISED
237
238 dc.SetPen((style == wxSB_RAISED) ? m_mediumShadowPen : m_hilightPen);
239
9a6aafe0 240#ifndef __WXPM__
c2919ab3
VZ
241
242 // Right and bottom lines
243 dc.DrawLine(rect.x + rect.width, rect.y,
244 rect.x + rect.width, rect.y + rect.height);
245 dc.DrawLine(rect.x + rect.width, rect.y + rect.height,
246 rect.x, rect.y + rect.height);
247
248 dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen);
249
250 // Left and top lines
251 dc.DrawLine(rect.x, rect.y + rect.height,
252 rect.x, rect.y);
253 dc.DrawLine(rect.x, rect.y,
254 rect.x + rect.width, rect.y);
9a6aafe0 255#else
c2919ab3
VZ
256
257 dc.DrawLine(rect.x + rect.width, rect.height + 2,
258 rect.x, rect.height + 2);
259 dc.DrawLine(rect.x + rect.width, rect.y,
260 rect.x + rect.width, rect.y + rect.height);
261
262 dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen);
263 dc.DrawLine(rect.x, rect.y,
264 rect.x + rect.width, rect.y);
265 dc.DrawLine(rect.x, rect.y + rect.height,
266 rect.x, rect.y);
b34590eb
DW
267
268#endif
c2919ab3 269 }
c801d85f 270
f51f94ea 271 DrawFieldText(dc, i);
c801d85f
KB
272}
273
9a6aafe0 274// Get the position and size of the field's internal bounding rectangle
ed791986 275bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const
c801d85f 276{
7b6fefbe 277 wxCHECK_MSG( (n >= 0) && ((size_t)n < m_panes.GetCount()), false,
390015c0 278 _T("invalid status bar field index") );
c801d85f 279
390015c0
VZ
280 // FIXME: workarounds for OS/2 bugs have nothing to do here (VZ)
281 int width, height;
28be2e8a 282#ifdef __WXPM__
390015c0 283 GetSize(&width, &height);
28be2e8a 284#else
390015c0 285 GetClientSize(&width, &height);
28be2e8a 286#endif
c801d85f 287
2b5f62a0
VZ
288 // we cache m_widthsAbs between calls and recompute it if client
289 // width has changed (or when it is initially empty)
9a6aafe0 290 if ( m_widthsAbs.IsEmpty() || m_lastClientWidth != width )
c801d85f 291 {
9a6aafe0
FM
292 wxConstCast(this, wxStatusBarGeneric)->m_widthsAbs = CalculateAbsWidths(width);
293
2b5f62a0 294 // remember last width for which we have recomputed the widths in pixels
9a6aafe0 295 wxConstCast(this, wxStatusBarGeneric)->m_lastClientWidth = width;
c801d85f 296 }
c801d85f 297
390015c0
VZ
298 rect.x = 0;
299 for ( int i = 0; i < n; i++ )
390015c0 300 rect.x += m_widthsAbs[i];
c801d85f 301
390015c0
VZ
302 rect.x += m_borderX;
303 rect.y = m_borderY;
c801d85f 304
390015c0
VZ
305 rect.width = m_widthsAbs[n] - 2*m_borderX;
306 rect.height = height - 2*m_borderY;
c801d85f 307
ca65c044 308 return true;
c801d85f
KB
309}
310
311// Initialize colours
ed791986 312void wxStatusBarGeneric::InitColours()
c801d85f 313{
ba959d4c 314#if defined(__WXPM__)
e715f4e7 315 m_mediumShadowPen = wxPen(wxColour(127, 127, 127), 1, wxSOLID);
b0fa2187 316 m_hilightPen = *wxWHITE_PEN;
dd7d1435 317
b0fa2187
PC
318 SetBackgroundColour(*wxLIGHT_GREY);
319 SetForegroundColour(*wxBLACK);
ba959d4c
VZ
320#else // !__WXPM__
321 m_mediumShadowPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW));
322 m_hilightPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT));
323#endif // __WXPM__/!__WXPM__
c801d85f
KB
324}
325
ed791986
VZ
326void wxStatusBarGeneric::SetMinHeight(int height)
327{
328 // check that this min height is not less than minimal height for the
329 // current font
330 wxClientDC dc(this);
331 wxCoord y;
2b5f62a0 332 dc.GetTextExtent( wxT("X"), NULL, &y );
ed791986
VZ
333
334 if ( height > (11*y)/10 )
335 {
422d0ff0 336 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height + 2*m_borderY);
ed791986
VZ
337 }
338}
339
9a6aafe0
FM
340
341// ----------------------------------------------------------------------------
342// wxStatusBarGeneric - event handlers
343// ----------------------------------------------------------------------------
344
345void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) )
346{
347 wxPaintDC dc(this);
348
349#ifdef __WXGTK20__
350 // Draw grip first
351 if ( ShowsSizeGrip() )
352 {
353 int width, height;
354 GetClientSize(&width, &height);
355
356 if (GetLayoutDirection() == wxLayout_RightToLeft)
357 {
358 gtk_paint_resize_grip( m_widget->style,
359 GTKGetDrawingWindow(),
360 (GtkStateType) GTK_WIDGET_STATE (m_widget),
361 NULL,
362 m_widget,
363 "statusbar",
364 GDK_WINDOW_EDGE_SOUTH_WEST,
365 2, 2, height-2, height-4 );
366 }
367 else
368 {
369 gtk_paint_resize_grip( m_widget->style,
370 GTKGetDrawingWindow(),
371 (GtkStateType) GTK_WIDGET_STATE (m_widget),
372 NULL,
373 m_widget,
374 "statusbar",
375 GDK_WINDOW_EDGE_SOUTH_EAST,
376 width-height-2, 2, height-2, height-4 );
377 }
378 }
379#endif // __WXGTK20__
380
381 if (GetFont().IsOk())
382 dc.SetFont(GetFont());
383
384 dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
385
386 for (size_t i = 0; i < m_panes.GetCount(); i ++)
387 DrawField(dc, i);
388}
389
390// Responds to colour changes, and passes event on to children.
391void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event)
392{
393 InitColours();
394
395 // Propagate the event to the non-top-level children
396 wxWindow::OnSysColourChanged(event);
397}
398
2b5f62a0 399void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event)
390015c0 400{
2b5f62a0
VZ
401#ifdef __WXGTK20__
402 int width, height;
403 GetClientSize(&width, &height);
8aa2cea1 404
7422d7c4 405 if ( ShowsSizeGrip() && (event.GetX() > width-height) )
2b5f62a0
VZ
406 {
407 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget );
408
409 if (!GTK_IS_WINDOW (ancestor))
410 return;
390015c0 411
08f53168 412 GdkWindow *source = GTKGetDrawingWindow();
2b5f62a0
VZ
413
414 int org_x = 0;
415 int org_y = 0;
416 gdk_window_get_origin( source, &org_x, &org_y );
417
fc2d4209
RR
418 if (GetLayoutDirection() == wxLayout_RightToLeft)
419 {
420 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
421 GDK_WINDOW_EDGE_SOUTH_WEST,
422 1,
423 org_x - event.GetX() + GetSize().x ,
424 org_y + event.GetY(),
425 0);
426 }
427 else
428 {
429 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
2b5f62a0
VZ
430 GDK_WINDOW_EDGE_SOUTH_EAST,
431 1,
8aa2cea1
RD
432 org_x + event.GetX(),
433 org_y + event.GetY(),
2b5f62a0 434 0);
fc2d4209 435 }
2b5f62a0
VZ
436 }
437 else
438 {
ca65c044 439 event.Skip( true );
2b5f62a0
VZ
440 }
441#else
ca65c044 442 event.Skip( true );
2b5f62a0
VZ
443#endif
444}
445
446void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event)
447{
448#ifdef __WXGTK20__
449 int width, height;
450 GetClientSize(&width, &height);
8aa2cea1 451
7422d7c4 452 if ( ShowsSizeGrip() && (event.GetX() > width-height) )
2b5f62a0
VZ
453 {
454 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget );
455
456 if (!GTK_IS_WINDOW (ancestor))
457 return;
458
08f53168 459 GdkWindow *source = GTKGetDrawingWindow();
2b5f62a0
VZ
460
461 int org_x = 0;
462 int org_y = 0;
463 gdk_window_get_origin( source, &org_x, &org_y );
8aa2cea1 464
2b5f62a0
VZ
465 gtk_window_begin_move_drag (GTK_WINDOW (ancestor),
466 2,
8aa2cea1
RD
467 org_x + event.GetX(),
468 org_y + event.GetY(),
2b5f62a0
VZ
469 0);
470 }
471 else
472 {
ca65c044 473 event.Skip( true );
2b5f62a0
VZ
474 }
475#else
ca65c044 476 event.Skip( true );
2b5f62a0 477#endif
390015c0
VZ
478}
479
1e6feb95 480#endif // wxUSE_STATUSBAR