don't show size grip if the window the status bar is attached to is maximized or...
[wxWidgets.git] / src / generic / statusbr.cpp
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 #endif
27
28 #ifdef __WXGTK20__
29 #include <gtk/gtk.h>
30 #endif
31
32 // we only have to do it here when we use wxStatusBarGeneric in addition to the
33 // standard wxStatusBar class, if wxStatusBarGeneric is the same as
34 // wxStatusBar, then the corresponding IMPLEMENT_DYNAMIC_CLASS is already in
35 // common/statbar.cpp
36 #if defined(__WXMAC__) || \
37 (defined(wxUSE_NATIVE_STATUSBAR) && wxUSE_NATIVE_STATUSBAR)
38 #include "wx/generic/statusbr.h"
39
40 IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric, wxWindow)
41 #endif // wxUSE_NATIVE_STATUSBAR
42
43 BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow)
44 EVT_PAINT(wxStatusBarGeneric::OnPaint)
45 EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown)
46 EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown)
47 EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged)
48 END_EVENT_TABLE()
49
50 // Default status border dimensions
51 #define wxTHICK_LINE_BORDER 2
52
53 void wxStatusBarGeneric::Init()
54 {
55 m_borderX = wxTHICK_LINE_BORDER;
56 m_borderY = wxTHICK_LINE_BORDER;
57 }
58
59 wxStatusBarGeneric::~wxStatusBarGeneric()
60 {
61 }
62
63 bool wxStatusBarGeneric::Create(wxWindow *parent,
64 wxWindowID id,
65 long style,
66 const wxString& name)
67 {
68 style |= wxTAB_TRAVERSAL | wxFULL_REPAINT_ON_RESIZE;
69 if ( !wxWindow::Create(parent, id,
70 wxDefaultPosition, wxDefaultSize,
71 style, name) )
72 return false;
73
74 // The status bar should have a themed background
75 SetThemeEnabled( true );
76
77 InitColours();
78
79 #ifdef __WXPM__
80 SetFont(*wxSMALL_FONT);
81 #endif
82
83 wxCoord y;
84 {
85 // Set the height according to the font and the border size
86 wxClientDC dc(this);
87 dc.SetFont(GetFont());
88
89 dc.GetTextExtent(_T("X"), NULL, &y );
90 }
91 int height = (int)( (11*y)/10 + 2*GetBorderY());
92
93 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height);
94
95 SetFieldsCount(1);
96
97 return true;
98 }
99
100
101 wxSize wxStatusBarGeneric::DoGetBestSize() const
102 {
103 int width, height;
104
105 // best width is the width of the parent
106 GetParent()->GetClientSize(&width, NULL);
107
108 // best height is as calculated above in Create
109 wxClientDC dc((wxWindow*)this);
110 dc.SetFont(GetFont());
111 wxCoord y;
112 dc.GetTextExtent(_T("X"), NULL, &y );
113 height = (int)( (11*y)/10 + 2*GetBorderY());
114
115 return wxSize(width, height);
116 }
117
118 void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths)
119 {
120 wxASSERT_MSG( number >= 0, _T("negative number of fields in wxStatusBar?") );
121
122 int i;
123 for(i = m_nFields; i < number; ++i)
124 m_statusStrings.Add( wxEmptyString );
125
126 for (i = m_nFields - 1; i >= number; --i)
127 m_statusStrings.RemoveAt(i);
128
129 // forget the old cached pixel widths
130 m_widthsAbs.Empty();
131
132 wxStatusBarBase::SetFieldsCount(number, widths);
133
134 wxASSERT_MSG( m_nFields == (int)m_statusStrings.GetCount(),
135 _T("This really should never happen, can we do away with m_nFields here?") );
136 }
137
138 void wxStatusBarGeneric::SetStatusText(const wxString& text, int number)
139 {
140 wxCHECK_RET( (number >= 0) && (number < m_nFields),
141 _T("invalid status bar field index") );
142
143 wxString oldText = m_statusStrings[number];
144 if (oldText != text)
145 {
146 m_statusStrings[number] = text;
147
148 wxRect rect;
149 GetFieldRect(number, rect);
150
151 Refresh(true, &rect);
152
153 // it's common to show some text in the status bar before starting a
154 // relatively lengthy operation, ensure that the text is shown to the
155 // user immediately and not after the lengthy operation end
156 Update();
157 }
158 }
159
160 wxString wxStatusBarGeneric::GetStatusText(int n) const
161 {
162 wxCHECK_MSG( (n >= 0) && (n < m_nFields), wxEmptyString,
163 _T("invalid status bar field index") );
164
165 return m_statusStrings[n];
166 }
167
168 void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[])
169 {
170 // only set status widths, when n == number of statuswindows
171 wxCHECK_RET( n == m_nFields, _T("status bar field count mismatch") );
172
173 // delete the old widths in any case - this function may be used to reset
174 // the widths to the default (all equal)
175 // MBN: this is incompatible with at least wxMSW and wxMAC and not
176 // documented, but let's keep it for now
177 ReinitWidths();
178
179 // forget the old cached pixel widths
180 m_widthsAbs.Empty();
181
182 if ( !widths_field )
183 {
184 // not an error, see the comment above
185 Refresh();
186 return;
187 }
188
189 wxStatusBarBase::SetStatusWidths(n, widths_field);
190 }
191
192 bool wxStatusBarGeneric::ShowsSizeGrip() const
193 {
194 if ( !HasFlag(wxST_SIZEGRIP) )
195 return false;
196
197 wxTopLevelWindow * const
198 tlw = wxDynamicCast(wxGetTopLevelParent(GetParent()), wxTopLevelWindow);
199 return tlw && !tlw->IsMaximized() && tlw->HasFlag(wxRESIZE_BORDER);
200 }
201
202 void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) )
203 {
204 wxPaintDC dc(this);
205
206 #ifdef __WXGTK20__
207 // Draw grip first
208 if ( ShowsSizeGrip() )
209 {
210 int width, height;
211 GetClientSize(&width, &height);
212
213 if (GetLayoutDirection() == wxLayout_RightToLeft)
214 {
215 gtk_paint_resize_grip( m_widget->style,
216 GTKGetDrawingWindow(),
217 (GtkStateType) GTK_WIDGET_STATE (m_widget),
218 NULL,
219 m_widget,
220 "statusbar",
221 GDK_WINDOW_EDGE_SOUTH_WEST,
222 2, 2, height-2, height-4 );
223 }
224 else
225 {
226 gtk_paint_resize_grip( m_widget->style,
227 GTKGetDrawingWindow(),
228 (GtkStateType) GTK_WIDGET_STATE (m_widget),
229 NULL,
230 m_widget,
231 "statusbar",
232 GDK_WINDOW_EDGE_SOUTH_EAST,
233 width-height-2, 2, height-2, height-4 );
234 }
235 }
236 #endif // __WXGTK20__
237
238 if (GetFont().Ok())
239 dc.SetFont(GetFont());
240
241 dc.SetBackgroundMode(wxTRANSPARENT);
242
243 #ifdef __WXPM__
244 wxColour vColor;
245
246 vColor = wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR);
247 ::WinFillRect(dc.m_hPS, &dc.m_vRclPaint, vColor.GetPixel());
248 #endif
249
250 for (int i = 0; i < m_nFields; i ++)
251 DrawField(dc, i);
252 }
253
254 void wxStatusBarGeneric::DrawFieldText(wxDC& dc, int i)
255 {
256 int leftMargin = 2;
257
258 wxRect rect;
259 GetFieldRect(i, rect);
260
261 wxString text(GetStatusText(i));
262
263 wxCoord x = 0, y = 0;
264
265 dc.GetTextExtent(text, &x, &y);
266
267 int xpos = rect.x + leftMargin;
268 int ypos = (int) (((rect.height - y) / 2 ) + rect.y + 0.5) ;
269
270 #if defined( __WXGTK__ ) || defined(__WXMAC__)
271 xpos++;
272 ypos++;
273 #endif
274
275 dc.SetClippingRegion(rect.x, rect.y, rect.width, rect.height);
276
277 dc.DrawText(text, xpos, ypos);
278
279 dc.DestroyClippingRegion();
280 }
281
282 void wxStatusBarGeneric::DrawField(wxDC& dc, int i)
283 {
284 wxRect rect;
285 GetFieldRect(i, rect);
286
287 int style = wxSB_NORMAL;
288 if (m_statusStyles)
289 style = m_statusStyles[i];
290
291 if (style != wxSB_FLAT)
292 {
293 // Draw border
294 // For wxSB_NORMAL:
295 // Have grey background, plus 3-d border -
296 // One black rectangle.
297 // Inside this, left and top sides - dark grey. Bottom and right -
298 // white.
299 // Reverse it for wxSB_RAISED
300
301 dc.SetPen((style == wxSB_RAISED) ? m_mediumShadowPen : m_hilightPen);
302
303 #ifndef __WXPM__
304
305 // Right and bottom lines
306 dc.DrawLine(rect.x + rect.width, rect.y,
307 rect.x + rect.width, rect.y + rect.height);
308 dc.DrawLine(rect.x + rect.width, rect.y + rect.height,
309 rect.x, rect.y + rect.height);
310
311 dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen);
312
313 // Left and top lines
314 dc.DrawLine(rect.x, rect.y + rect.height,
315 rect.x, rect.y);
316 dc.DrawLine(rect.x, rect.y,
317 rect.x + rect.width, rect.y);
318 #else
319
320 dc.DrawLine(rect.x + rect.width, rect.height + 2,
321 rect.x, rect.height + 2);
322 dc.DrawLine(rect.x + rect.width, rect.y,
323 rect.x + rect.width, rect.y + rect.height);
324
325 dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen);
326 dc.DrawLine(rect.x, rect.y,
327 rect.x + rect.width, rect.y);
328 dc.DrawLine(rect.x, rect.y + rect.height,
329 rect.x, rect.y);
330
331 #endif
332 }
333
334 DrawFieldText(dc, i);
335 }
336
337 // Get the position and size of the field's internal bounding rectangle
338 bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const
339 {
340 wxCHECK_MSG( (n >= 0) && (n < m_nFields), false,
341 _T("invalid status bar field index") );
342
343 // FIXME: workarounds for OS/2 bugs have nothing to do here (VZ)
344 int width, height;
345 #ifdef __WXPM__
346 GetSize(&width, &height);
347 #else
348 GetClientSize(&width, &height);
349 #endif
350
351 // we cache m_widthsAbs between calls and recompute it if client
352 // width has changed (or when it is initially empty)
353 if ( m_widthsAbs.IsEmpty() || (m_lastClientWidth != width) )
354 {
355 wxConstCast(this, wxStatusBarGeneric)->
356 m_widthsAbs = CalculateAbsWidths(width);
357 // remember last width for which we have recomputed the widths in pixels
358 wxConstCast(this, wxStatusBarGeneric)->
359 m_lastClientWidth = width;
360 }
361
362 rect.x = 0;
363 for ( int i = 0; i < n; i++ )
364 {
365 rect.x += m_widthsAbs[i];
366 }
367
368 rect.x += m_borderX;
369 rect.y = m_borderY;
370
371 rect.width = m_widthsAbs[n] - 2*m_borderX;
372 rect.height = height - 2*m_borderY;
373
374 return true;
375 }
376
377 // Initialize colours
378 void wxStatusBarGeneric::InitColours()
379 {
380 // Shadow colours
381 #if defined(__WXMSW__) || defined(__WXMAC__)
382 wxColour mediumShadowColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW));
383 m_mediumShadowPen = wxPen(mediumShadowColour, 1, wxSOLID);
384
385 wxColour hilightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT));
386 m_hilightPen = wxPen(hilightColour, 1, wxSOLID);
387 #elif defined(__WXPM__)
388 m_mediumShadowPen = wxPen(wxColour(127, 127, 127), 1, wxSOLID);
389 m_hilightPen = *wxWHITE_PEN;
390
391 SetBackgroundColour(*wxLIGHT_GREY);
392 SetForegroundColour(*wxBLACK);
393 #else
394 m_mediumShadowPen = *wxGREY_PEN;
395 m_hilightPen = *wxWHITE_PEN;
396 #endif
397 }
398
399 // Responds to colour changes, and passes event on to children.
400 void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event)
401 {
402 InitColours();
403
404 // Propagate the event to the non-top-level children
405 wxWindow::OnSysColourChanged(event);
406 }
407
408 void wxStatusBarGeneric::SetMinHeight(int height)
409 {
410 // check that this min height is not less than minimal height for the
411 // current font
412 wxClientDC dc(this);
413 wxCoord y;
414 dc.GetTextExtent( wxT("X"), NULL, &y );
415
416 if ( height > (11*y)/10 )
417 {
418 SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height + 2*m_borderY);
419 }
420 }
421
422 void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event)
423 {
424 #ifdef __WXGTK20__
425 int width, height;
426 GetClientSize(&width, &height);
427
428 if ( ShowsSizeGrip() && (event.GetX() > width-height) )
429 {
430 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget );
431
432 if (!GTK_IS_WINDOW (ancestor))
433 return;
434
435 GdkWindow *source = GTKGetDrawingWindow();
436
437 int org_x = 0;
438 int org_y = 0;
439 gdk_window_get_origin( source, &org_x, &org_y );
440
441 if (GetLayoutDirection() == wxLayout_RightToLeft)
442 {
443 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
444 GDK_WINDOW_EDGE_SOUTH_WEST,
445 1,
446 org_x - event.GetX() + GetSize().x ,
447 org_y + event.GetY(),
448 0);
449 }
450 else
451 {
452 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
453 GDK_WINDOW_EDGE_SOUTH_EAST,
454 1,
455 org_x + event.GetX(),
456 org_y + event.GetY(),
457 0);
458 }
459 }
460 else
461 {
462 event.Skip( true );
463 }
464 #else
465 event.Skip( true );
466 #endif
467 }
468
469 void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event)
470 {
471 #ifdef __WXGTK20__
472 int width, height;
473 GetClientSize(&width, &height);
474
475 if ( ShowsSizeGrip() && (event.GetX() > width-height) )
476 {
477 GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget );
478
479 if (!GTK_IS_WINDOW (ancestor))
480 return;
481
482 GdkWindow *source = GTKGetDrawingWindow();
483
484 int org_x = 0;
485 int org_y = 0;
486 gdk_window_get_origin( source, &org_x, &org_y );
487
488 gtk_window_begin_move_drag (GTK_WINDOW (ancestor),
489 2,
490 org_x + event.GetX(),
491 org_y + event.GetY(),
492 0);
493 }
494 else
495 {
496 event.Skip( true );
497 }
498 #else
499 event.Skip( true );
500 #endif
501 }
502
503 #endif // wxUSE_STATUSBAR