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