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