1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/statusbr.cpp
3 // Purpose: wxStatusBarGeneric class implementation
4 // Author: Julian Smart
5 // Modified by: Francesco Montorsi
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
21 #include "wx/statusbr.h"
24 #include "wx/settings.h"
25 #include "wx/dcclient.h"
26 #include "wx/toplevel.h"
27 #include "wx/control.h"
32 #include "wx/gtk/private.h"
33 #include "wx/gtk/private/gtk2-compat.h"
36 // we only have to do it here when we use wxStatusBarGeneric in addition to the
37 // standard wxStatusBar class, if wxStatusBarGeneric is the same as
38 // wxStatusBar, then the corresponding IMPLEMENT_DYNAMIC_CLASS is already in
40 #if defined(__WXMAC__) || \
41 (defined(wxUSE_NATIVE_STATUSBAR) && wxUSE_NATIVE_STATUSBAR)
42 #include "wx/generic/statusbr.h"
44 IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric
, wxWindow
)
45 #endif // wxUSE_NATIVE_STATUSBAR
47 // Default status border dimensions
48 #define wxTHICK_LINE_BORDER 2
50 // Margin between the field text and the field rect
51 #define wxFIELD_TEXT_MARGIN 2
53 // ----------------------------------------------------------------------------
54 // GTK+ signal handler
55 // ----------------------------------------------------------------------------
57 #if defined( __WXGTK20__ )
58 #if GTK_CHECK_VERSION(2,12,0)
61 gboolean
statusbar_query_tooltip(GtkWidget
* WXUNUSED(widget
),
64 gboolean
WXUNUSED(keyboard_mode
),
68 int n
= statbar
->GetFieldFromPoint(wxPoint(x
,y
));
72 // should we show the tooltip for the n-th pane of the statusbar?
73 if (!statbar
->GetField(n
).IsEllipsized())
74 return FALSE
; // no, it's not useful
76 const wxString
& str
= statbar
->GetStatusText(n
);
80 gtk_tooltip_set_text(tooltip
, wxGTK_CONV_SYS(str
));
87 // ----------------------------------------------------------------------------
89 // ----------------------------------------------------------------------------
91 BEGIN_EVENT_TABLE(wxStatusBarGeneric
, wxWindow
)
92 EVT_PAINT(wxStatusBarGeneric::OnPaint
)
93 EVT_SIZE(wxStatusBarGeneric::OnSize
)
95 EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown
)
96 EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown
)
98 EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged
)
101 void wxStatusBarGeneric::Init()
103 m_borderX
= wxTHICK_LINE_BORDER
;
104 m_borderY
= wxTHICK_LINE_BORDER
;
107 wxStatusBarGeneric::~wxStatusBarGeneric()
111 bool wxStatusBarGeneric::Create(wxWindow
*parent
,
114 const wxString
& name
)
116 style
|= wxTAB_TRAVERSAL
| wxFULL_REPAINT_ON_RESIZE
;
117 if ( !wxWindow::Create(parent
, id
,
118 wxDefaultPosition
, wxDefaultSize
,
122 // The status bar should have a themed background
123 SetThemeEnabled( true );
128 SetFont(*wxSMALL_FONT
);
131 int height
= (int)((11*GetCharHeight())/10 + 2*GetBorderY());
132 SetSize(wxDefaultCoord
, wxDefaultCoord
, wxDefaultCoord
, height
);
136 #if defined( __WXGTK20__ )
137 #if GTK_CHECK_VERSION(2,12,0)
138 if (HasFlag(wxSTB_SHOW_TIPS
)
140 && gtk_check_version(2,12,0) == NULL
144 g_object_set(m_widget
, "has-tooltip", TRUE
, NULL
);
145 g_signal_connect(m_widget
, "query-tooltip",
146 G_CALLBACK(statusbar_query_tooltip
), this);
154 wxSize
wxStatusBarGeneric::DoGetBestSize() const
158 // best width is the width of the parent
160 GetParent()->GetClientSize(&width
, NULL
);
162 width
= 80; // a dummy value
164 // best height is as calculated above in Create()
165 height
= (int)((11*GetCharHeight())/10 + 2*GetBorderY());
167 return wxSize(width
, height
);
170 void wxStatusBarGeneric::DoUpdateStatusText(int number
)
173 GetFieldRect(number
, rect
);
175 Refresh(true, &rect
);
177 // it's common to show some text in the status bar before starting a
178 // relatively lengthy operation, ensure that the text is shown to the
179 // user immediately and not after the lengthy operation end
183 void wxStatusBarGeneric::SetStatusWidths(int n
, const int widths_field
[])
185 // only set status widths when n == number of statuswindows
186 wxCHECK_RET( (size_t)n
== m_panes
.GetCount(), wxT("status bar field count mismatch") );
188 wxStatusBarBase::SetStatusWidths(n
, widths_field
);
191 DoUpdateFieldWidths();
194 void wxStatusBarGeneric::DoUpdateFieldWidths()
196 m_lastClientSize
= GetClientSize();
198 // recompute the cache of the field widths if the status bar width has changed
199 m_widthsAbs
= CalculateAbsWidths(m_lastClientSize
.x
);
202 bool wxStatusBarGeneric::ShowsSizeGrip() const
204 if ( !HasFlag(wxSTB_SIZEGRIP
) )
207 wxTopLevelWindow
* const
208 tlw
= wxDynamicCast(wxGetTopLevelParent(GetParent()), wxTopLevelWindow
);
209 return tlw
&& !tlw
->IsMaximized() && tlw
->HasFlag(wxRESIZE_BORDER
);
212 void wxStatusBarGeneric::DrawFieldText(wxDC
& dc
, const wxRect
& rect
, int i
, int textHeight
)
214 wxString
text(GetStatusText(i
));
216 return; // optimization
218 int xpos
= rect
.x
+ wxFIELD_TEXT_MARGIN
,
219 maxWidth
= rect
.width
- 2*wxFIELD_TEXT_MARGIN
,
220 ypos
= (int) (((rect
.height
- textHeight
) / 2) + rect
.y
+ 0.5);
224 // don't write text over the size grip:
225 // NOTE: overloading DoGetClientSize() and GetClientAreaOrigin() wouldn't
226 // work because the adjustment needs to be done only when drawing
227 // the field text and not also when drawing the background, the
228 // size grip itself, etc
229 if ((GetLayoutDirection() == wxLayout_RightToLeft
&& i
== 0) ||
230 (GetLayoutDirection() != wxLayout_RightToLeft
&&
231 i
== (int)m_panes
.GetCount()-1))
233 const wxRect
& gripRc
= GetSizeGripRect();
235 // NOTE: we don't need any special treatment wrt to the layout direction
236 // since DrawText() will automatically adjust the origin of the
237 // text accordingly to the layout in use
239 maxWidth
-= gripRc
.width
;
243 // eventually ellipsize the text so that it fits the field width
245 wxEllipsizeMode ellmode
= (wxEllipsizeMode
)-1;
246 if (HasFlag(wxSTB_ELLIPSIZE_START
)) ellmode
= wxELLIPSIZE_START
;
247 else if (HasFlag(wxSTB_ELLIPSIZE_MIDDLE
)) ellmode
= wxELLIPSIZE_MIDDLE
;
248 else if (HasFlag(wxSTB_ELLIPSIZE_END
)) ellmode
= wxELLIPSIZE_END
;
250 if (ellmode
== (wxEllipsizeMode
)-1)
252 // if we have the wxSTB_SHOW_TIPS we must set the ellipsized flag even if
253 // we don't ellipsize the text but just truncate it
254 if (HasFlag(wxSTB_SHOW_TIPS
))
255 SetEllipsizedFlag(i
, dc
.GetTextExtent(text
).GetWidth() > maxWidth
);
257 dc
.SetClippingRegion(rect
);
261 text
= wxControl::Ellipsize(text
, dc
,
264 wxELLIPSIZE_FLAGS_EXPAND_TABS
);
265 // Ellipsize() will do something only if necessary
267 // update the ellipsization status for this pane; this is used later to
268 // decide whether a tooltip should be shown or not for this pane
269 // (if we have wxSTB_SHOW_TIPS)
270 SetEllipsizedFlag(i
, text
!= GetStatusText(i
));
273 #if defined( __WXGTK__ ) || defined(__WXMAC__)
279 dc
.DrawText(text
, xpos
, ypos
);
281 if (ellmode
== (wxEllipsizeMode
)-1)
282 dc
.DestroyClippingRegion();
285 void wxStatusBarGeneric::DrawField(wxDC
& dc
, int i
, int textHeight
)
288 GetFieldRect(i
, rect
);
290 if (rect
.GetWidth() <= 0)
291 return; // happens when the status bar is shrunk in a very small area!
293 int style
= m_panes
[i
].GetStyle();
294 if (style
!= wxSB_FLAT
)
297 // For wxSB_NORMAL: paint a grey background, plus 3-d border (one black rectangle)
298 // Inside this, left and top sides (dark grey). Bottom and right (white).
299 // Reverse it for wxSB_RAISED
301 dc
.SetPen((style
== wxSB_RAISED
) ? m_mediumShadowPen
: m_hilightPen
);
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
);
311 dc
.SetPen((style
== wxSB_RAISED
) ? m_hilightPen
: m_mediumShadowPen
);
313 // Left and top lines
314 dc
.DrawLine(rect
.x
, rect
.y
+ rect
.height
,
316 dc
.DrawLine(rect
.x
, rect
.y
,
317 rect
.x
+ rect
.width
, rect
.y
);
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
);
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
,
333 DrawFieldText(dc
, rect
, i
, textHeight
);
336 bool wxStatusBarGeneric::GetFieldRect(int n
, wxRect
& rect
) const
338 wxCHECK_MSG( (n
>= 0) && ((size_t)n
< m_panes
.GetCount()), false,
339 wxT("invalid status bar field index") );
341 // We can be called from the user-defined EVT_SIZE handler in which case
342 // the widths haven't been updated yet and we need to do it now. This is
343 // not very efficient as we keep testing the size but there is no other way
344 // to make the code needing the up-to-date fields sizes in its EVT_SIZE to
346 if ( GetClientSize().x
!= m_lastClientSize
.x
)
348 const_cast<wxStatusBarGeneric
*>(this)->DoUpdateFieldWidths();
351 if (m_widthsAbs
.IsEmpty())
355 for ( int i
= 0; i
< n
; i
++ )
356 rect
.x
+= m_widthsAbs
[i
];
360 rect
.width
= m_widthsAbs
[n
] - 2*m_borderX
;
361 rect
.height
= m_lastClientSize
.y
- 2*m_borderY
;
366 int wxStatusBarGeneric::GetFieldFromPoint(const wxPoint
& pt
) const
368 if (m_widthsAbs
.IsEmpty())
371 // NOTE: we explicitly don't take in count the borders since they are only
372 // useful when rendering the status text, not for hit-test computations
374 if (pt
.y
<= 0 || pt
.y
>= m_lastClientSize
.y
)
378 for ( size_t i
= 0; i
< m_panes
.GetCount(); i
++ )
380 if (pt
.x
> x
&& pt
.x
< x
+m_widthsAbs
[i
])
389 void wxStatusBarGeneric::InitColours()
391 #if defined(__WXPM__)
392 m_mediumShadowPen
= wxPen(wxColour(127, 127, 127));
393 m_hilightPen
= *wxWHITE_PEN
;
395 SetBackgroundColour(*wxLIGHT_GREY
);
396 SetForegroundColour(*wxBLACK
);
398 m_mediumShadowPen
= wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
));
399 m_hilightPen
= wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT
));
400 #endif // __WXPM__/!__WXPM__
403 void wxStatusBarGeneric::SetMinHeight(int height
)
405 // check that this min height is not less than minimal height for the
406 // current font (min height is as calculated above in Create() except for border)
407 int minHeight
= (int)((11*GetCharHeight())/10);
409 if ( height
> minHeight
)
410 SetSize(wxDefaultCoord
, wxDefaultCoord
, wxDefaultCoord
, height
+ 2*m_borderY
);
413 wxRect
wxStatusBarGeneric::GetSizeGripRect() const
416 wxWindow::DoGetClientSize(&width
, &height
);
418 if (GetLayoutDirection() == wxLayout_RightToLeft
)
419 return wxRect(2, 2, height
-2, height
-4);
421 return wxRect(width
-height
-2, 2, height
-2, height
-4);
424 // ----------------------------------------------------------------------------
425 // wxStatusBarGeneric - event handlers
426 // ----------------------------------------------------------------------------
428 void wxStatusBarGeneric::OnPaint(wxPaintEvent
& WXUNUSED(event
) )
434 if ( ShowsSizeGrip() )
436 const wxRect
& rc
= GetSizeGripRect();
438 GtkWidget
* toplevel
= gtk_widget_get_toplevel(m_widget
);
439 if (toplevel
&& !gtk_window_get_has_resize_grip(GTK_WINDOW(toplevel
)))
441 GtkStyleContext
* sc
= gtk_widget_get_style_context(toplevel
);
442 gtk_style_context_save(sc
);
443 gtk_style_context_add_class(sc
, GTK_STYLE_CLASS_GRIP
);
444 GtkJunctionSides sides
= GTK_JUNCTION_CORNER_BOTTOMRIGHT
;
445 if (GetLayoutDirection() == wxLayout_RightToLeft
)
446 sides
= GTK_JUNCTION_CORNER_BOTTOMLEFT
;
447 gtk_style_context_set_junction_sides(sc
, sides
);
448 gtk_render_handle(sc
,
449 static_cast<cairo_t
*>(dc
.GetImpl()->GetCairoContext()),
450 rc
.x
, rc
.y
, rc
.width
, rc
.height
);
451 gtk_style_context_restore(sc
);
455 GetLayoutDirection() == wxLayout_RightToLeft
? GDK_WINDOW_EDGE_SOUTH_WEST
:
456 GDK_WINDOW_EDGE_SOUTH_EAST
;
457 gtk_paint_resize_grip(gtk_widget_get_style(m_widget
),
458 GTKGetDrawingWindow(),
459 gtk_widget_get_state(m_widget
),
464 rc
.x
, rc
.y
, rc
.width
, rc
.height
);
467 #endif // __WXGTK20__
469 if (GetFont().IsOk())
470 dc
.SetFont(GetFont());
472 // compute char height only once for all panes:
473 int textHeight
= dc
.GetCharHeight();
475 dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
);
476 for (size_t i
= 0; i
< m_panes
.GetCount(); i
++)
477 DrawField(dc
, i
, textHeight
);
480 void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent
& event
)
484 // Propagate the event to the non-top-level children
485 wxWindow::OnSysColourChanged(event
);
489 void wxStatusBarGeneric::OnLeftDown(wxMouseEvent
& event
)
492 GetClientSize(&width
, &height
);
494 GtkWidget
* ancestor
= gtk_widget_get_toplevel(m_widget
);
496 if (ancestor
&& gtk_window_get_has_resize_grip(GTK_WINDOW(ancestor
)))
500 if (ancestor
&& ShowsSizeGrip() && event
.GetX() > width
- height
)
502 GdkWindow
*source
= GTKGetDrawingWindow();
506 gdk_window_get_origin( source
, &org_x
, &org_y
);
508 if (GetLayoutDirection() == wxLayout_RightToLeft
)
510 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
511 GDK_WINDOW_EDGE_SOUTH_WEST
,
513 org_x
- event
.GetX() + GetSize().x
,
514 org_y
+ event
.GetY(),
519 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
520 GDK_WINDOW_EDGE_SOUTH_EAST
,
522 org_x
+ event
.GetX(),
523 org_y
+ event
.GetY(),
533 void wxStatusBarGeneric::OnRightDown(wxMouseEvent
& event
)
536 GetClientSize(&width
, &height
);
538 GtkWidget
* ancestor
= gtk_widget_get_toplevel(m_widget
);
540 if (ancestor
&& gtk_window_get_has_resize_grip(GTK_WINDOW(ancestor
)))
544 if (ancestor
&& ShowsSizeGrip() && event
.GetX() > width
- height
)
546 GdkWindow
*source
= GTKGetDrawingWindow();
550 gdk_window_get_origin( source
, &org_x
, &org_y
);
552 gtk_window_begin_move_drag (GTK_WINDOW (ancestor
),
554 org_x
+ event
.GetX(),
555 org_y
+ event
.GetY(),
563 #endif // __WXGTK20__
565 void wxStatusBarGeneric::OnSize(wxSizeEvent
& event
)
567 DoUpdateFieldWidths();
572 #endif // wxUSE_STATUSBAR