]> git.saurik.com Git - wxWidgets.git/blob - src/univ/button.cpp
a6438e0d51c83d0131dff8925f3483cebf0b01de
[wxWidgets.git] / src / univ / button.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: univ/button.cpp
3 // Purpose: wxButton
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 14.08.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "univbutton.h"
22 #endif
23
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #if wxUSE_BUTTON
31
32 #ifndef WX_PRECOMP
33 #include "wx/dcclient.h"
34 #include "wx/dcscreen.h"
35 #include "wx/button.h"
36 #include "wx/validate.h"
37 #endif
38
39 #include "wx/univ/renderer.h"
40 #include "wx/univ/inphand.h"
41 #include "wx/univ/theme.h"
42
43 // ----------------------------------------------------------------------------
44 // constants
45 // ----------------------------------------------------------------------------
46
47 // default margins around the image
48 static const wxCoord DEFAULT_BTN_MARGIN_X = 0;
49 static const wxCoord DEFAULT_BTN_MARGIN_Y = 0;
50
51 // ============================================================================
52 // implementation
53 // ============================================================================
54
55 IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl)
56
57 // ----------------------------------------------------------------------------
58 // creation
59 // ----------------------------------------------------------------------------
60
61 void wxButton::Init()
62 {
63 m_isPressed =
64 m_isDefault = FALSE;
65 }
66
67 bool wxButton::Create(wxWindow *parent,
68 wxWindowID id,
69 const wxBitmap& bitmap,
70 const wxString &label,
71 const wxPoint &pos,
72 const wxSize &size,
73 long style,
74 const wxValidator& validator,
75 const wxString &name)
76 {
77 // center label by default
78 if ( !(style & wxALIGN_MASK) )
79 {
80 style |= wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL;
81 }
82
83 if ( !wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name) )
84 return FALSE;
85
86 SetLabel(label);
87 SetImageLabel(bitmap);
88 // SetBestSize(size); -- called by SetImageLabel()
89
90 CreateInputHandler(wxINP_HANDLER_BUTTON);
91
92 return TRUE;
93 }
94
95 wxButton::~wxButton()
96 {
97 }
98
99 // ----------------------------------------------------------------------------
100 // size management
101 // ----------------------------------------------------------------------------
102
103 /* static */
104 wxSize wxButtonBase::GetDefaultSize()
105 {
106 static wxSize s_sizeBtn;
107
108 if ( s_sizeBtn.x == 0 )
109 {
110 wxScreenDC dc;
111
112 // this corresponds more or less to wxMSW standard in Win32 theme (see
113 // wxWin32Renderer::AdjustSize())
114 s_sizeBtn.x = 8*dc.GetCharWidth();
115 s_sizeBtn.y = (11*dc.GetCharHeight())/10 + 2;
116 }
117
118 return s_sizeBtn;
119 }
120
121 wxSize wxButton::DoGetBestClientSize() const
122 {
123 wxClientDC dc(wxConstCast(this, wxButton));
124 wxCoord width, height;
125 dc.GetMultiLineTextExtent(GetLabel(), &width, &height);
126
127 if ( m_bitmap.Ok() )
128 {
129 // allocate extra space for the bitmap
130 wxCoord heightBmp = m_bitmap.GetHeight() + 2*m_marginBmpY;
131 if ( height < heightBmp )
132 height = heightBmp;
133
134 width += m_bitmap.GetWidth() + 2*m_marginBmpX;
135 }
136
137 // for compatibility with other ports, the buttons default size is never
138 // less than the standard one
139 if ( !(GetWindowStyle() & wxBU_EXACTFIT) )
140 {
141 wxSize szDef = GetDefaultSize();
142 if ( width < szDef.x )
143 width = szDef.x;
144 }
145
146 return wxSize(width, height);
147 }
148
149 // ----------------------------------------------------------------------------
150 // drawing
151 // ----------------------------------------------------------------------------
152
153 void wxButton::DoDraw(wxControlRenderer *renderer)
154 {
155 renderer->DrawButtonBorder();
156 renderer->DrawLabel(m_bitmap, m_marginBmpX, m_marginBmpY);
157 }
158
159 // ----------------------------------------------------------------------------
160 // input processing
161 // ----------------------------------------------------------------------------
162
163 void wxButton::Press()
164 {
165 if ( !m_isPressed )
166 {
167 m_isPressed = TRUE;
168
169 Refresh();
170 }
171 }
172
173 void wxButton::Release()
174 {
175 if ( m_isPressed )
176 {
177 m_isPressed = FALSE;
178
179 Refresh();
180 }
181 }
182
183 void wxButton::Toggle()
184 {
185 if ( m_isPressed )
186 Release();
187 else
188 Press();
189
190 if ( !m_isPressed )
191 {
192 // releasing button after it had been pressed generates a click event
193 Click();
194 }
195 }
196
197 void wxButton::Click()
198 {
199 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
200 InitCommandEvent(event);
201 Command(event);
202 }
203
204 bool wxButton::PerformAction(const wxControlAction& action,
205 long numArg,
206 const wxString& strArg)
207 {
208 if ( action == wxACTION_BUTTON_TOGGLE )
209 Toggle();
210 else if ( action == wxACTION_BUTTON_CLICK )
211 Click();
212 else if ( action == wxACTION_BUTTON_PRESS )
213 Press();
214 else if ( action == wxACTION_BUTTON_RELEASE )
215 Release();
216 else
217 return wxControl::PerformAction(action, numArg, strArg);
218
219 return TRUE;
220 }
221
222 // ----------------------------------------------------------------------------
223 // misc
224 // ----------------------------------------------------------------------------
225
226 void wxButton::SetImageLabel(const wxBitmap& bitmap)
227 {
228 m_bitmap = bitmap;
229
230 SetImageMargins(DEFAULT_BTN_MARGIN_X, DEFAULT_BTN_MARGIN_Y);
231 }
232
233 void wxButton::SetImageMargins(wxCoord x, wxCoord y)
234 {
235 m_marginBmpX = x;
236 m_marginBmpY = y;
237
238 SetBestSize(wxDefaultSize);
239 }
240
241 void wxButton::SetDefault()
242 {
243 m_isDefault = TRUE;
244 }
245
246 // ============================================================================
247 // wxStdButtonInputHandler
248 // ============================================================================
249
250 wxStdButtonInputHandler::wxStdButtonInputHandler(wxInputHandler *handler)
251 : wxStdInputHandler(handler)
252 {
253 m_winCapture = NULL;
254 m_winHasMouse = FALSE;
255 }
256
257 bool wxStdButtonInputHandler::HandleKey(wxControl *control,
258 const wxKeyEvent& event,
259 bool pressed)
260 {
261 int keycode = event.GetKeyCode();
262 if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
263 {
264 control->PerformAction(wxACTION_BUTTON_TOGGLE);
265
266 return TRUE;
267 }
268
269 return wxStdInputHandler::HandleKey(control, event, pressed);
270 }
271
272 bool wxStdButtonInputHandler::HandleMouse(wxControl *control,
273 const wxMouseEvent& event)
274 {
275 // the button has 2 states: pressed and normal with the following
276 // transitions between them:
277 //
278 // normal -> left down -> capture mouse and go to pressed state
279 // pressed -> left up inside -> generate click -> go to normal
280 // outside ------------------>
281 //
282 // the other mouse buttons are ignored
283 if ( event.Button(1) )
284 {
285 if ( event.ButtonDown(1) )
286 {
287 m_winCapture = control;
288 m_winCapture->CaptureMouse();
289 m_winHasMouse = TRUE;
290
291 control->PerformAction(wxACTION_BUTTON_PRESS);
292
293 return TRUE;
294 }
295 else // up
296 {
297 if ( m_winCapture )
298 {
299 m_winCapture->ReleaseMouse();
300 m_winCapture = NULL;
301 }
302
303 if ( m_winHasMouse )
304 {
305 // this will generate a click event
306 control->PerformAction(wxACTION_BUTTON_TOGGLE);
307
308 return TRUE;
309 }
310 //else: the mouse was released outside the window, this doesn't
311 // count as a click
312 }
313 }
314
315 return wxStdInputHandler::HandleMouse(control, event);
316 }
317
318 bool wxStdButtonInputHandler::HandleMouseMove(wxControl *control,
319 const wxMouseEvent& event)
320 {
321 // we only have to do something when the mouse leaves/enters the pressed
322 // button and don't care about the other ones
323 if ( event.GetEventObject() == m_winCapture )
324 {
325 // leaving the button should remove its pressed state
326 if ( event.Leaving() )
327 {
328 // remember that the mouse is now outside
329 m_winHasMouse = FALSE;
330
331 // we do have a pressed button, so release it
332 control->SetCurrent(FALSE);
333 control->PerformAction(wxACTION_BUTTON_RELEASE);
334
335 return TRUE;
336 }
337 // and entering it back should make it pressed again if it had been
338 // pressed
339 else if ( event.Entering() )
340 {
341 // the mouse is (back) inside the button
342 m_winHasMouse = TRUE;
343
344 // we did have a pressed button which we released when leaving the
345 // window, press it again
346 control->SetCurrent(TRUE);
347 control->PerformAction(wxACTION_BUTTON_PRESS);
348
349 return TRUE;
350 }
351 }
352
353 return wxStdInputHandler::HandleMouseMove(control, event);
354 }
355
356 bool wxStdButtonInputHandler::HandleFocus(wxControl *control,
357 const wxFocusEvent& event)
358 {
359 // buttons change appearance when they get/lose focus, so return TRUE to
360 // refresh
361 return TRUE;
362 }
363
364 bool wxStdButtonInputHandler::HandleActivation(wxControl *control,
365 bool activated)
366 {
367 // the default button changes appearance when the app is [de]activated, so
368 // return TRUE to refresh
369 return wxStaticCast(control, wxButton)->IsDefault();
370 }
371
372 #endif // wxUSE_BUTTON
373