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