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