]> git.saurik.com Git - wxWidgets.git/blame - src/generic/hyperlinkg.cpp
Improved handling of anchors in wxHTML: scroll to better position (patch #11406).
[wxWidgets.git] / src / generic / hyperlinkg.cpp
CommitLineData
17e91437 1/////////////////////////////////////////////////////////////////////////////
c105dda0 2// Name: src/generic/hyperlinkg.cpp
17e91437
VZ
3// Purpose: Hyperlink control
4// Author: David Norris <danorris@gmail.com>, Otto Wyss
5// Modified by: Ryan Norton, Francesco Montorsi
6// Created: 04/02/2005
7// RCS-ID: $Id$
8// Copyright: (c) 2005 David Norris
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16//---------------------------------------------------------------------------
17// Pre-compiled header stuff
18//---------------------------------------------------------------------------
19
17e91437
VZ
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
3cb3b8b8 24 #pragma hdrstop
17e91437
VZ
25#endif
26
98159dd8
WS
27#if wxUSE_HYPERLINKCTRL
28
17e91437
VZ
29//---------------------------------------------------------------------------
30// Includes
31//---------------------------------------------------------------------------
32
33#include "wx/hyperlink.h"
17e91437 34
98159dd8
WS
35#ifndef WX_PRECOMP
36 #include "wx/utils.h" // for wxLaunchDefaultBrowser
33f9f48e
WS
37 #include "wx/dcclient.h"
38 #include "wx/menu.h"
39 #include "wx/log.h"
28f92d74 40 #include "wx/dataobj.h"
98159dd8 41#endif
17e91437 42
98159dd8 43#include "wx/clipbrd.h"
17e91437
VZ
44
45// ============================================================================
46// implementation
47// ============================================================================
48
c105dda0 49IMPLEMENT_DYNAMIC_CLASS(wxGenericHyperlinkCtrl, wxControl)
17e91437
VZ
50
51// reserved for internal use only
c105dda0 52#define wxHYPERLINK_POPUP_COPY_ID 16384
b85db900 53
17e91437 54// ----------------------------------------------------------------------------
c105dda0 55// wxGenericHyperlinkCtrl
17e91437
VZ
56// ----------------------------------------------------------------------------
57
c105dda0 58bool wxGenericHyperlinkCtrl::Create(wxWindow *parent, wxWindowID id,
17e91437
VZ
59 const wxString& label, const wxString& url, const wxPoint& pos,
60 const wxSize& size, long style, const wxString& name)
61{
c105dda0
VZ
62 // do validation checks:
63 CheckParams(label, url, style);
914f5157 64
6d020baf
PC
65 if ((style & wxHL_ALIGN_LEFT) == 0)
66 style |= wxFULL_REPAINT_ON_RESIZE;
67
17e91437
VZ
68 if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name))
69 return false;
70
71 // set to non empty strings both the url and the label
c105dda0
VZ
72 SetURL(url.empty() ? label : url);
73 SetLabel(label.empty() ? url : label);
17e91437 74
17e91437
VZ
75 m_rollover = false;
76 m_clicking = false;
77 m_visited = false;
78
79 // colours
80 m_normalColour = *wxBLUE;
81 m_hoverColour = *wxRED;
c25bb731 82 m_visitedColour = wxColour("#551a8b");
17e91437
VZ
83 SetForegroundColour(m_normalColour);
84
85 // by default the font of an hyperlink control is underlined
86 wxFont f = GetFont();
87 f.SetUnderlined(true);
88 SetFont(f);
89
170acdc9 90 SetInitialSize(size);
c105dda0
VZ
91
92
93 // connect our event handlers:
94 // NOTE: since this class is the base class of the GTK+'s native implementation
95 // of wxHyperlinkCtrl, we cannot use the static macros in BEGIN/END_EVENT_TABLE
96 // blocks, otherwise the GTK+'s native impl of wxHyperlinkCtrl would not
97 // behave correctly (as we intercept events doing things which interfere
98 // with GTK+'s native handling):
99
100 Connect( wxEVT_PAINT, wxPaintEventHandler(wxGenericHyperlinkCtrl::OnPaint) );
c105dda0
VZ
101 Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnLeaveWindow) );
102
103 Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnLeftDown) );
104 Connect( wxEVT_LEFT_UP, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnLeftUp) );
105 Connect( wxEVT_RIGHT_UP, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnRightUp) );
106 Connect( wxEVT_MOTION, wxMouseEventHandler(wxGenericHyperlinkCtrl::OnMotion) );
107
108 Connect( wxHYPERLINK_POPUP_COPY_ID, wxEVT_COMMAND_MENU_SELECTED,
109 wxCommandEventHandler(wxGenericHyperlinkCtrl::OnPopUpCopy) );
110
17e91437
VZ
111 return true;
112}
113
c105dda0 114wxSize wxGenericHyperlinkCtrl::DoGetBestSize() const
17e91437
VZ
115{
116 int w, h;
117
118 wxClientDC dc((wxWindow *)this);
119 dc.SetFont(GetFont());
120 dc.GetTextExtent(GetLabel(), &w, &h);
121
b4b5a92e
RD
122 wxSize best(w, h);
123 CacheBestSize(best);
124 return best;
17e91437
VZ
125}
126
17e91437 127
c105dda0 128void wxGenericHyperlinkCtrl::SetNormalColour(const wxColour &colour)
17e91437
VZ
129{
130 m_normalColour = colour;
131 if (!m_visited)
132 {
133 SetForegroundColour(m_normalColour);
134 Refresh();
135 }
136}
137
c105dda0 138void wxGenericHyperlinkCtrl::SetVisitedColour(const wxColour &colour)
17e91437
VZ
139{
140 m_visitedColour = colour;
141 if (m_visited)
142 {
143 SetForegroundColour(m_visitedColour);
144 Refresh();
145 }
146}
147
c105dda0 148void wxGenericHyperlinkCtrl::DoContextMenu(const wxPoint &pos)
17e91437
VZ
149{
150 wxMenu *menuPopUp = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
28dd9a9d 151 menuPopUp->Append(wxHYPERLINK_POPUP_COPY_ID, _("&Copy URL"));
17e91437
VZ
152 PopupMenu( menuPopUp, pos );
153 delete menuPopUp;
154}
155
c105dda0 156wxRect wxGenericHyperlinkCtrl::GetLabelRect() const
914f5157
VZ
157{
158 // our best size is always the size of the label without borders
159 wxSize c(GetClientSize()), b(GetBestSize());
160 wxPoint offset;
161
162 // the label is always centered vertically
163 offset.y = (c.GetHeight()-b.GetHeight())/2;
164
165 if (HasFlag(wxHL_ALIGN_CENTRE))
166 offset.x = (c.GetWidth()-b.GetWidth())/2;
167 else if (HasFlag(wxHL_ALIGN_RIGHT))
168 offset.x = c.GetWidth()-b.GetWidth();
169 else if (HasFlag(wxHL_ALIGN_LEFT))
170 offset.x = 0;
171 return wxRect(offset, b);
172}
173
17e91437
VZ
174
175
176// ----------------------------------------------------------------------------
c105dda0 177// wxGenericHyperlinkCtrl - event handlers
17e91437
VZ
178// ----------------------------------------------------------------------------
179
c105dda0 180void wxGenericHyperlinkCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
17e91437
VZ
181{
182 wxPaintDC dc(this);
183 dc.SetFont(GetFont());
184 dc.SetTextForeground(GetForegroundColour());
185 dc.SetTextBackground(GetBackgroundColour());
914f5157
VZ
186
187 dc.DrawText(GetLabel(), GetLabelRect().GetTopLeft());
17e91437
VZ
188}
189
c105dda0 190void wxGenericHyperlinkCtrl::OnLeftDown(wxMouseEvent& event)
17e91437 191{
914f5157 192 // the left click must start from the hyperlink rect
22a35096 193 m_clicking = GetLabelRect().Contains(event.GetPosition());
17e91437
VZ
194}
195
c105dda0 196void wxGenericHyperlinkCtrl::OnLeftUp(wxMouseEvent& event)
17e91437 197{
914f5157 198 // the click must be started and ended in the hyperlink rect
03647350 199 if (!m_clicking || !GetLabelRect().Contains(event.GetPosition()))
914f5157 200 return;
17e91437
VZ
201
202 SetForegroundColour(m_visitedColour);
203 m_visited = true;
204 m_clicking = false;
205
206 // send the event
c105dda0 207 SendEvent();
17e91437
VZ
208}
209
c105dda0 210void wxGenericHyperlinkCtrl::OnRightUp(wxMouseEvent& event)
17e91437
VZ
211{
212 if( GetWindowStyle() & wxHL_CONTEXTMENU )
22a35096 213 if ( GetLabelRect().Contains(event.GetPosition()) )
914f5157 214 DoContextMenu(wxPoint(event.m_x, event.m_y));
17e91437
VZ
215}
216
c105dda0 217void wxGenericHyperlinkCtrl::OnMotion(wxMouseEvent& event)
17e91437 218{
914f5157
VZ
219 wxRect textrc = GetLabelRect();
220
22a35096 221 if (textrc.Contains(event.GetPosition()))
914f5157
VZ
222 {
223 SetCursor(wxCursor(wxCURSOR_HAND));
224 SetForegroundColour(m_hoverColour);
225 m_rollover = true;
226 Refresh();
227 }
228 else if (m_rollover)
229 {
230 SetCursor(*wxSTANDARD_CURSOR);
231 SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
232 m_rollover = false;
233 Refresh();
234 }
17e91437
VZ
235}
236
c105dda0 237void wxGenericHyperlinkCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event) )
17e91437 238{
914f5157
VZ
239 // NB: when the label rect and the client size rect have the same
240 // height this function is indispensable to remove the "rollover"
241 // effect as the OnMotion() event handler could not be called
242 // in that case moving the mouse out of the label vertically...
243
17e91437
VZ
244 if (m_rollover)
245 {
914f5157 246 SetCursor(*wxSTANDARD_CURSOR);
17e91437
VZ
247 SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
248 m_rollover = false;
249 Refresh();
250 }
251}
252
c105dda0 253void wxGenericHyperlinkCtrl::OnPopUpCopy( wxCommandEvent& WXUNUSED(event) )
17e91437 254{
3cb3b8b8 255#if wxUSE_CLIPBOARD
17e91437
VZ
256 if (!wxTheClipboard->Open())
257 return;
258
259 wxTextDataObject *data = new wxTextDataObject( m_url );
260 wxTheClipboard->SetData( data );
261 wxTheClipboard->Close();
3cb3b8b8 262#endif // wxUSE_CLIPBOARD
17e91437
VZ
263}
264
265#endif // wxUSE_HYPERLINKCTRL