]> git.saurik.com Git - wxWidgets.git/blame - src/generic/hyperlink.cpp
Fix setting the clipping region for a DC when the region is an
[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
118 CacheBestSize(DoGetBestSize());
119 SetMinSize(GetBestSize());
120 SetSize (DoGetBestSize());
121
122 return true;
123}
124
125wxSize wxHyperlinkCtrl::DoGetBestSize() const
126{
127 int w, h;
128
129 wxClientDC dc((wxWindow *)this);
130 dc.SetFont(GetFont());
131 dc.GetTextExtent(GetLabel(), &w, &h);
132
133 return wxSize(w, h);
134}
135
136void wxHyperlinkCtrl::DoGetSize(int *width, int *height) const
137{
138 if (width) *width = GetBestSize().GetWidth();
139 if (height) *height = GetBestSize().GetHeight();
140}
141
142void wxHyperlinkCtrl::SetNormalColour(const wxColour &colour)
143{
144 m_normalColour = colour;
145 if (!m_visited)
146 {
147 SetForegroundColour(m_normalColour);
148 Refresh();
149 }
150}
151
152void wxHyperlinkCtrl::SetVisitedColour(const wxColour &colour)
153{
154 m_visitedColour = colour;
155 if (m_visited)
156 {
157 SetForegroundColour(m_visitedColour);
158 Refresh();
159 }
160}
161
162void wxHyperlinkCtrl::DoContextMenu(const wxPoint &pos)
163{
164 wxMenu *menuPopUp = new wxMenu(wxEmptyString, wxMENU_TEAROFF);
165 menuPopUp->Append(wxHYPERLINKCTRL_POPUP_COPY_ID, wxT("Copy URL"));
166 PopupMenu( menuPopUp, pos );
167 delete menuPopUp;
168}
169
914f5157
VZ
170wxRect wxHyperlinkCtrl::GetLabelRect() const
171{
172 // our best size is always the size of the label without borders
173 wxSize c(GetClientSize()), b(GetBestSize());
174 wxPoint offset;
175
176 // the label is always centered vertically
177 offset.y = (c.GetHeight()-b.GetHeight())/2;
178
179 if (HasFlag(wxHL_ALIGN_CENTRE))
180 offset.x = (c.GetWidth()-b.GetWidth())/2;
181 else if (HasFlag(wxHL_ALIGN_RIGHT))
182 offset.x = c.GetWidth()-b.GetWidth();
183 else if (HasFlag(wxHL_ALIGN_LEFT))
184 offset.x = 0;
185 return wxRect(offset, b);
186}
187
17e91437
VZ
188
189
190// ----------------------------------------------------------------------------
191// wxHyperlinkCtrl - event handlers
192// ----------------------------------------------------------------------------
193
194void wxHyperlinkCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
195{
196 wxPaintDC dc(this);
197 dc.SetFont(GetFont());
198 dc.SetTextForeground(GetForegroundColour());
199 dc.SetTextBackground(GetBackgroundColour());
914f5157
VZ
200
201 dc.DrawText(GetLabel(), GetLabelRect().GetTopLeft());
17e91437
VZ
202}
203
914f5157 204void wxHyperlinkCtrl::OnLeftDown(wxMouseEvent& event)
17e91437 205{
914f5157 206 // the left click must start from the hyperlink rect
22a35096 207 m_clicking = GetLabelRect().Contains(event.GetPosition());
17e91437
VZ
208}
209
914f5157 210void wxHyperlinkCtrl::OnLeftUp(wxMouseEvent& event)
17e91437 211{
914f5157 212 // the click must be started and ended in the hyperlink rect
22a35096 213 if (!m_clicking || !GetLabelRect().Contains(event.GetPosition()))
914f5157 214 return;
17e91437
VZ
215
216 SetForegroundColour(m_visitedColour);
217 m_visited = true;
218 m_clicking = false;
219
220 // send the event
221 wxHyperlinkEvent linkEvent(this, GetId(), m_url);
222 if (!GetEventHandler()->ProcessEvent(linkEvent)) // was the event skipped ?
223 if (!wxLaunchDefaultBrowser(m_url))
224 wxLogWarning(wxT("Could not launch the default browser with url '%s' !"), m_url.c_str());
225}
226
227void wxHyperlinkCtrl::OnRightUp(wxMouseEvent& event)
228{
229 if( GetWindowStyle() & wxHL_CONTEXTMENU )
22a35096 230 if ( GetLabelRect().Contains(event.GetPosition()) )
914f5157 231 DoContextMenu(wxPoint(event.m_x, event.m_y));
17e91437
VZ
232}
233
914f5157 234void wxHyperlinkCtrl::OnMotion(wxMouseEvent& event)
17e91437 235{
914f5157
VZ
236 wxRect textrc = GetLabelRect();
237
22a35096 238 if (textrc.Contains(event.GetPosition()))
914f5157
VZ
239 {
240 SetCursor(wxCursor(wxCURSOR_HAND));
241 SetForegroundColour(m_hoverColour);
242 m_rollover = true;
243 Refresh();
244 }
245 else if (m_rollover)
246 {
247 SetCursor(*wxSTANDARD_CURSOR);
248 SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
249 m_rollover = false;
250 Refresh();
251 }
17e91437
VZ
252}
253
914f5157 254void wxHyperlinkCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event) )
17e91437 255{
914f5157
VZ
256 // NB: when the label rect and the client size rect have the same
257 // height this function is indispensable to remove the "rollover"
258 // effect as the OnMotion() event handler could not be called
259 // in that case moving the mouse out of the label vertically...
260
17e91437
VZ
261 if (m_rollover)
262 {
914f5157 263 SetCursor(*wxSTANDARD_CURSOR);
17e91437
VZ
264 SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
265 m_rollover = false;
266 Refresh();
267 }
268}
269
270void wxHyperlinkCtrl::OnPopUpCopy( wxCommandEvent& WXUNUSED(event) )
271{
3cb3b8b8 272#if wxUSE_CLIPBOARD
17e91437
VZ
273 if (!wxTheClipboard->Open())
274 return;
275
276 wxTextDataObject *data = new wxTextDataObject( m_url );
277 wxTheClipboard->SetData( data );
278 wxTheClipboard->Close();
3cb3b8b8 279#endif // wxUSE_CLIPBOARD
17e91437
VZ
280}
281
914f5157
VZ
282void wxHyperlinkCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
283{
284 // update the position of the label in the screen respecting
285 // the selected align flag
286 Refresh();
287}
288
17e91437 289#endif // wxUSE_HYPERLINKCTRL