]> git.saurik.com Git - wxWidgets.git/blob - src/univ/button.cpp
improved memory liberation (explicitly set to NULL after delete)
[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 #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 void wxButton::Init()
64 {
65 m_isPressed =
66 m_isDefault = FALSE;
67 }
68
69 bool 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
97 wxButton::~wxButton()
98 {
99 }
100
101 // ----------------------------------------------------------------------------
102 // size management
103 // ----------------------------------------------------------------------------
104
105 /* static */
106 wxSize 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
123 wxSize 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
140 // less than the standard one, but not when display not PDAs.
141 if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA)
142 {
143 if ( !(GetWindowStyle() & wxBU_EXACTFIT) )
144 {
145 wxSize szDef = GetDefaultSize();
146 if ( width < szDef.x )
147 width = szDef.x;
148 }
149 }
150
151 return wxSize(width, height);
152 }
153
154 // ----------------------------------------------------------------------------
155 // drawing
156 // ----------------------------------------------------------------------------
157
158 void wxButton::DoDraw(wxControlRenderer *renderer)
159 {
160 if ( !(GetWindowStyle() & wxBORDER_NONE) )
161 {
162 renderer->DrawButtonBorder();
163 }
164
165 renderer->DrawLabel(m_bitmap, m_marginBmpX, m_marginBmpY);
166 }
167
168 bool 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
192 // ----------------------------------------------------------------------------
193 // input processing
194 // ----------------------------------------------------------------------------
195
196 void wxButton::Press()
197 {
198 if ( !m_isPressed )
199 {
200 m_isPressed = TRUE;
201
202 Refresh();
203 }
204 }
205
206 void wxButton::Release()
207 {
208 if ( m_isPressed )
209 {
210 m_isPressed = FALSE;
211
212 Refresh();
213 }
214 }
215
216 void 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
230 void wxButton::Click()
231 {
232 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
233 InitCommandEvent(event);
234 Command(event);
235 }
236
237 bool 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
259 void wxButton::SetImageLabel(const wxBitmap& bitmap)
260 {
261 m_bitmap = bitmap;
262
263 SetImageMargins(DEFAULT_BTN_MARGIN_X, DEFAULT_BTN_MARGIN_Y);
264 }
265
266 void wxButton::SetImageMargins(wxCoord x, wxCoord y)
267 {
268 m_marginBmpX = x + 2;
269 m_marginBmpY = y + 2;
270
271 SetBestSize(wxDefaultSize);
272 }
273
274 void wxButton::SetDefault()
275 {
276 m_isDefault = TRUE;
277 }
278
279 // ============================================================================
280 // wxStdButtonInputHandler
281 // ============================================================================
282
283 wxStdButtonInputHandler::wxStdButtonInputHandler(wxInputHandler *handler)
284 : wxStdInputHandler(handler)
285 {
286 m_winCapture = NULL;
287 m_winHasMouse = FALSE;
288 }
289
290 bool wxStdButtonInputHandler::HandleKey(wxInputConsumer *consumer,
291 const wxKeyEvent& event,
292 bool pressed)
293 {
294 int keycode = event.GetKeyCode();
295 if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
296 {
297 consumer->PerformAction(wxACTION_BUTTON_TOGGLE);
298
299 return TRUE;
300 }
301
302 return wxStdInputHandler::HandleKey(consumer, event, pressed);
303 }
304
305 bool wxStdButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
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 {
318 if ( event.LeftDown() || event.LeftDClick() )
319 {
320 m_winCapture = consumer->GetInputWindow();
321 m_winCapture->CaptureMouse();
322 m_winHasMouse = TRUE;
323
324 consumer->PerformAction(wxACTION_BUTTON_PRESS);
325
326 return TRUE;
327 }
328 else if ( event.LeftUp() )
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
339 consumer->PerformAction(wxACTION_BUTTON_TOGGLE);
340
341 return TRUE;
342 }
343 //else: the mouse was released outside the window, this doesn't
344 // count as a click
345 }
346 //else: don't do anything special about the double click
347 }
348
349 return wxStdInputHandler::HandleMouse(consumer, event);
350 }
351
352 bool wxStdButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
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
366 consumer->GetInputWindow()->SetCurrent(FALSE);
367 consumer->PerformAction(wxACTION_BUTTON_RELEASE);
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
380 consumer->GetInputWindow()->SetCurrent(TRUE);
381 consumer->PerformAction(wxACTION_BUTTON_PRESS);
382
383 return TRUE;
384 }
385 }
386
387 return wxStdInputHandler::HandleMouseMove(consumer, event);
388 }
389
390 bool wxStdButtonInputHandler::HandleFocus(wxInputConsumer *consumer,
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
398 bool wxStdButtonInputHandler::HandleActivation(wxInputConsumer *consumer,
399 bool activated)
400 {
401 // the default button changes appearance when the app is [de]activated, so
402 // return TRUE to refresh
403 return wxStaticCast(consumer->GetInputWindow(), wxButton)->IsDefault();
404 }
405
406 #endif // wxUSE_BUTTON
407