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