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