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