]> git.saurik.com Git - wxWidgets.git/blob - src/generic/hyperlink.cpp
allow building wxXRC with wxUSE_HTML=0: make linking work in absence of wxHTML library
[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 SetInitialSize(size);
119
120 return true;
121 }
122
123 wxSize 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
131 wxSize best(w, h);
132 CacheBestSize(best);
133 return best;
134 }
135
136
137 void wxHyperlinkCtrl::SetNormalColour(const wxColour &colour)
138 {
139 m_normalColour = colour;
140 if (!m_visited)
141 {
142 SetForegroundColour(m_normalColour);
143 Refresh();
144 }
145 }
146
147 void wxHyperlinkCtrl::SetVisitedColour(const wxColour &colour)
148 {
149 m_visitedColour = colour;
150 if (m_visited)
151 {
152 SetForegroundColour(m_visitedColour);
153 Refresh();
154 }
155 }
156
157 void 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
165 wxRect 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
183
184
185 // ----------------------------------------------------------------------------
186 // wxHyperlinkCtrl - event handlers
187 // ----------------------------------------------------------------------------
188
189 void wxHyperlinkCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
190 {
191 wxPaintDC dc(this);
192 dc.SetFont(GetFont());
193 dc.SetTextForeground(GetForegroundColour());
194 dc.SetTextBackground(GetBackgroundColour());
195
196 dc.DrawText(GetLabel(), GetLabelRect().GetTopLeft());
197 }
198
199 void wxHyperlinkCtrl::OnLeftDown(wxMouseEvent& event)
200 {
201 // the left click must start from the hyperlink rect
202 m_clicking = GetLabelRect().Contains(event.GetPosition());
203 }
204
205 void wxHyperlinkCtrl::OnLeftUp(wxMouseEvent& event)
206 {
207 // the click must be started and ended in the hyperlink rect
208 if (!m_clicking || !GetLabelRect().Contains(event.GetPosition()))
209 return;
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
222 void wxHyperlinkCtrl::OnRightUp(wxMouseEvent& event)
223 {
224 if( GetWindowStyle() & wxHL_CONTEXTMENU )
225 if ( GetLabelRect().Contains(event.GetPosition()) )
226 DoContextMenu(wxPoint(event.m_x, event.m_y));
227 }
228
229 void wxHyperlinkCtrl::OnMotion(wxMouseEvent& event)
230 {
231 wxRect textrc = GetLabelRect();
232
233 if (textrc.Contains(event.GetPosition()))
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 }
247 }
248
249 void wxHyperlinkCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event) )
250 {
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
256 if (m_rollover)
257 {
258 SetCursor(*wxSTANDARD_CURSOR);
259 SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour);
260 m_rollover = false;
261 Refresh();
262 }
263 }
264
265 void wxHyperlinkCtrl::OnPopUpCopy( wxCommandEvent& WXUNUSED(event) )
266 {
267 #if wxUSE_CLIPBOARD
268 if (!wxTheClipboard->Open())
269 return;
270
271 wxTextDataObject *data = new wxTextDataObject( m_url );
272 wxTheClipboard->SetData( data );
273 wxTheClipboard->Close();
274 #endif // wxUSE_CLIPBOARD
275 }
276
277 void 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
284 #endif // wxUSE_HYPERLINKCTRL