]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/hyperlinkg.cpp
native wxHyperlinkCtrl implementation for GTK+ 2.10+ (patch 1661851)
[wxWidgets.git] / src / generic / hyperlinkg.cpp
diff --git a/src/generic/hyperlinkg.cpp b/src/generic/hyperlinkg.cpp
new file mode 100644 (file)
index 0000000..573c18d
--- /dev/null
@@ -0,0 +1,269 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        src/generic/hyperlinkg.cpp
+// Purpose:     Hyperlink control
+// Author:      David Norris <danorris@gmail.com>, Otto Wyss
+// Modified by: Ryan Norton, Francesco Montorsi
+// Created:     04/02/2005
+// RCS-ID:      $Id$
+// Copyright:   (c) 2005 David Norris
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+//---------------------------------------------------------------------------
+// Pre-compiled header stuff
+//---------------------------------------------------------------------------
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_HYPERLINKCTRL
+
+//---------------------------------------------------------------------------
+// Includes
+//---------------------------------------------------------------------------
+
+#include "wx/hyperlink.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/utils.h" // for wxLaunchDefaultBrowser
+    #include "wx/dcclient.h"
+    #include "wx/menu.h"
+    #include "wx/log.h"
+    #include "wx/dataobj.h"
+#endif
+
+#include "wx/clipbrd.h"
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+IMPLEMENT_DYNAMIC_CLASS(wxGenericHyperlinkCtrl, wxControl)
+
+// reserved for internal use only
+#define wxHYPERLINK_POPUP_COPY_ID           16384
+
+// ----------------------------------------------------------------------------
+// wxGenericHyperlinkCtrl
+// ----------------------------------------------------------------------------
+
+bool wxGenericHyperlinkCtrl::Create(wxWindow *parent, wxWindowID id,
+    const wxString& label, const wxString& url, const wxPoint& pos,
+    const wxSize& size, long style, const wxString& name)
+{
+    // do validation checks:
+    CheckParams(label, url, style);
+
+    if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name))
+        return false;
+
+    // set to non empty strings both the url and the label
+    SetURL(url.empty() ? label : url);
+    SetLabel(label.empty() ? url : label);
+
+    m_rollover = false;
+    m_clicking = false;
+    m_visited = false;
+
+    // colours
+    m_normalColour = *wxBLUE;
+    m_hoverColour = *wxRED;
+    SetForegroundColour(m_normalColour);
+
+    // by default the font of an hyperlink control is underlined
+    wxFont f = GetFont();
+    f.SetUnderlined(true);
+    SetFont(f);
+
+    SetInitialSize(size);
+
+
+    // connect our event handlers:
+    // NOTE: since this class is the base class of the GTK+'s native implementation
+    //       of wxHyperlinkCtrl, we cannot use the static macros in BEGIN/END_EVENT_TABLE
+    //       blocks, otherwise the GTK+'s native impl of wxHyperlinkCtrl would not
+    //       behave correctly (as we intercept events doing things which interfere
+    //       with GTK+'s native handling):
+
+    Connect( wxEVT_PAINT, wxPaintEventHandler(wxGenericHyperlinkCtrl::OnPaint) );
+    Connect( wxEVT_SIZE, wxSizeEventHandler(wxGenericHyperlinkCtrl::OnSize) );
+    Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnLeaveWindow) );
+
+    Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnLeftDown) );
+    Connect( wxEVT_LEFT_UP, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnLeftUp) );
+    Connect( wxEVT_RIGHT_UP, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnRightUp) );
+    Connect( wxEVT_MOTION, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnMotion) );
+
+    Connect( wxHYPERLINK_POPUP_COPY_ID, wxEVT_COMMAND_MENU_SELECTED,
+             wxCommandEventHandler(wxGenericHyperlinkCtrl::OnPopUpCopy) );
+
+    return true;
+}
+
+wxSize wxGenericHyperlinkCtrl::DoGetBestSize() const
+{
+    int w, h;
+
+    wxClientDC dc((wxWindow *)this);
+    dc.SetFont(GetFont());
+    dc.GetTextExtent(GetLabel(), &w, &h);
+
+    wxSize best(w, h);
+    CacheBestSize(best);
+    return best;
+}
+
+
+void wxGenericHyperlinkCtrl::SetNormalColour(const wxColour &colour)
+{
+    m_normalColour = colour;
+    if (!m_visited)
+    {
+        SetForegroundColour(m_normalColour);
+        Refresh();
+    }
+}
+
+void wxGenericHyperlinkCtrl::SetVisitedColour(const wxColour &colour)
+{
+    m_visitedColour = colour;
+    if (m_visited)
+    {
+        SetForegroundColour(m_visitedColour);
+        Refresh();
+    }
+}
+
+void wxGenericHyperlinkCtrl::DoContextMenu(const wxPoint &pos)
+{
+    wxMenu *menuPopUp = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
+    menuPopUp->Append(wxHYPERLINK_POPUP_COPY_ID, wxT("Copy URL"));
+    PopupMenu( menuPopUp, pos );
+    delete menuPopUp;
+}
+
+wxRect wxGenericHyperlinkCtrl::GetLabelRect() const
+{
+    // our best size is always the size of the label without borders
+    wxSize c(GetClientSize()), b(GetBestSize());
+    wxPoint offset;
+
+    // the label is always centered vertically
+    offset.y = (c.GetHeight()-b.GetHeight())/2;
+
+    if (HasFlag(wxHL_ALIGN_CENTRE))
+        offset.x = (c.GetWidth()-b.GetWidth())/2;
+    else if (HasFlag(wxHL_ALIGN_RIGHT))
+        offset.x = c.GetWidth()-b.GetWidth();
+    else if (HasFlag(wxHL_ALIGN_LEFT))
+        offset.x = 0;
+    return wxRect(offset, b);
+}
+
+
+
+// ----------------------------------------------------------------------------
+// wxGenericHyperlinkCtrl - event handlers
+// ----------------------------------------------------------------------------
+
+void wxGenericHyperlinkCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
+{
+    wxPaintDC dc(this);
+    dc.SetFont(GetFont());
+    dc.SetTextForeground(GetForegroundColour());
+    dc.SetTextBackground(GetBackgroundColour());
+
+    dc.DrawText(GetLabel(), GetLabelRect().GetTopLeft());
+}
+
+void wxGenericHyperlinkCtrl::OnLeftDown(wxMouseEvent& event)
+{
+    // the left click must start from the hyperlink rect
+    m_clicking = GetLabelRect().Contains(event.GetPosition());
+}
+
+void wxGenericHyperlinkCtrl::OnLeftUp(wxMouseEvent& event)
+{
+    // the click must be started and ended in the hyperlink rect
+    if (!m_clicking || !GetLabelRect().Contains(event.GetPosition())) 
+        return;
+
+    SetForegroundColour(m_visitedColour);
+    m_visited = true;
+    m_clicking = false;
+
+    // send the event
+    SendEvent();
+}
+
+void wxGenericHyperlinkCtrl::OnRightUp(wxMouseEvent& event)
+{
+    if( GetWindowStyle() & wxHL_CONTEXTMENU )
+        if ( GetLabelRect().Contains(event.GetPosition()) )
+            DoContextMenu(wxPoint(event.m_x, event.m_y));
+}
+
+void wxGenericHyperlinkCtrl::OnMotion(wxMouseEvent& event)
+{
+    wxRect textrc = GetLabelRect();
+
+    if (textrc.Contains(event.GetPosition()))
+    {
+        SetCursor(wxCursor(wxCURSOR_HAND));
+        SetForegroundColour(m_hoverColour);
+        m_rollover = true;
+        Refresh();
+    }
+    else if (m_rollover)
+    {
+        SetCursor(*wxSTANDARD_CURSOR);
+        SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
+        m_rollover = false;
+        Refresh();
+    }
+}
+
+void wxGenericHyperlinkCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event) )
+{
+    // NB: when the label rect and the client size rect have the same
+    //     height this function is indispensable to remove the "rollover"
+    //     effect as the OnMotion() event handler could not be called
+    //     in that case moving the mouse out of the label vertically...
+
+    if (m_rollover)
+    {
+        SetCursor(*wxSTANDARD_CURSOR);
+        SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
+        m_rollover = false;
+        Refresh();
+    }
+}
+
+void wxGenericHyperlinkCtrl::OnPopUpCopy( wxCommandEvent& WXUNUSED(event) )
+{
+#if wxUSE_CLIPBOARD
+    if (!wxTheClipboard->Open())
+        return;
+
+    wxTextDataObject *data = new wxTextDataObject( m_url );
+    wxTheClipboard->SetData( data );
+    wxTheClipboard->Close();
+#endif // wxUSE_CLIPBOARD
+}
+
+void wxGenericHyperlinkCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
+{
+    // update the position of the label in the screen respecting
+    // the selected align flag
+    Refresh();
+}
+
+#endif // wxUSE_HYPERLINKCTRL