]> git.saurik.com Git - wxWidgets.git/blob - src/generic/hyperlink.cpp
HIShapeCreateEmpty doesn't exist prior to OSX 10.4, use
[wxWidgets.git] / src / generic / hyperlink.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/hyperlink.cpp
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
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_HYPERLINKCTRL
28
29 //---------------------------------------------------------------------------
30 // Includes
31 //---------------------------------------------------------------------------
32
33 #include "wx/hyperlink.h"
34
35 #ifndef WX_PRECOMP
36 #include "wx/utils.h" // for wxLaunchDefaultBrowser
37 #include "wx/dcclient.h"
38 #include "wx/menu.h"
39 #include "wx/log.h"
40 #include "wx/dataobj.h"
41 #endif
42
43 #include "wx/clipbrd.h"
44
45 // ============================================================================
46 // implementation
47 // ============================================================================
48
49 IMPLEMENT_DYNAMIC_CLASS(wxHyperlinkCtrl, wxControl)
50 IMPLEMENT_DYNAMIC_CLASS(wxHyperlinkEvent, wxCommandEvent)
51 DEFINE_EVENT_TYPE(wxEVT_COMMAND_HYPERLINK)
52
53 // reserved for internal use only
54 #define wxHYPERLINKCTRL_POPUP_COPY_ID 16384
55
56 const wxChar wxHyperlinkCtrlNameStr[] = wxT("hyperlink");
57
58 // ----------------------------------------------------------------------------
59 // wxHyperlinkCtrl
60 // ----------------------------------------------------------------------------
61
62 BEGIN_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)
67 EVT_MOTION(wxHyperlinkCtrl::OnMotion)
68 EVT_LEAVE_WINDOW(wxHyperlinkCtrl::OnLeaveWindow)
69 EVT_SIZE(wxHyperlinkCtrl::OnSize)
70
71 // for the context menu
72 EVT_MENU(wxHYPERLINKCTRL_POPUP_COPY_ID, wxHyperlinkCtrl::OnPopUpCopy)
73 END_EVENT_TABLE()
74
75 bool 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 {
79 wxASSERT_MSG(!url.empty() || !label.empty(),
80 wxT("Both URL and label are empty ?"));
81
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
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
94 if(url.empty())
95 SetURL(label);
96 else
97 SetURL(url);
98
99 if(label.empty())
100 SetLabel(url);
101 else
102 SetLabel(label);
103
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
125 wxSize 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
136 void wxHyperlinkCtrl::DoGetSize(int *width, int *height) const
137 {
138 if (width) *width = GetBestSize().GetWidth();
139 if (height) *height = GetBestSize().GetHeight();
140 }
141
142 void wxHyperlinkCtrl::SetNormalColour(const wxColour &colour)
143 {
144 m_normalColour = colour;
145 if (!m_visited)
146 {
147 SetForegroundColour(m_normalColour);
148 Refresh();
149 }
150 }
151
152 void wxHyperlinkCtrl::SetVisitedColour(const wxColour &colour)
153 {
154 m_visitedColour = colour;
155 if (m_visited)
156 {
157 SetForegroundColour(m_visitedColour);
158 Refresh();
159 }
160 }
161
162 void 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
170 wxRect 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
188
189
190 // ----------------------------------------------------------------------------
191 // wxHyperlinkCtrl - event handlers
192 // ----------------------------------------------------------------------------
193
194 void wxHyperlinkCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
195 {
196 wxPaintDC dc(this);
197 dc.SetFont(GetFont());
198 dc.SetTextForeground(GetForegroundColour());
199 dc.SetTextBackground(GetBackgroundColour());
200
201 dc.DrawText(GetLabel(), GetLabelRect().GetTopLeft());
202 }
203
204 void wxHyperlinkCtrl::OnLeftDown(wxMouseEvent& event)
205 {
206 // the left click must start from the hyperlink rect
207 m_clicking = GetLabelRect().Contains(event.GetPosition());
208 }
209
210 void wxHyperlinkCtrl::OnLeftUp(wxMouseEvent& event)
211 {
212 // the click must be started and ended in the hyperlink rect
213 if (!m_clicking || !GetLabelRect().Contains(event.GetPosition()))
214 return;
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
227 void wxHyperlinkCtrl::OnRightUp(wxMouseEvent& event)
228 {
229 if( GetWindowStyle() & wxHL_CONTEXTMENU )
230 if ( GetLabelRect().Contains(event.GetPosition()) )
231 DoContextMenu(wxPoint(event.m_x, event.m_y));
232 }
233
234 void wxHyperlinkCtrl::OnMotion(wxMouseEvent& event)
235 {
236 wxRect textrc = GetLabelRect();
237
238 if (textrc.Contains(event.GetPosition()))
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 }
252 }
253
254 void wxHyperlinkCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event) )
255 {
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
261 if (m_rollover)
262 {
263 SetCursor(*wxSTANDARD_CURSOR);
264 SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
265 m_rollover = false;
266 Refresh();
267 }
268 }
269
270 void wxHyperlinkCtrl::OnPopUpCopy( wxCommandEvent& WXUNUSED(event) )
271 {
272 #if wxUSE_CLIPBOARD
273 if (!wxTheClipboard->Open())
274 return;
275
276 wxTextDataObject *data = new wxTextDataObject( m_url );
277 wxTheClipboard->SetData( data );
278 wxTheClipboard->Close();
279 #endif // wxUSE_CLIPBOARD
280 }
281
282 void 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
289 #endif // wxUSE_HYPERLINKCTRL