X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c34d2f356ba024fdcf0d29f231e35c894186e8b0..7d6a4d96961eac84d05db8bb24c64d39003f6e54:/src/generic/statusbr.cpp diff --git a/src/generic/statusbr.cpp b/src/generic/statusbr.cpp index e78c18d216..b2a98212b2 100644 --- a/src/generic/statusbr.cpp +++ b/src/generic/statusbr.cpp @@ -2,7 +2,7 @@ // Name: src/generic/statusbr.cpp // Purpose: wxStatusBarGeneric class implementation // Author: Julian Smart -// Modified by: +// Modified by: Francesco Montorsi // Created: 01/02/97 // RCS-ID: $Id$ // Copyright: (c) Julian Smart @@ -29,6 +29,8 @@ #ifdef __WXGTK20__ #include + #include "wx/gtk/private.h" + #include "wx/gtk/private/gtk2-compat.h" #endif // we only have to do it here when we use wxStatusBarGeneric in addition to the @@ -48,6 +50,39 @@ // Margin between the field text and the field rect #define wxFIELD_TEXT_MARGIN 2 +// ---------------------------------------------------------------------------- +// GTK+ signal handler +// ---------------------------------------------------------------------------- + +#if defined( __WXGTK20__ ) +#if GTK_CHECK_VERSION(2,12,0) +extern "C" { +static +gboolean statusbar_query_tooltip(GtkWidget* WXUNUSED(widget), + gint x, + gint y, + gboolean WXUNUSED(keyboard_mode), + GtkTooltip *tooltip, + wxStatusBar* statbar) +{ + int n = statbar->GetFieldFromPoint(wxPoint(x,y)); + if (n == wxNOT_FOUND) + return FALSE; + + // should we show the tooltip for the n-th pane of the statusbar? + if (!statbar->GetField(n).IsEllipsized()) + return FALSE; // no, it's not useful + + const wxString& str = statbar->GetStatusText(n); + if (str.empty()) + return FALSE; + + gtk_tooltip_set_text(tooltip, wxGTK_CONV_SYS(str)); + return TRUE; +} +} +#endif +#endif // ---------------------------------------------------------------------------- // wxStatusBarGeneric @@ -56,8 +91,10 @@ BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow) EVT_PAINT(wxStatusBarGeneric::OnPaint) EVT_SIZE(wxStatusBarGeneric::OnSize) +#ifdef __WXGTK20__ EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown) EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown) +#endif EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged) END_EVENT_TABLE() @@ -96,6 +133,21 @@ bool wxStatusBarGeneric::Create(wxWindow *parent, SetFieldsCount(1); +#if defined( __WXGTK20__ ) +#if GTK_CHECK_VERSION(2,12,0) + if (HasFlag(wxSTB_SHOW_TIPS) +#ifndef __WXGTK3__ + && gtk_check_version(2,12,0) == NULL +#endif + ) + { + g_object_set(m_widget, "has-tooltip", TRUE, NULL); + g_signal_connect(m_widget, "query-tooltip", + G_CALLBACK(statusbar_query_tooltip), this); + } +#endif +#endif + return true; } @@ -115,71 +167,41 @@ wxSize wxStatusBarGeneric::DoGetBestSize() const return wxSize(width, height); } -void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths) +void wxStatusBarGeneric::DoUpdateStatusText(int number) { - wxASSERT_MSG( number >= 0, _T("negative number of fields in wxStatusBar?") ); - - // enlarge the m_statusStrings array if needed: - for (size_t i = m_panes.GetCount(); i < (size_t)number; ++i) - m_statusStrings.Add( wxEmptyString ); - - // shrink the m_statusStrings array if needed: - for (int j = (int)m_panes.GetCount() - 1; j >= number; --j) - m_statusStrings.RemoveAt(j); - - // forget the old cached pixel widths - m_widthsAbs.Empty(); + wxRect rect; + GetFieldRect(number, rect); - wxStatusBarBase::SetFieldsCount(number, widths); + Refresh(true, &rect); - wxASSERT_MSG( m_panes.GetCount() == m_statusStrings.GetCount(), - _T("This really should never happen, can we do away with m_panes.GetCount() here?") ); + // it's common to show some text in the status bar before starting a + // relatively lengthy operation, ensure that the text is shown to the + // user immediately and not after the lengthy operation end + Update(); } -void wxStatusBarGeneric::SetStatusText(const wxString& text, int number) +void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[]) { - wxCHECK_RET( (number >= 0) && ((size_t)number < m_panes.GetCount()), - _T("invalid status bar field index") ); - - wxString oldText = m_statusStrings[number]; - if (oldText != text) - { - m_statusStrings[number] = text; - - wxRect rect; - GetFieldRect(number, rect); - - Refresh(true, &rect); - - // it's common to show some text in the status bar before starting a - // relatively lengthy operation, ensure that the text is shown to the - // user immediately and not after the lengthy operation end - Update(); - } -} + // only set status widths when n == number of statuswindows + wxCHECK_RET( (size_t)n == m_panes.GetCount(), wxT("status bar field count mismatch") ); -wxString wxStatusBarGeneric::GetStatusText(int n) const -{ - wxCHECK_MSG( (n >= 0) && ((size_t)n < m_panes.GetCount()), wxEmptyString, - _T("invalid status bar field index") ); + wxStatusBarBase::SetStatusWidths(n, widths_field); - return m_statusStrings[n]; + // update cache + DoUpdateFieldWidths(); } -void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[]) +void wxStatusBarGeneric::DoUpdateFieldWidths() { - // only set status widths when n == number of statuswindows - wxCHECK_RET( (size_t)n == m_panes.GetCount(), _T("status bar field count mismatch") ); + m_lastClientSize = GetClientSize(); - // forget the old cached pixel widths - m_widthsAbs.Empty(); - - wxStatusBarBase::SetStatusWidths(n, widths_field); + // recompute the cache of the field widths if the status bar width has changed + m_widthsAbs = CalculateAbsWidths(m_lastClientSize.x); } bool wxStatusBarGeneric::ShowsSizeGrip() const { - if ( !HasFlag(wxST_SIZEGRIP) ) + if ( !HasFlag(wxSTB_SIZEGRIP) ) return false; wxTopLevelWindow * const @@ -219,12 +241,34 @@ void wxStatusBarGeneric::DrawFieldText(wxDC& dc, const wxRect& rect, int i, int } // eventually ellipsize the text so that it fits the field width - text = wxControl::Ellipsize( - text, dc, - GetLayoutDirection() == wxLayout_RightToLeft ? wxELLIPSIZE_START : wxELLIPSIZE_END, - maxWidth, - wxELLIPSIZE_EXPAND_TAB); - // Ellipsize() will do something only if necessary + + wxEllipsizeMode ellmode = (wxEllipsizeMode)-1; + if (HasFlag(wxSTB_ELLIPSIZE_START)) ellmode = wxELLIPSIZE_START; + else if (HasFlag(wxSTB_ELLIPSIZE_MIDDLE)) ellmode = wxELLIPSIZE_MIDDLE; + else if (HasFlag(wxSTB_ELLIPSIZE_END)) ellmode = wxELLIPSIZE_END; + + if (ellmode == (wxEllipsizeMode)-1) + { + // if we have the wxSTB_SHOW_TIPS we must set the ellipsized flag even if + // we don't ellipsize the text but just truncate it + if (HasFlag(wxSTB_SHOW_TIPS)) + SetEllipsizedFlag(i, dc.GetTextExtent(text).GetWidth() > maxWidth); + + dc.SetClippingRegion(rect); + } + else + { + text = wxControl::Ellipsize(text, dc, + ellmode, + maxWidth, + wxELLIPSIZE_FLAGS_EXPAND_TABS); + // Ellipsize() will do something only if necessary + + // update the ellipsization status for this pane; this is used later to + // decide whether a tooltip should be shown or not for this pane + // (if we have wxSTB_SHOW_TIPS) + SetEllipsizedFlag(i, text != GetStatusText(i)); + } #if defined( __WXGTK__ ) || defined(__WXMAC__) xpos++; @@ -233,6 +277,9 @@ void wxStatusBarGeneric::DrawFieldText(wxDC& dc, const wxRect& rect, int i, int // draw the text dc.DrawText(text, xpos, ypos); + + if (ellmode == (wxEllipsizeMode)-1) + dc.DestroyClippingRegion(); } void wxStatusBarGeneric::DrawField(wxDC& dc, int i, int textHeight) @@ -241,17 +288,14 @@ void wxStatusBarGeneric::DrawField(wxDC& dc, int i, int textHeight) GetFieldRect(i, rect); if (rect.GetWidth() <= 0) - return; // happens when the status bar is shrinked in a very small area! + return; // happens when the status bar is shrunk in a very small area! - int style = m_panes[i].nStyle; + int style = m_panes[i].GetStyle(); if (style != wxSB_FLAT) { // Draw border - // For wxSB_NORMAL: - // Have grey background, plus 3-d border - - // One black rectangle. - // Inside this, left and top sides - dark grey. Bottom and right - - // white. + // For wxSB_NORMAL: paint a grey background, plus 3-d border (one black rectangle) + // Inside this, left and top sides (dark grey). Bottom and right (white). // Reverse it for wxSB_RAISED dc.SetPen((style == wxSB_RAISED) ? m_mediumShadowPen : m_hilightPen); @@ -282,18 +326,27 @@ void wxStatusBarGeneric::DrawField(wxDC& dc, int i, int textHeight) dc.DrawLine(rect.x, rect.y, rect.x + rect.width, rect.y); dc.DrawLine(rect.x, rect.y + rect.height, - rect.x, rect.y); + rect.x, rect.y); #endif } DrawFieldText(dc, rect, i, textHeight); } -// Get the position and size of the field's internal bounding rectangle bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const { wxCHECK_MSG( (n >= 0) && ((size_t)n < m_panes.GetCount()), false, - _T("invalid status bar field index") ); + wxT("invalid status bar field index") ); + + // We can be called from the user-defined EVT_SIZE handler in which case + // the widths haven't been updated yet and we need to do it now. This is + // not very efficient as we keep testing the size but there is no other way + // to make the code needing the up-to-date fields sizes in its EVT_SIZE to + // work. + if ( GetClientSize().x != m_lastClientSize.x ) + { + const_cast(this)->DoUpdateFieldWidths(); + } if (m_widthsAbs.IsEmpty()) return false; @@ -305,12 +358,34 @@ bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const rect.y = m_borderY; rect.width = m_widthsAbs[n] - 2*m_borderX; - rect.height = m_lastClientHeight - 2*m_borderY; + rect.height = m_lastClientSize.y - 2*m_borderY; return true; } -// Initialize colours +int wxStatusBarGeneric::GetFieldFromPoint(const wxPoint& pt) const +{ + if (m_widthsAbs.IsEmpty()) + return wxNOT_FOUND; + + // NOTE: we explicitly don't take in count the borders since they are only + // useful when rendering the status text, not for hit-test computations + + if (pt.y <= 0 || pt.y >= m_lastClientSize.y) + return wxNOT_FOUND; + + int x = 0; + for ( size_t i = 0; i < m_panes.GetCount(); i++ ) + { + if (pt.x > x && pt.x < x+m_widthsAbs[i]) + return i; + + x += m_widthsAbs[i]; + } + + return wxNOT_FOUND; +} + void wxStatusBarGeneric::InitColours() { #if defined(__WXPM__) @@ -359,17 +434,35 @@ void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) ) if ( ShowsSizeGrip() ) { const wxRect& rc = GetSizeGripRect(); +#ifdef __WXGTK3__ + GtkWidget* toplevel = gtk_widget_get_toplevel(m_widget); + if (toplevel && !gtk_window_get_has_resize_grip(GTK_WINDOW(toplevel))) + { + GtkStyleContext* sc = gtk_widget_get_style_context(toplevel); + gtk_style_context_save(sc); + gtk_style_context_add_class(sc, GTK_STYLE_CLASS_GRIP); + GtkJunctionSides sides = GTK_JUNCTION_CORNER_BOTTOMRIGHT; + if (GetLayoutDirection() == wxLayout_RightToLeft) + sides = GTK_JUNCTION_CORNER_BOTTOMLEFT; + gtk_style_context_set_junction_sides(sc, sides); + gtk_render_handle(sc, + static_cast(dc.GetImpl()->GetCairoContext()), + rc.x, rc.y, rc.width, rc.height); + gtk_style_context_restore(sc); + } +#else GdkWindowEdge edge = GetLayoutDirection() == wxLayout_RightToLeft ? GDK_WINDOW_EDGE_SOUTH_WEST : GDK_WINDOW_EDGE_SOUTH_EAST; - gtk_paint_resize_grip( m_widget->style, + gtk_paint_resize_grip(gtk_widget_get_style(m_widget), GTKGetDrawingWindow(), - (GtkStateType) GTK_WIDGET_STATE (m_widget), + gtk_widget_get_state(m_widget), NULL, m_widget, "statusbar", edge, rc.x, rc.y, rc.width, rc.height ); +#endif } #endif // __WXGTK20__ @@ -384,7 +477,6 @@ void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) ) DrawField(dc, i, textHeight); } -// Responds to colour changes, and passes event on to children. void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event) { InitColours(); @@ -393,19 +485,20 @@ void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event) wxWindow::OnSysColourChanged(event); } +#ifdef __WXGTK20__ void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event) { -#ifdef __WXGTK20__ int width, height; GetClientSize(&width, &height); - if ( ShowsSizeGrip() && (event.GetX() > width-height) ) - { - GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget ); - - if (!GTK_IS_WINDOW (ancestor)) - return; + GtkWidget* ancestor = gtk_widget_get_toplevel(m_widget); +#ifdef __WXGTK3__ + if (ancestor && gtk_window_get_has_resize_grip(GTK_WINDOW(ancestor))) + ancestor = NULL; +#endif + if (ancestor && ShowsSizeGrip() && event.GetX() > width - height) + { GdkWindow *source = GTKGetDrawingWindow(); int org_x = 0; @@ -435,24 +528,21 @@ void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event) { event.Skip( true ); } -#else - event.Skip( true ); -#endif } void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event) { -#ifdef __WXGTK20__ int width, height; GetClientSize(&width, &height); - if ( ShowsSizeGrip() && (event.GetX() > width-height) ) - { - GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget ); - - if (!GTK_IS_WINDOW (ancestor)) - return; + GtkWidget* ancestor = gtk_widget_get_toplevel(m_widget); +#ifdef __WXGTK3__ + if (ancestor && gtk_window_get_has_resize_grip(GTK_WINDOW(ancestor))) + ancestor = NULL; +#endif + if (ancestor && ShowsSizeGrip() && event.GetX() > width - height) + { GdkWindow *source = GTKGetDrawingWindow(); int org_x = 0; @@ -469,23 +559,14 @@ void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event) { event.Skip( true ); } -#else - event.Skip( true ); -#endif } +#endif // __WXGTK20__ -void wxStatusBarGeneric::OnSize(wxSizeEvent& WXUNUSED(event)) +void wxStatusBarGeneric::OnSize(wxSizeEvent& event) { - // FIXME: workarounds for OS/2 bugs have nothing to do here (VZ) - int width; -#ifdef __WXPM__ - GetSize(&width, &m_lastClientHeight); -#else - GetClientSize(&width, &m_lastClientHeight); -#endif + DoUpdateFieldWidths(); - // recompute the cache of the field widths if the status bar width has changed - m_widthsAbs = CalculateAbsWidths(width); + event.Skip(); } #endif // wxUSE_STATUSBAR