]> git.saurik.com Git - wxWidgets.git/blame - src/univ/button.cpp
Include missing.h to find O_* flags.
[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)
65571936 9// Licence: wxWindows licence
1e6feb95
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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"
5f7bcb48 44#include "wx/stockitem.h"
1e6feb95
VZ
45
46// ----------------------------------------------------------------------------
47// constants
48// ----------------------------------------------------------------------------
49
50// default margins around the image
ea1ad04b 51static const wxCoord DEFAULT_BTN_MARGIN_X = 0; // We should give space for the border, at least.
1e6feb95
VZ
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 =
a290fa5a 67 m_isDefault = false;
1e6feb95
VZ
68}
69
70bool wxButton::Create(wxWindow *parent,
71 wxWindowID id,
72 const wxBitmap& bitmap,
5f7bcb48 73 const wxString &lbl,
1e6feb95
VZ
74 const wxPoint &pos,
75 const wxSize &size,
76 long style,
77 const wxValidator& validator,
78 const wxString &name)
79{
5f7bcb48
VS
80 wxString label(lbl);
81 if (label.empty() && wxIsStockID(id))
82 label = wxGetStockLabel(id);
83
1e6feb95
VZ
84 // center label by default
85 if ( !(style & wxALIGN_MASK) )
86 {
87 style |= wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL;
88 }
89
61fef19b 90 if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
a290fa5a 91 return false;
1e6feb95
VZ
92
93 SetLabel(label);
94 SetImageLabel(bitmap);
95 // SetBestSize(size); -- called by SetImageLabel()
96
97 CreateInputHandler(wxINP_HANDLER_BUTTON);
98
a290fa5a 99 return true;
1e6feb95
VZ
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())
61a83c1c
JS
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;
1e6feb95
VZ
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
61a83c1c
JS
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/*
1e6feb95 152 // for compatibility with other ports, the buttons default size is never
c15521c6 153 // less than the standard one, but not when display not PDAs.
41fecb44 154 if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA)
7ef8bfc4 155 {
c15521c6
RR
156 if ( !(GetWindowStyle() & wxBU_EXACTFIT) )
157 {
158 wxSize szDef = GetDefaultSize();
159 if ( width < szDef.x )
160 width = szDef.x;
161 }
7ef8bfc4 162 }
61a83c1c 163*/
1e6feb95
VZ
164 return wxSize(width, height);
165}
166
167// ----------------------------------------------------------------------------
168// drawing
169// ----------------------------------------------------------------------------
170
171void wxButton::DoDraw(wxControlRenderer *renderer)
172{
e4606ed9
VZ
173 if ( !(GetWindowStyle() & wxBORDER_NONE) )
174 {
175 renderer->DrawButtonBorder();
176 }
177
1e6feb95
VZ
178 renderer->DrawLabel(m_bitmap, m_marginBmpX, m_marginBmpY);
179}
180
193e19cf
RR
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
a290fa5a 202 return true;
193e19cf
RR
203}
204
1e6feb95
VZ
205// ----------------------------------------------------------------------------
206// input processing
207// ----------------------------------------------------------------------------
208
209void wxButton::Press()
210{
211 if ( !m_isPressed )
212 {
a290fa5a 213 m_isPressed = true;
1e6feb95
VZ
214
215 Refresh();
216 }
217}
218
219void wxButton::Release()
220{
221 if ( m_isPressed )
222 {
a290fa5a 223 m_isPressed = false;
1e6feb95
VZ
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
a290fa5a 265 return true;
1e6feb95
VZ
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{
34d26f42
RR
281 m_marginBmpX = x + 2;
282 m_marginBmpY = y + 2;
283
1e6feb95
VZ
284 SetBestSize(wxDefaultSize);
285}
286
287void wxButton::SetDefault()
288{
a290fa5a 289 m_isDefault = true;
1e6feb95
VZ
290}
291
292// ============================================================================
293// wxStdButtonInputHandler
294// ============================================================================
295
296wxStdButtonInputHandler::wxStdButtonInputHandler(wxInputHandler *handler)
297 : wxStdInputHandler(handler)
298{
299 m_winCapture = NULL;
a290fa5a 300 m_winHasMouse = false;
1e6feb95
VZ
301}
302
23645bfa 303bool wxStdButtonInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
304 const wxKeyEvent& event,
305 bool pressed)
306{
307 int keycode = event.GetKeyCode();
308 if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
309 {
23645bfa 310 consumer->PerformAction(wxACTION_BUTTON_TOGGLE);
1e6feb95 311
a290fa5a 312 return true;
1e6feb95
VZ
313 }
314
23645bfa 315 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
316}
317
23645bfa 318bool wxStdButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
1e6feb95
VZ
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 {
96e3c3d4 331 if ( event.LeftDown() || event.LeftDClick() )
1e6feb95 332 {
23645bfa 333 m_winCapture = consumer->GetInputWindow();
1e6feb95 334 m_winCapture->CaptureMouse();
a290fa5a 335 m_winHasMouse = true;
1e6feb95 336
23645bfa 337 consumer->PerformAction(wxACTION_BUTTON_PRESS);
1e6feb95 338
a290fa5a 339 return true;
1e6feb95 340 }
96e3c3d4 341 else if ( event.LeftUp() )
1e6feb95
VZ
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
23645bfa 352 consumer->PerformAction(wxACTION_BUTTON_TOGGLE);
1e6feb95 353
a290fa5a 354 return true;
1e6feb95
VZ
355 }
356 //else: the mouse was released outside the window, this doesn't
357 // count as a click
358 }
96e3c3d4 359 //else: don't do anything special about the double click
1e6feb95
VZ
360 }
361
23645bfa 362 return wxStdInputHandler::HandleMouse(consumer, event);
1e6feb95
VZ
363}
364
23645bfa 365bool wxStdButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1e6feb95
VZ
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
a290fa5a 376 m_winHasMouse = false;
1e6feb95
VZ
377
378 // we do have a pressed button, so release it
a290fa5a 379 consumer->GetInputWindow()->SetCurrent(false);
23645bfa 380 consumer->PerformAction(wxACTION_BUTTON_RELEASE);
1e6feb95 381
a290fa5a 382 return true;
1e6feb95
VZ
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
a290fa5a 389 m_winHasMouse = true;
1e6feb95
VZ
390
391 // we did have a pressed button which we released when leaving the
392 // window, press it again
a290fa5a 393 consumer->GetInputWindow()->SetCurrent(true);
23645bfa 394 consumer->PerformAction(wxACTION_BUTTON_PRESS);
1e6feb95 395
a290fa5a 396 return true;
1e6feb95
VZ
397 }
398 }
399
23645bfa 400 return wxStdInputHandler::HandleMouseMove(consumer, event);
1e6feb95
VZ
401}
402
61fef19b
VZ
403bool wxStdButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
404 const wxFocusEvent& WXUNUSED(event))
1e6feb95 405{
a290fa5a 406 // buttons change appearance when they get/lose focus, so return true to
1e6feb95 407 // refresh
a290fa5a 408 return true;
1e6feb95
VZ
409}
410
23645bfa 411bool wxStdButtonInputHandler::HandleActivation(wxInputConsumer *consumer,
61fef19b 412 bool WXUNUSED(activated))
1e6feb95
VZ
413{
414 // the default button changes appearance when the app is [de]activated, so
a290fa5a 415 // return true to refresh
23645bfa 416 return wxStaticCast(consumer->GetInputWindow(), wxButton)->IsDefault();
1e6feb95
VZ
417}
418
419#endif // wxUSE_BUTTON
420