1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/statusbr.cpp
3 // Purpose: wxStatusBarGeneric class implementation
4 // Author: Julian Smart
5 // Modified by: Francesco Montorsi
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
20 #include "wx/statusbr.h"
23 #include "wx/settings.h"
24 #include "wx/dcclient.h"
25 #include "wx/toplevel.h"
26 #include "wx/control.h"
31 #include "wx/gtk/private.h"
32 #include "wx/gtk/private/gtk2-compat.h"
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
39 #if defined(__WXMAC__) || \
40 (defined(wxUSE_NATIVE_STATUSBAR) && wxUSE_NATIVE_STATUSBAR)
41 #include "wx/generic/statusbr.h"
43 IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric
, wxWindow
)
44 #endif // wxUSE_NATIVE_STATUSBAR
46 // Default status border dimensions
47 #define wxTHICK_LINE_BORDER 2
49 // Margin between the field text and the field rect
50 #define wxFIELD_TEXT_MARGIN 2
52 // ----------------------------------------------------------------------------
53 // GTK+ signal handler
54 // ----------------------------------------------------------------------------
56 #if defined( __WXGTK20__ )
57 #if GTK_CHECK_VERSION(2,12,0)
60 gboolean
statusbar_query_tooltip(GtkWidget
* WXUNUSED(widget
),
63 gboolean
WXUNUSED(keyboard_mode
),
67 int n
= statbar
->GetFieldFromPoint(wxPoint(x
,y
));
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
75 const wxString
& str
= statbar
->GetStatusText(n
);
79 gtk_tooltip_set_text(tooltip
, wxGTK_CONV_SYS(str
));
86 // ----------------------------------------------------------------------------
88 // ----------------------------------------------------------------------------
90 BEGIN_EVENT_TABLE(wxStatusBarGeneric
, wxWindow
)
91 EVT_PAINT(wxStatusBarGeneric::OnPaint
)
92 EVT_SIZE(wxStatusBarGeneric::OnSize
)
94 EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown
)
95 EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown
)
97 EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged
)
100 void wxStatusBarGeneric::Init()
102 m_borderX
= wxTHICK_LINE_BORDER
;
103 m_borderY
= wxTHICK_LINE_BORDER
;
106 wxStatusBarGeneric::~wxStatusBarGeneric()
110 bool wxStatusBarGeneric::Create(wxWindow
*parent
,
113 const wxString
& name
)
115 style
|= wxTAB_TRAVERSAL
| wxFULL_REPAINT_ON_RESIZE
;
116 if ( !wxWindow::Create(parent
, id
,
117 wxDefaultPosition
, wxDefaultSize
,
121 // The status bar should have a themed background
122 SetThemeEnabled( true );
127 SetFont(*wxSMALL_FONT
);
130 int height
= (int)((11*GetCharHeight())/10 + 2*GetBorderY());
131 SetSize(wxDefaultCoord
, wxDefaultCoord
, wxDefaultCoord
, height
);
135 #if defined( __WXGTK20__ )
136 #if GTK_CHECK_VERSION(2,12,0)
137 if (HasFlag(wxSTB_SHOW_TIPS
)
139 && gtk_check_version(2,12,0) == NULL
143 g_object_set(m_widget
, "has-tooltip", TRUE
, NULL
);
144 g_signal_connect(m_widget
, "query-tooltip",
145 G_CALLBACK(statusbar_query_tooltip
), this);
153 wxSize
wxStatusBarGeneric::DoGetBestSize() const
157 // best width is the width of the parent
159 GetParent()->GetClientSize(&width
, NULL
);
161 width
= 80; // a dummy value
163 // best height is as calculated above in Create()
164 height
= (int)((11*GetCharHeight())/10 + 2*GetBorderY());
166 return wxSize(width
, height
);
169 void wxStatusBarGeneric::DoUpdateStatusText(int number
)
172 GetFieldRect(number
, rect
);
174 Refresh(true, &rect
);
176 // it's common to show some text in the status bar before starting a
177 // relatively lengthy operation, ensure that the text is shown to the
178 // user immediately and not after the lengthy operation end
182 void wxStatusBarGeneric::SetStatusWidths(int n
, const int widths_field
[])
184 // only set status widths when n == number of statuswindows
185 wxCHECK_RET( (size_t)n
== m_panes
.GetCount(), wxT("status bar field count mismatch") );
187 wxStatusBarBase::SetStatusWidths(n
, widths_field
);
190 DoUpdateFieldWidths();
193 void wxStatusBarGeneric::DoUpdateFieldWidths()
195 m_lastClientSize
= GetClientSize();
197 // recompute the cache of the field widths if the status bar width has changed
198 m_widthsAbs
= CalculateAbsWidths(m_lastClientSize
.x
);
201 bool wxStatusBarGeneric::ShowsSizeGrip() const
203 if ( !HasFlag(wxSTB_SIZEGRIP
) )
206 wxTopLevelWindow
* const
207 tlw
= wxDynamicCast(wxGetTopLevelParent(GetParent()), wxTopLevelWindow
);
208 return tlw
&& !tlw
->IsMaximized() && tlw
->HasFlag(wxRESIZE_BORDER
);
211 void wxStatusBarGeneric::DrawFieldText(wxDC
& dc
, const wxRect
& rect
, int i
, int textHeight
)
213 wxString
text(GetStatusText(i
));
215 return; // optimization
217 int xpos
= rect
.x
+ wxFIELD_TEXT_MARGIN
,
218 maxWidth
= rect
.width
- 2*wxFIELD_TEXT_MARGIN
,
219 ypos
= (int) (((rect
.height
- textHeight
) / 2) + rect
.y
+ 0.5);
223 // don't write text over the size grip:
224 // NOTE: overloading DoGetClientSize() and GetClientAreaOrigin() wouldn't
225 // work because the adjustment needs to be done only when drawing
226 // the field text and not also when drawing the background, the
227 // size grip itself, etc
228 if ((GetLayoutDirection() == wxLayout_RightToLeft
&& i
== 0) ||
229 (GetLayoutDirection() != wxLayout_RightToLeft
&&
230 i
== (int)m_panes
.GetCount()-1))
232 const wxRect
& gripRc
= GetSizeGripRect();
234 // NOTE: we don't need any special treatment wrt to the layout direction
235 // since DrawText() will automatically adjust the origin of the
236 // text accordingly to the layout in use
238 maxWidth
-= gripRc
.width
;
242 // eventually ellipsize the text so that it fits the field width
244 wxEllipsizeMode ellmode
= (wxEllipsizeMode
)-1;
245 if (HasFlag(wxSTB_ELLIPSIZE_START
)) ellmode
= wxELLIPSIZE_START
;
246 else if (HasFlag(wxSTB_ELLIPSIZE_MIDDLE
)) ellmode
= wxELLIPSIZE_MIDDLE
;
247 else if (HasFlag(wxSTB_ELLIPSIZE_END
)) ellmode
= wxELLIPSIZE_END
;
249 if (ellmode
== (wxEllipsizeMode
)-1)
251 // if we have the wxSTB_SHOW_TIPS we must set the ellipsized flag even if
252 // we don't ellipsize the text but just truncate it
253 if (HasFlag(wxSTB_SHOW_TIPS
))
254 SetEllipsizedFlag(i
, dc
.GetTextExtent(text
).GetWidth() > maxWidth
);
256 dc
.SetClippingRegion(rect
);
260 text
= wxControl::Ellipsize(text
, dc
,
263 wxELLIPSIZE_FLAGS_EXPAND_TABS
);
264 // Ellipsize() will do something only if necessary
266 // update the ellipsization status for this pane; this is used later to
267 // decide whether a tooltip should be shown or not for this pane
268 // (if we have wxSTB_SHOW_TIPS)
269 SetEllipsizedFlag(i
, text
!= GetStatusText(i
));
272 #if defined( __WXGTK__ ) || defined(__WXMAC__)
278 dc
.DrawText(text
, xpos
, ypos
);
280 if (ellmode
== (wxEllipsizeMode
)-1)
281 dc
.DestroyClippingRegion();
284 void wxStatusBarGeneric::DrawField(wxDC
& dc
, int i
, int textHeight
)
287 GetFieldRect(i
, rect
);
289 if (rect
.GetWidth() <= 0)
290 return; // happens when the status bar is shrunk in a very small area!
292 int style
= m_panes
[i
].GetStyle();
293 if (style
== wxSB_RAISED
|| style
== wxSB_SUNKEN
)
296 // For wxSB_SUNKEN: paint a grey background, plus 3-d border (one black rectangle)
297 // Inside this, left and top sides (dark grey). Bottom and right (white).
298 // Reverse it for wxSB_RAISED
300 dc
.SetPen((style
== wxSB_RAISED
) ? m_mediumShadowPen
: m_hilightPen
);
304 // Right and bottom lines
305 dc
.DrawLine(rect
.x
+ rect
.width
, rect
.y
,
306 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
307 dc
.DrawLine(rect
.x
+ rect
.width
, rect
.y
+ rect
.height
,
308 rect
.x
, rect
.y
+ rect
.height
);
310 dc
.SetPen((style
== wxSB_RAISED
) ? m_hilightPen
: m_mediumShadowPen
);
312 // Left and top lines
313 dc
.DrawLine(rect
.x
, rect
.y
+ rect
.height
,
315 dc
.DrawLine(rect
.x
, rect
.y
,
316 rect
.x
+ rect
.width
, rect
.y
);
319 dc
.DrawLine(rect
.x
+ rect
.width
, rect
.height
+ 2,
320 rect
.x
, rect
.height
+ 2);
321 dc
.DrawLine(rect
.x
+ rect
.width
, rect
.y
,
322 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
324 dc
.SetPen((style
== wxSB_RAISED
) ? m_hilightPen
: m_mediumShadowPen
);
325 dc
.DrawLine(rect
.x
, rect
.y
,
326 rect
.x
+ rect
.width
, rect
.y
);
327 dc
.DrawLine(rect
.x
, rect
.y
+ rect
.height
,
332 DrawFieldText(dc
, rect
, i
, textHeight
);
335 bool wxStatusBarGeneric::GetFieldRect(int n
, wxRect
& rect
) const
337 wxCHECK_MSG( (n
>= 0) && ((size_t)n
< m_panes
.GetCount()), false,
338 wxT("invalid status bar field index") );
340 // We can be called from the user-defined EVT_SIZE handler in which case
341 // the widths haven't been updated yet and we need to do it now. This is
342 // not very efficient as we keep testing the size but there is no other way
343 // to make the code needing the up-to-date fields sizes in its EVT_SIZE to
345 if ( GetClientSize().x
!= m_lastClientSize
.x
)
347 const_cast<wxStatusBarGeneric
*>(this)->DoUpdateFieldWidths();
350 if (m_widthsAbs
.IsEmpty())
354 for ( int i
= 0; i
< n
; i
++ )
355 rect
.x
+= m_widthsAbs
[i
];
359 rect
.width
= m_widthsAbs
[n
] - 2*m_borderX
;
360 rect
.height
= m_lastClientSize
.y
- 2*m_borderY
;
365 int wxStatusBarGeneric::GetFieldFromPoint(const wxPoint
& pt
) const
367 if (m_widthsAbs
.IsEmpty())
370 // NOTE: we explicitly don't take in count the borders since they are only
371 // useful when rendering the status text, not for hit-test computations
373 if (pt
.y
<= 0 || pt
.y
>= m_lastClientSize
.y
)
377 for ( size_t i
= 0; i
< m_panes
.GetCount(); i
++ )
379 if (pt
.x
> x
&& pt
.x
< x
+m_widthsAbs
[i
])
388 void wxStatusBarGeneric::InitColours()
390 #if defined(__WXPM__)
391 m_mediumShadowPen
= wxPen(wxColour(127, 127, 127));
392 m_hilightPen
= *wxWHITE_PEN
;
394 SetBackgroundColour(*wxLIGHT_GREY
);
395 SetForegroundColour(*wxBLACK
);
397 m_mediumShadowPen
= wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
));
398 m_hilightPen
= wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT
));
399 #endif // __WXPM__/!__WXPM__
402 void wxStatusBarGeneric::SetMinHeight(int height
)
404 // check that this min height is not less than minimal height for the
405 // current font (min height is as calculated above in Create() except for border)
406 int minHeight
= (int)((11*GetCharHeight())/10);
408 if ( height
> minHeight
)
409 SetSize(wxDefaultCoord
, wxDefaultCoord
, wxDefaultCoord
, height
+ 2*m_borderY
);
412 wxRect
wxStatusBarGeneric::GetSizeGripRect() const
415 wxWindow::DoGetClientSize(&width
, &height
);
417 if (GetLayoutDirection() == wxLayout_RightToLeft
)
418 return wxRect(2, 2, height
-2, height
-4);
420 return wxRect(width
-height
-2, 2, height
-2, height
-4);
423 // ----------------------------------------------------------------------------
424 // wxStatusBarGeneric - event handlers
425 // ----------------------------------------------------------------------------
427 void wxStatusBarGeneric::OnPaint(wxPaintEvent
& WXUNUSED(event
) )
433 if ( ShowsSizeGrip() )
435 const wxRect
& rc
= GetSizeGripRect();
437 GtkWidget
* toplevel
= gtk_widget_get_toplevel(m_widget
);
439 if (toplevel
&& (!gtk_window_get_resize_grip_area(GTK_WINDOW(toplevel
), &rect
) ||
440 rect
.width
== 0 || rect
.height
== 0))
442 GtkStyleContext
* sc
= gtk_widget_get_style_context(toplevel
);
443 gtk_style_context_save(sc
);
444 gtk_style_context_add_class(sc
, GTK_STYLE_CLASS_GRIP
);
445 GtkJunctionSides sides
= GTK_JUNCTION_CORNER_BOTTOMRIGHT
;
446 if (GetLayoutDirection() == wxLayout_RightToLeft
)
447 sides
= GTK_JUNCTION_CORNER_BOTTOMLEFT
;
448 gtk_style_context_set_junction_sides(sc
, sides
);
449 gtk_render_handle(sc
,
450 static_cast<cairo_t
*>(dc
.GetImpl()->GetCairoContext()),
451 rc
.x
, rc
.y
, rc
.width
, rc
.height
);
452 gtk_style_context_restore(sc
);
456 GetLayoutDirection() == wxLayout_RightToLeft
? GDK_WINDOW_EDGE_SOUTH_WEST
:
457 GDK_WINDOW_EDGE_SOUTH_EAST
;
458 gtk_paint_resize_grip(gtk_widget_get_style(m_widget
),
459 GTKGetDrawingWindow(),
460 gtk_widget_get_state(m_widget
),
465 rc
.x
, rc
.y
, rc
.width
, rc
.height
);
468 #endif // __WXGTK20__
470 if (GetFont().IsOk())
471 dc
.SetFont(GetFont());
473 // compute char height only once for all panes:
474 int textHeight
= dc
.GetCharHeight();
476 dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
);
477 for (size_t i
= 0; i
< m_panes
.GetCount(); i
++)
478 DrawField(dc
, i
, textHeight
);
481 void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent
& event
)
485 // Propagate the event to the non-top-level children
486 wxWindow::OnSysColourChanged(event
);
490 void wxStatusBarGeneric::OnLeftDown(wxMouseEvent
& event
)
493 GetClientSize(&width
, &height
);
495 GtkWidget
* ancestor
= gtk_widget_get_toplevel(m_widget
);
498 if (ancestor
&& gtk_window_get_resize_grip_area(GTK_WINDOW(ancestor
), &rect
) &&
499 rect
.width
&& rect
.height
)
505 if (ancestor
&& ShowsSizeGrip() && event
.GetX() > width
- height
)
507 GdkWindow
*source
= GTKGetDrawingWindow();
511 gdk_window_get_origin( source
, &org_x
, &org_y
);
513 if (GetLayoutDirection() == wxLayout_RightToLeft
)
515 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
516 GDK_WINDOW_EDGE_SOUTH_WEST
,
518 org_x
- event
.GetX() + GetSize().x
,
519 org_y
+ event
.GetY(),
524 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
525 GDK_WINDOW_EDGE_SOUTH_EAST
,
527 org_x
+ event
.GetX(),
528 org_y
+ event
.GetY(),
538 void wxStatusBarGeneric::OnRightDown(wxMouseEvent
& event
)
541 GetClientSize(&width
, &height
);
543 GtkWidget
* ancestor
= gtk_widget_get_toplevel(m_widget
);
546 if (ancestor
&& gtk_window_get_resize_grip_area(GTK_WINDOW(ancestor
), &rect
) &&
547 rect
.width
&& rect
.height
)
553 if (ancestor
&& ShowsSizeGrip() && event
.GetX() > width
- height
)
555 GdkWindow
*source
= GTKGetDrawingWindow();
559 gdk_window_get_origin( source
, &org_x
, &org_y
);
561 gtk_window_begin_move_drag (GTK_WINDOW (ancestor
),
563 org_x
+ event
.GetX(),
564 org_y
+ event
.GetY(),
572 #endif // __WXGTK20__
574 void wxStatusBarGeneric::OnSize(wxSizeEvent
& event
)
576 DoUpdateFieldWidths();
581 #endif // wxUSE_STATUSBAR