]> git.saurik.com Git - wxWidgets.git/blame - src/generic/hyperlink.cpp
Override GetPixelSize on OS X as the base impl creates a wxScreenDC each time, which...
[wxWidgets.git] / src / generic / hyperlink.cpp
CommitLineData
17e91437 1/////////////////////////////////////////////////////////////////////////////
98159dd8 2// Name: src/generic/hyperlink.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
49IMPLEMENT_DYNAMIC_CLASS(wxHyperlinkCtrl, wxControl)
258b2ca6 50IMPLEMENT_DYNAMIC_CLASS(wxHyperlinkEvent, wxCommandEvent)
17e91437
VZ
51DEFINE_EVENT_TYPE(wxEVT_COMMAND_HYPERLINK)
52
53// reserved for internal use only
54#define wxHYPERLINKCTRL_POPUP_COPY_ID 16384
55
b85db900
RD
56const wxChar wxHyperlinkCtrlNameStr[] = wxT("hyperlink");
57
17e91437
VZ
58// ----------------------------------------------------------------------------
59// wxHyperlinkCtrl
60// ----------------------------------------------------------------------------
61
62BEGIN_EVENT_TABLE(wxHyperlinkCtrl, wxControl)
63 EVT_PAINT(wxHyperlinkCtrl::OnPaint)
64 EVT_LEFT_DOWN(wxHyperlinkCtrl::OnLeftDown)
65 EVT_LEFT_UP(wxHyperlinkCtrl::OnLeftUp)
66 EVT_RIGHT_UP(wxHyperlinkCtrl::OnRightUp)
914f5157 67 EVT_MOTION(wxHyperlinkCtrl::OnMotion)
17e91437 68 EVT_LEAVE_WINDOW(wxHyperlinkCtrl::OnLeaveWindow)
914f5157 69 EVT_SIZE(wxHyperlinkCtrl::OnSize)
17e91437
VZ
70
71 // for the context menu
72 EVT_MENU(wxHYPERLINKCTRL_POPUP_COPY_ID, wxHyperlinkCtrl::OnPopUpCopy)
73END_EVENT_TABLE()
74
75bool wxHyperlinkCtrl::Create(wxWindow *parent, wxWindowID id,
76 const wxString& label, const wxString& url, const wxPoint& pos,
77 const wxSize& size, long style, const wxString& name)
78{
98159dd8 79 wxASSERT_MSG(!url.empty() || !label.empty(),
17e91437
VZ
80 wxT("Both URL and label are empty ?"));
81
914f5157
VZ
82#ifdef __WXDEBUG__
83 int alignment = (int)((style & wxHL_ALIGN_LEFT) != 0) +
84 (int)((style & wxHL_ALIGN_CENTRE) != 0) +
85 (int)((style & wxHL_ALIGN_RIGHT) != 0);
86 wxASSERT_MSG(alignment == 1,
87 wxT("Specify exactly one align flag!"));
88#endif
89
17e91437
VZ
90 if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name))
91 return false;
92
93 // set to non empty strings both the url and the label
98159dd8
WS
94 if(url.empty())
95 SetURL(label);
96 else
06ec4d9c 97 SetURL(url);
98159dd8
WS
98
99 if(label.empty())
100 SetLabel(url);
101 else
102 SetLabel(label);
17e91437 103
17e91437
VZ
104 m_rollover = false;
105 m_clicking = false;
106 m_visited = false;
107
108 // colours
109 m_normalColour = *wxBLUE;
110 m_hoverColour = *wxRED;
111 SetForegroundColour(m_normalColour);
112
113 // by default the font of an hyperlink control is underlined
114 wxFont f = GetFont();
115 f.SetUnderlined(true);
116 SetFont(f);
117
b4b5a92e
RD
118 SetBestFittingSize(size);
119
17e91437
VZ
120 return true;
121}
122
123wxSize wxHyperlinkCtrl::DoGetBestSize() const
124{
125 int w, h;
126
127 wxClientDC dc((wxWindow *)this);
128 dc.SetFont(GetFont());
129 dc.GetTextExtent(GetLabel(), &w, &h);
130
b4b5a92e
RD
131 wxSize best(w, h);
132 CacheBestSize(best);
133 return best;
17e91437
VZ
134}
135
17e91437
VZ
136
137void wxHyperlinkCtrl::SetNormalColour(const wxColour &colour)
138{
139 m_normalColour = colour;
140 if (!m_visited)
141 {
142 SetForegroundColour(m_normalColour);
143 Refresh();
144 }
145}
146
147void wxHyperlinkCtrl::SetVisitedColour(const wxColour &colour)
148{
149 m_visitedColour = colour;
150 if (m_visited)
151 {
152 SetForegroundColour(m_visitedColour);
153 Refresh();
154 }
155}
156
157void wxHyperlinkCtrl::DoContextMenu(const wxPoint &pos)
158{
159 wxMenu *menuPopUp = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
160 menuPopUp->Append(wxHYPERLINKCTRL_POPUP_COPY_ID, wxT("Copy URL"));
161 PopupMenu( menuPopUp, pos );
162 delete menuPopUp;
163}
164
914f5157
VZ
165wxRect wxHyperlinkCtrl::GetLabelRect() const
166{
167 // our best size is always the size of the label without borders
168 wxSize c(GetClientSize()), b(GetBestSize());
169 wxPoint offset;
170
171 // the label is always centered vertically
172 offset.y = (c.GetHeight()-b.GetHeight())/2;
173
174 if (HasFlag(wxHL_ALIGN_CENTRE))
175 offset.x = (c.GetWidth()-b.GetWidth())/2;
176 else if (HasFlag(wxHL_ALIGN_RIGHT))
177 offset.x = c.GetWidth()-b.GetWidth();
178 else if (HasFlag(wxHL_ALIGN_LEFT))
179 offset.x = 0;
180 return wxRect(offset, b);
181}
182
17e91437
VZ
183
184
185// ----------------------------------------------------------------------------
186// wxHyperlinkCtrl - event handlers
187// ----------------------------------------------------------------------------
188
189void wxHyperlinkCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
190{
191 wxPaintDC dc(this);
192 dc.SetFont(GetFont());
193 dc.SetTextForeground(GetForegroundColour());
194 dc.SetTextBackground(GetBackgroundColour());
914f5157
VZ
195
196 dc.DrawText(GetLabel(), GetLabelRect().GetTopLeft());
17e91437
VZ
197}
198
914f5157 199void wxHyperlinkCtrl::OnLeftDown(wxMouseEvent& event)
17e91437 200{
914f5157 201 // the left click must start from the hyperlink rect
22a35096 202 m_clicking = GetLabelRect().Contains(event.GetPosition());
17e91437
VZ
203}
204
914f5157 205void wxHyperlinkCtrl::OnLeftUp(wxMouseEvent& event)
17e91437 206{
914f5157 207 // the click must be started and ended in the hyperlink rect
22a35096 208 if (!m_clicking || !GetLabelRect().Contains(event.GetPosition()))
914f5157 209 return;
17e91437
VZ
210
211 SetForegroundColour(m_visitedColour);
212 m_visited = true;
213 m_clicking = false;
214
215 // send the event
216 wxHyperlinkEvent linkEvent(this, GetId(), m_url);
217 if (!GetEventHandler()->ProcessEvent(linkEvent)) // was the event skipped ?
218 if (!wxLaunchDefaultBrowser(m_url))
219 wxLogWarning(wxT("Could not launch the default browser with url '%s' !"), m_url.c_str());
220}
221
222void wxHyperlinkCtrl::OnRightUp(wxMouseEvent& event)
223{
224 if( GetWindowStyle() & wxHL_CONTEXTMENU )
22a35096 225 if ( GetLabelRect().Contains(event.GetPosition()) )
914f5157 226 DoContextMenu(wxPoint(event.m_x, event.m_y));
17e91437
VZ
227}
228
914f5157 229void wxHyperlinkCtrl::OnMotion(wxMouseEvent& event)
17e91437 230{
914f5157
VZ
231 wxRect textrc = GetLabelRect();
232
22a35096 233 if (textrc.Contains(event.GetPosition()))
914f5157
VZ
234 {
235 SetCursor(wxCursor(wxCURSOR_HAND));
236 SetForegroundColour(m_hoverColour);
237 m_rollover = true;
238 Refresh();
239 }
240 else if (m_rollover)
241 {
242 SetCursor(*wxSTANDARD_CURSOR);
243 SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
244 m_rollover = false;
245 Refresh();
246 }
17e91437
VZ
247}
248
914f5157 249void wxHyperlinkCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event) )
17e91437 250{
914f5157
VZ
251 // NB: when the label rect and the client size rect have the same
252 // height this function is indispensable to remove the "rollover"
253 // effect as the OnMotion() event handler could not be called
254 // in that case moving the mouse out of the label vertically...
255
17e91437
VZ
256 if (m_rollover)
257 {
914f5157 258 SetCursor(*wxSTANDARD_CURSOR);
17e91437
VZ
259 SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
260 m_rollover = false;
261 Refresh();
262 }
263}
264
265void wxHyperlinkCtrl::OnPopUpCopy( wxCommandEvent& WXUNUSED(event) )
266{
3cb3b8b8 267#if wxUSE_CLIPBOARD
17e91437
VZ
268 if (!wxTheClipboard->Open())
269 return;
270
271 wxTextDataObject *data = new wxTextDataObject( m_url );
272 wxTheClipboard->SetData( data );
273 wxTheClipboard->Close();
3cb3b8b8 274#endif // wxUSE_CLIPBOARD
17e91437
VZ
275}
276
914f5157
VZ
277void wxHyperlinkCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
278{
279 // update the position of the label in the screen respecting
280 // the selected align flag
281 Refresh();
282}
283
17e91437 284#endif // wxUSE_HYPERLINKCTRL