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