]> git.saurik.com Git - wxWidgets.git/blame - src/generic/statusbr.cpp
Restore DrawRadioButton to the main wxRenderer API, create a method overload for...
[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"
c34d2f35 27 #include "wx/control.h"
c801d85f
KB
28#endif
29
2b5f62a0 30#ifdef __WXGTK20__
53b6d7a2 31 #include <gtk/gtk.h>
2b5f62a0
VZ
32#endif
33
84f68c21
VZ
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)
b64a8473 40 #include "wx/generic/statusbr.h"
c801d85f 41
b64a8473
VZ
42 IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric, wxWindow)
43#endif // wxUSE_NATIVE_STATUSBAR
ed791986 44
7b6fefbe
FM
45// Default status border dimensions
46#define wxTHICK_LINE_BORDER 2
47
78612fa6
FM
48// Margin between the field text and the field rect
49#define wxFIELD_TEXT_MARGIN 2
50
7b6fefbe
FM
51
52// ----------------------------------------------------------------------------
53// wxStatusBarGeneric
54// ----------------------------------------------------------------------------
55
ed791986
VZ
56BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow)
57 EVT_PAINT(wxStatusBarGeneric::OnPaint)
ba4589db 58 EVT_SIZE(wxStatusBarGeneric::OnSize)
2b5f62a0
VZ
59 EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown)
60 EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown)
ed791986 61 EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged)
c801d85f 62END_EVENT_TABLE()
c801d85f 63
390015c0 64void wxStatusBarGeneric::Init()
c801d85f 65{
48f7ffbe
WS
66 m_borderX = wxTHICK_LINE_BORDER;
67 m_borderY = wxTHICK_LINE_BORDER;
c801d85f
KB
68}
69
ed791986 70wxStatusBarGeneric::~wxStatusBarGeneric()
c801d85f 71{
c801d85f
KB
72}
73
ed791986 74bool wxStatusBarGeneric::Create(wxWindow *parent,
76880b87
RL
75 wxWindowID id,
76 long style,
77 const wxString& name)
c801d85f 78{
53b6d7a2 79 style |= wxTAB_TRAVERSAL | wxFULL_REPAINT_ON_RESIZE;
48f7ffbe
WS
80 if ( !wxWindow::Create(parent, id,
81 wxDefaultPosition, wxDefaultSize,
53b6d7a2 82 style, name) )
48f7ffbe 83 return false;
c801d85f 84
48f7ffbe
WS
85 // The status bar should have a themed background
86 SetThemeEnabled( true );
87
88 InitColours();
f90566f5 89
1ca21594 90#ifdef __WXPM__
48f7ffbe 91 SetFont(*wxSMALL_FONT);
1ca21594 92#endif
c801d85f 93
ba4589db 94 int height = (int)((11*GetCharHeight())/10 + 2*GetBorderY());
48f7ffbe 95 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height);
71e03035 96
48f7ffbe 97 SetFieldsCount(1);
8aa2cea1 98
48f7ffbe 99 return true;
c801d85f
KB
100}
101
595a9493
RD
102wxSize wxStatusBarGeneric::DoGetBestSize() const
103{
104 int width, height;
105
106 // best width is the width of the parent
ba4589db
FM
107 if (GetParent())
108 GetParent()->GetClientSize(&width, NULL);
109 else
110 width = 80; // a dummy value
595a9493 111
9a6aafe0 112 // best height is as calculated above in Create()
ba4589db 113 height = (int)((11*GetCharHeight())/10 + 2*GetBorderY());
595a9493
RD
114
115 return wxSize(width, height);
ca65c044 116}
595a9493 117
cc56206f 118void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths)
c801d85f 119{
390015c0 120 wxASSERT_MSG( number >= 0, _T("negative number of fields in wxStatusBar?") );
76880b87 121
0cd15959
FM
122 // this will result in a call to SetStatusWidths() and thus an update to our
123 // m_widthsAbs cache
d64b1c76 124 wxStatusBarBase::SetFieldsCount(number, widths);
c801d85f
KB
125}
126
ed791986 127void wxStatusBarGeneric::SetStatusText(const wxString& text, int number)
c801d85f 128{
7b6fefbe 129 wxCHECK_RET( (number >= 0) && ((size_t)number < m_panes.GetCount()),
633d67bb 130 _T("invalid status bar field index") );
c801d85f 131
0cd15959 132 wxString oldText = GetStatusText(number);
87ff599d
JS
133 if (oldText != text)
134 {
0cd15959 135 wxStatusBarBase::SetStatusText(text, number);
c801d85f 136
87ff599d
JS
137 wxRect rect;
138 GetFieldRect(number, rect);
e715f4e7 139
e5e0c727
VZ
140 Refresh(true, &rect);
141
142 // it's common to show some text in the status bar before starting a
143 // relatively lengthy operation, ensure that the text is shown to the
144 // user immediately and not after the lengthy operation end
145 Update();
87ff599d 146 }
c801d85f
KB
147}
148
ed791986 149void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[])
c801d85f 150{
7b6fefbe
FM
151 // only set status widths when n == number of statuswindows
152 wxCHECK_RET( (size_t)n == m_panes.GetCount(), _T("status bar field count mismatch") );
633d67bb 153
1f361cdd 154 wxStatusBarBase::SetStatusWidths(n, widths_field);
0cd15959
FM
155
156 // update cache
157 int width;
158 GetClientSize(&width, &m_lastClientHeight);
159 m_widthsAbs = CalculateAbsWidths(width);
c801d85f
KB
160}
161
7422d7c4
VZ
162bool wxStatusBarGeneric::ShowsSizeGrip() const
163{
164 if ( !HasFlag(wxST_SIZEGRIP) )
165 return false;
166
167 wxTopLevelWindow * const
168 tlw = wxDynamicCast(wxGetTopLevelParent(GetParent()), wxTopLevelWindow);
169 return tlw && !tlw->IsMaximized() && tlw->HasFlag(wxRESIZE_BORDER);
170}
171
ba4589db 172void wxStatusBarGeneric::DrawFieldText(wxDC& dc, const wxRect& rect, int i, int textHeight)
c801d85f 173{
ba4589db
FM
174 wxString text(GetStatusText(i));
175 if (text.empty())
176 return; // optimization
c801d85f 177
ba4589db
FM
178 int xpos = rect.x + wxFIELD_TEXT_MARGIN,
179 maxWidth = rect.width - 2*wxFIELD_TEXT_MARGIN,
180 ypos = (int) (((rect.height - textHeight) / 2) + rect.y + 0.5);
78612fa6
FM
181
182 if (ShowsSizeGrip())
183 {
184 // don't write text over the size grip:
185 // NOTE: overloading DoGetClientSize() and GetClientAreaOrigin() wouldn't
186 // work because the adjustment needs to be done only when drawing
187 // the field text and not also when drawing the background, the
188 // size grip itself, etc
ba4589db
FM
189 if ((GetLayoutDirection() == wxLayout_RightToLeft && i == 0) ||
190 (GetLayoutDirection() != wxLayout_RightToLeft &&
191 i == (int)m_panes.GetCount()-1))
78612fa6 192 {
ba4589db 193 const wxRect& gripRc = GetSizeGripRect();
78612fa6 194
ba4589db
FM
195 // NOTE: we don't need any special treatment wrt to the layout direction
196 // since DrawText() will automatically adjust the origin of the
197 // text accordingly to the layout in use
78612fa6 198
ba4589db 199 maxWidth -= gripRc.width;
78612fa6
FM
200 }
201 }
202
203 // eventually ellipsize the text so that it fits the field width
78612fa6
FM
204 text = wxControl::Ellipsize(
205 text, dc,
206 GetLayoutDirection() == wxLayout_RightToLeft ? wxELLIPSIZE_START : wxELLIPSIZE_END,
ba4589db 207 maxWidth,
78612fa6
FM
208 wxELLIPSIZE_EXPAND_TAB);
209 // Ellipsize() will do something only if necessary
c801d85f 210
7c74e7fe 211#if defined( __WXGTK__ ) || defined(__WXMAC__)
48f7ffbe
WS
212 xpos++;
213 ypos++;
92976ab6 214#endif
c801d85f 215
78612fa6 216 // draw the text
48f7ffbe 217 dc.DrawText(text, xpos, ypos);
c801d85f
KB
218}
219
ba4589db 220void wxStatusBarGeneric::DrawField(wxDC& dc, int i, int textHeight)
c801d85f 221{
2b5f62a0
VZ
222 wxRect rect;
223 GetFieldRect(i, rect);
c801d85f 224
ba4589db
FM
225 if (rect.GetWidth() <= 0)
226 return; // happens when the status bar is shrinked in a very small area!
227
7b6fefbe 228 int style = m_panes[i].nStyle;
c2919ab3
VZ
229 if (style != wxSB_FLAT)
230 {
231 // Draw border
232 // For wxSB_NORMAL:
233 // Have grey background, plus 3-d border -
234 // One black rectangle.
235 // Inside this, left and top sides - dark grey. Bottom and right -
236 // white.
237 // Reverse it for wxSB_RAISED
238
239 dc.SetPen((style == wxSB_RAISED) ? m_mediumShadowPen : m_hilightPen);
240
9a6aafe0 241#ifndef __WXPM__
c2919ab3
VZ
242
243 // Right and bottom lines
244 dc.DrawLine(rect.x + rect.width, rect.y,
245 rect.x + rect.width, rect.y + rect.height);
246 dc.DrawLine(rect.x + rect.width, rect.y + rect.height,
247 rect.x, rect.y + rect.height);
248
249 dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen);
250
251 // Left and top lines
252 dc.DrawLine(rect.x, rect.y + rect.height,
253 rect.x, rect.y);
254 dc.DrawLine(rect.x, rect.y,
255 rect.x + rect.width, rect.y);
9a6aafe0 256#else
c2919ab3
VZ
257
258 dc.DrawLine(rect.x + rect.width, rect.height + 2,
259 rect.x, rect.height + 2);
260 dc.DrawLine(rect.x + rect.width, rect.y,
261 rect.x + rect.width, rect.y + rect.height);
262
263 dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen);
264 dc.DrawLine(rect.x, rect.y,
265 rect.x + rect.width, rect.y);
266 dc.DrawLine(rect.x, rect.y + rect.height,
267 rect.x, rect.y);
b34590eb 268#endif
c2919ab3 269 }
c801d85f 270
ba4589db 271 DrawFieldText(dc, rect, i, textHeight);
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
ba4589db
FM
280 if (m_widthsAbs.IsEmpty())
281 return false;
c801d85f 282
390015c0
VZ
283 rect.x = 0;
284 for ( int i = 0; i < n; i++ )
390015c0 285 rect.x += m_widthsAbs[i];
390015c0 286 rect.x += m_borderX;
c801d85f 287
ba4589db 288 rect.y = m_borderY;
390015c0 289 rect.width = m_widthsAbs[n] - 2*m_borderX;
ba4589db 290 rect.height = m_lastClientHeight - 2*m_borderY;
c801d85f 291
ca65c044 292 return true;
c801d85f
KB
293}
294
295// Initialize colours
ed791986 296void wxStatusBarGeneric::InitColours()
c801d85f 297{
ba959d4c 298#if defined(__WXPM__)
c34d2f35 299 m_mediumShadowPen = wxPen(wxColour(127, 127, 127));
b0fa2187 300 m_hilightPen = *wxWHITE_PEN;
dd7d1435 301
b0fa2187
PC
302 SetBackgroundColour(*wxLIGHT_GREY);
303 SetForegroundColour(*wxBLACK);
ba959d4c
VZ
304#else // !__WXPM__
305 m_mediumShadowPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW));
306 m_hilightPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT));
307#endif // __WXPM__/!__WXPM__
c801d85f
KB
308}
309
ed791986
VZ
310void wxStatusBarGeneric::SetMinHeight(int height)
311{
312 // check that this min height is not less than minimal height for the
ba4589db
FM
313 // current font (min height is as calculated above in Create() except for border)
314 int minHeight = (int)((11*GetCharHeight())/10);
ed791986 315
ba4589db 316 if ( height > minHeight )
422d0ff0 317 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height + 2*m_borderY);
ed791986
VZ
318}
319
78612fa6
FM
320wxRect wxStatusBarGeneric::GetSizeGripRect() const
321{
322 int width, height;
323 wxWindow::DoGetClientSize(&width, &height);
324
325 if (GetLayoutDirection() == wxLayout_RightToLeft)
326 return wxRect(2, 2, height-2, height-4);
327 else
328 return wxRect(width-height-2, 2, height-2, height-4);
329}
9a6aafe0
FM
330
331// ----------------------------------------------------------------------------
332// wxStatusBarGeneric - event handlers
333// ----------------------------------------------------------------------------
334
335void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) )
336{
337 wxPaintDC dc(this);
338
339#ifdef __WXGTK20__
340 // Draw grip first
341 if ( ShowsSizeGrip() )
342 {
78612fa6
FM
343 const wxRect& rc = GetSizeGripRect();
344 GdkWindowEdge edge =
345 GetLayoutDirection() == wxLayout_RightToLeft ? GDK_WINDOW_EDGE_SOUTH_WEST :
346 GDK_WINDOW_EDGE_SOUTH_EAST;
347 gtk_paint_resize_grip( m_widget->style,
348 GTKGetDrawingWindow(),
349 (GtkStateType) GTK_WIDGET_STATE (m_widget),
350 NULL,
351 m_widget,
352 "statusbar",
353 edge,
354 rc.x, rc.y, rc.width, rc.height );
9a6aafe0
FM
355 }
356#endif // __WXGTK20__
357
358 if (GetFont().IsOk())
359 dc.SetFont(GetFont());
360
ba4589db
FM
361 // compute char height only once for all panes:
362 int textHeight = dc.GetCharHeight();
9a6aafe0 363
ba4589db 364 dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
9a6aafe0 365 for (size_t i = 0; i < m_panes.GetCount(); i ++)
ba4589db 366 DrawField(dc, i, textHeight);
9a6aafe0
FM
367}
368
369// Responds to colour changes, and passes event on to children.
370void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event)
371{
372 InitColours();
373
374 // Propagate the event to the non-top-level children
375 wxWindow::OnSysColourChanged(event);
376}
377
2b5f62a0 378void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event)
390015c0 379{
2b5f62a0
VZ
380#ifdef __WXGTK20__
381 int width, height;
382 GetClientSize(&width, &height);
8aa2cea1 383
7422d7c4 384 if ( ShowsSizeGrip() && (event.GetX() > width-height) )
2b5f62a0
VZ
385 {
386 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget );
387
388 if (!GTK_IS_WINDOW (ancestor))
389 return;
390015c0 390
08f53168 391 GdkWindow *source = GTKGetDrawingWindow();
2b5f62a0
VZ
392
393 int org_x = 0;
394 int org_y = 0;
395 gdk_window_get_origin( source, &org_x, &org_y );
396
fc2d4209
RR
397 if (GetLayoutDirection() == wxLayout_RightToLeft)
398 {
399 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
400 GDK_WINDOW_EDGE_SOUTH_WEST,
401 1,
402 org_x - event.GetX() + GetSize().x ,
403 org_y + event.GetY(),
404 0);
405 }
406 else
407 {
408 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
2b5f62a0
VZ
409 GDK_WINDOW_EDGE_SOUTH_EAST,
410 1,
8aa2cea1
RD
411 org_x + event.GetX(),
412 org_y + event.GetY(),
2b5f62a0 413 0);
fc2d4209 414 }
2b5f62a0
VZ
415 }
416 else
417 {
ca65c044 418 event.Skip( true );
2b5f62a0
VZ
419 }
420#else
ca65c044 421 event.Skip( true );
2b5f62a0
VZ
422#endif
423}
424
425void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event)
426{
427#ifdef __WXGTK20__
428 int width, height;
429 GetClientSize(&width, &height);
8aa2cea1 430
7422d7c4 431 if ( ShowsSizeGrip() && (event.GetX() > width-height) )
2b5f62a0
VZ
432 {
433 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget );
434
435 if (!GTK_IS_WINDOW (ancestor))
436 return;
437
08f53168 438 GdkWindow *source = GTKGetDrawingWindow();
2b5f62a0
VZ
439
440 int org_x = 0;
441 int org_y = 0;
442 gdk_window_get_origin( source, &org_x, &org_y );
8aa2cea1 443
2b5f62a0
VZ
444 gtk_window_begin_move_drag (GTK_WINDOW (ancestor),
445 2,
8aa2cea1
RD
446 org_x + event.GetX(),
447 org_y + event.GetY(),
2b5f62a0
VZ
448 0);
449 }
450 else
451 {
ca65c044 452 event.Skip( true );
2b5f62a0
VZ
453 }
454#else
ca65c044 455 event.Skip( true );
2b5f62a0 456#endif
390015c0
VZ
457}
458
ba4589db
FM
459void wxStatusBarGeneric::OnSize(wxSizeEvent& WXUNUSED(event))
460{
461 // FIXME: workarounds for OS/2 bugs have nothing to do here (VZ)
462 int width;
463#ifdef __WXPM__
464 GetSize(&width, &m_lastClientHeight);
465#else
466 GetClientSize(&width, &m_lastClientHeight);
467#endif
468
469 // recompute the cache of the field widths if the status bar width has changed
470 m_widthsAbs = CalculateAbsWidths(width);
471}
472
1e6feb95 473#endif // wxUSE_STATUSBAR