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