]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/statusbr.cpp
reset the tooltip text before changing it, this apparently prevents a spurious redraw...
[wxWidgets.git] / src / generic / statusbr.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/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
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
19#if wxUSE_STATUSBAR
20
21#include "wx/statusbr.h"
22
23#ifndef WX_PRECOMP
24 #include "wx/settings.h"
25 #include "wx/dcclient.h"
26 #include "wx/toplevel.h"
27 #include "wx/control.h"
28#endif
29
30#ifdef __WXGTK20__
31 #include <gtk/gtk.h>
32#endif
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// Default status border dimensions
46#define wxTHICK_LINE_BORDER 2
47
48// Margin between the field text and the field rect
49#define wxFIELD_TEXT_MARGIN 2
50
51
52// ----------------------------------------------------------------------------
53// wxStatusBarGeneric
54// ----------------------------------------------------------------------------
55
56BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow)
57 EVT_PAINT(wxStatusBarGeneric::OnPaint)
58 EVT_SIZE(wxStatusBarGeneric::OnSize)
59 EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown)
60 EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown)
61 EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged)
62END_EVENT_TABLE()
63
64void wxStatusBarGeneric::Init()
65{
66 m_borderX = wxTHICK_LINE_BORDER;
67 m_borderY = wxTHICK_LINE_BORDER;
68}
69
70wxStatusBarGeneric::~wxStatusBarGeneric()
71{
72}
73
74bool wxStatusBarGeneric::Create(wxWindow *parent,
75 wxWindowID id,
76 long style,
77 const wxString& name)
78{
79 style |= wxTAB_TRAVERSAL | wxFULL_REPAINT_ON_RESIZE;
80 if ( !wxWindow::Create(parent, id,
81 wxDefaultPosition, wxDefaultSize,
82 style, name) )
83 return false;
84
85 // The status bar should have a themed background
86 SetThemeEnabled( true );
87
88 InitColours();
89
90#ifdef __WXPM__
91 SetFont(*wxSMALL_FONT);
92#endif
93
94 int height = (int)((11*GetCharHeight())/10 + 2*GetBorderY());
95 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height);
96
97 SetFieldsCount(1);
98
99 return true;
100}
101
102wxSize wxStatusBarGeneric::DoGetBestSize() const
103{
104 int width, height;
105
106 // best width is the width of the parent
107 if (GetParent())
108 GetParent()->GetClientSize(&width, NULL);
109 else
110 width = 80; // a dummy value
111
112 // best height is as calculated above in Create()
113 height = (int)((11*GetCharHeight())/10 + 2*GetBorderY());
114
115 return wxSize(width, height);
116}
117
118void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths)
119{
120 wxASSERT_MSG( number >= 0, _T("negative number of fields in wxStatusBar?") );
121
122 // this will result in a call to SetStatusWidths() and thus an update to our
123 // m_widthsAbs cache
124 wxStatusBarBase::SetFieldsCount(number, widths);
125}
126
127void wxStatusBarGeneric::SetStatusText(const wxString& text, int number)
128{
129 wxCHECK_RET( (number >= 0) && ((size_t)number < m_panes.GetCount()),
130 _T("invalid status bar field index") );
131
132 wxString oldText = GetStatusText(number);
133 if (oldText != text)
134 {
135 wxStatusBarBase::SetStatusText(text, number);
136
137 wxRect rect;
138 GetFieldRect(number, rect);
139
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();
146 }
147}
148
149void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[])
150{
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") );
153
154 wxStatusBarBase::SetStatusWidths(n, widths_field);
155
156 // update cache
157 int width;
158 GetClientSize(&width, &m_lastClientHeight);
159 m_widthsAbs = CalculateAbsWidths(width);
160}
161
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
172void wxStatusBarGeneric::DrawFieldText(wxDC& dc, const wxRect& rect, int i, int textHeight)
173{
174 wxString text(GetStatusText(i));
175 if (text.empty())
176 return; // optimization
177
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);
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
189 if ((GetLayoutDirection() == wxLayout_RightToLeft && i == 0) ||
190 (GetLayoutDirection() != wxLayout_RightToLeft &&
191 i == (int)m_panes.GetCount()-1))
192 {
193 const wxRect& gripRc = GetSizeGripRect();
194
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
198
199 maxWidth -= gripRc.width;
200 }
201 }
202
203 // eventually ellipsize the text so that it fits the field width
204 text = wxControl::Ellipsize(
205 text, dc,
206 GetLayoutDirection() == wxLayout_RightToLeft ? wxELLIPSIZE_START : wxELLIPSIZE_END,
207 maxWidth,
208 wxELLIPSIZE_EXPAND_TAB);
209 // Ellipsize() will do something only if necessary
210
211#if defined( __WXGTK__ ) || defined(__WXMAC__)
212 xpos++;
213 ypos++;
214#endif
215
216 // draw the text
217 dc.DrawText(text, xpos, ypos);
218}
219
220void wxStatusBarGeneric::DrawField(wxDC& dc, int i, int textHeight)
221{
222 wxRect rect;
223 GetFieldRect(i, rect);
224
225 if (rect.GetWidth() <= 0)
226 return; // happens when the status bar is shrinked in a very small area!
227
228 int style = m_panes[i].nStyle;
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
241#ifndef __WXPM__
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);
256#else
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);
268#endif
269 }
270
271 DrawFieldText(dc, rect, i, textHeight);
272}
273
274// Get the position and size of the field's internal bounding rectangle
275bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const
276{
277 wxCHECK_MSG( (n >= 0) && ((size_t)n < m_panes.GetCount()), false,
278 _T("invalid status bar field index") );
279
280 if (m_widthsAbs.IsEmpty())
281 return false;
282
283 rect.x = 0;
284 for ( int i = 0; i < n; i++ )
285 rect.x += m_widthsAbs[i];
286 rect.x += m_borderX;
287
288 rect.y = m_borderY;
289 rect.width = m_widthsAbs[n] - 2*m_borderX;
290 rect.height = m_lastClientHeight - 2*m_borderY;
291
292 return true;
293}
294
295// Initialize colours
296void wxStatusBarGeneric::InitColours()
297{
298#if defined(__WXPM__)
299 m_mediumShadowPen = wxPen(wxColour(127, 127, 127));
300 m_hilightPen = *wxWHITE_PEN;
301
302 SetBackgroundColour(*wxLIGHT_GREY);
303 SetForegroundColour(*wxBLACK);
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__
308}
309
310void wxStatusBarGeneric::SetMinHeight(int height)
311{
312 // check that this min height is not less than minimal height for the
313 // current font (min height is as calculated above in Create() except for border)
314 int minHeight = (int)((11*GetCharHeight())/10);
315
316 if ( height > minHeight )
317 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height + 2*m_borderY);
318}
319
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}
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 {
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 );
355 }
356#endif // __WXGTK20__
357
358 if (GetFont().IsOk())
359 dc.SetFont(GetFont());
360
361 // compute char height only once for all panes:
362 int textHeight = dc.GetCharHeight();
363
364 dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
365 for (size_t i = 0; i < m_panes.GetCount(); i ++)
366 DrawField(dc, i, textHeight);
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
378void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event)
379{
380#ifdef __WXGTK20__
381 int width, height;
382 GetClientSize(&width, &height);
383
384 if ( ShowsSizeGrip() && (event.GetX() > width-height) )
385 {
386 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget );
387
388 if (!GTK_IS_WINDOW (ancestor))
389 return;
390
391 GdkWindow *source = GTKGetDrawingWindow();
392
393 int org_x = 0;
394 int org_y = 0;
395 gdk_window_get_origin( source, &org_x, &org_y );
396
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),
409 GDK_WINDOW_EDGE_SOUTH_EAST,
410 1,
411 org_x + event.GetX(),
412 org_y + event.GetY(),
413 0);
414 }
415 }
416 else
417 {
418 event.Skip( true );
419 }
420#else
421 event.Skip( true );
422#endif
423}
424
425void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event)
426{
427#ifdef __WXGTK20__
428 int width, height;
429 GetClientSize(&width, &height);
430
431 if ( ShowsSizeGrip() && (event.GetX() > width-height) )
432 {
433 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget );
434
435 if (!GTK_IS_WINDOW (ancestor))
436 return;
437
438 GdkWindow *source = GTKGetDrawingWindow();
439
440 int org_x = 0;
441 int org_y = 0;
442 gdk_window_get_origin( source, &org_x, &org_y );
443
444 gtk_window_begin_move_drag (GTK_WINDOW (ancestor),
445 2,
446 org_x + event.GetX(),
447 org_y + event.GetY(),
448 0);
449 }
450 else
451 {
452 event.Skip( true );
453 }
454#else
455 event.Skip( true );
456#endif
457}
458
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
473#endif // wxUSE_STATUSBAR