1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/univ/button.cpp 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2000 SciTech Software, Inc. (www.scitechsoft.com) 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #include "wx/wxprec.h" 
  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" 
  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" 
  42 // ---------------------------------------------------------------------------- 
  43 // wxStdButtonInputHandler: translates SPACE and ENTER keys and the left mouse 
  44 // click into button press/release actions 
  45 // ---------------------------------------------------------------------------- 
  47 class WXDLLEXPORT wxStdButtonInputHandler 
: public wxStdInputHandler
 
  50     wxStdButtonInputHandler(wxInputHandler 
*inphand
); 
  52     virtual bool HandleKey(wxInputConsumer 
*consumer
, 
  53                            const wxKeyEvent
& event
, 
  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
); 
  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
; 
  70 // ---------------------------------------------------------------------------- 
  72 // ---------------------------------------------------------------------------- 
  74 // default margins around the image 
  75 static const wxCoord DEFAULT_BTN_MARGIN_X 
= 0;  // We should give space for the border, at least. 
  76 static const wxCoord DEFAULT_BTN_MARGIN_Y 
= 0; 
  78 // ============================================================================ 
  80 // ============================================================================ 
  82 // ---------------------------------------------------------------------------- 
  84 // ---------------------------------------------------------------------------- 
  92 bool wxButton::Create(wxWindow 
*parent
, 
  94                       const wxBitmap
& bitmap
, 
  99                       const wxValidator
& validator
, 
 100                       const wxString 
&name
) 
 103     if (label
.empty() && wxIsStockID(id
)) 
 104         label 
= wxGetStockLabel(id
); 
 106     long ctrl_style 
= style 
& ~wxBU_ALIGN_MASK
; 
 107     ctrl_style 
= ctrl_style 
& ~wxALIGN_MASK
; 
 109     if((style 
& wxBU_RIGHT
) == wxBU_RIGHT
) 
 110         ctrl_style 
|= wxALIGN_RIGHT
; 
 111     else if((style 
& wxBU_LEFT
) == wxBU_LEFT
) 
 112         ctrl_style 
|= wxALIGN_LEFT
; 
 114         ctrl_style 
|= wxALIGN_CENTRE_HORIZONTAL
; 
 116     if((style 
& wxBU_TOP
) == wxBU_TOP
) 
 117         ctrl_style 
|= wxALIGN_TOP
; 
 118     else if((style 
& wxBU_BOTTOM
) == wxBU_BOTTOM
) 
 119         ctrl_style 
|= wxALIGN_BOTTOM
; 
 121         ctrl_style 
|= wxALIGN_CENTRE_VERTICAL
; 
 123     if ( !wxControl::Create(parent
, id
, pos
, size
, ctrl_style
, validator
, name
) ) 
 129         SetBitmap(bitmap
); // SetInitialSize called by SetBitmap() 
 131         SetInitialSize(size
); 
 133     CreateInputHandler(wxINP_HANDLER_BUTTON
); 
 138 wxButton::~wxButton() 
 142 // ---------------------------------------------------------------------------- 
 144 // ---------------------------------------------------------------------------- 
 147 wxSize 
wxButtonBase::GetDefaultSize() 
 149     static wxSize s_sizeBtn
; 
 151     if ( s_sizeBtn
.x 
== 0 ) 
 155         // this corresponds more or less to wxMSW standard in Win32 theme (see 
 156         // wxWin32Renderer::AdjustSize()) 
 157 //        s_sizeBtn.x = 8*dc.GetCharWidth(); 
 158 //        s_sizeBtn.y = (11*dc.GetCharHeight())/10 + 2; 
 159         // Otto Wyss, Patch 664399 
 160         s_sizeBtn
.x 
= dc
.GetCharWidth()*10 + 2; 
 161         s_sizeBtn
.y 
= dc
.GetCharHeight()*11/10 + 2; 
 167 wxSize 
wxButton::DoGetBestClientSize() const 
 169     wxClientDC 
dc(wxConstCast(this, wxButton
)); 
 170     wxCoord width
, height
; 
 171     dc
.GetMultiLineTextExtent(GetLabel(), &width
, &height
); 
 173     if ( m_bitmap
.IsOk() ) 
 175         // allocate extra space for the bitmap 
 176         wxCoord heightBmp 
= m_bitmap
.GetHeight() + 2*m_marginBmpY
; 
 177         if ( height 
< heightBmp 
) 
 180         width 
+= m_bitmap
.GetWidth() + 2*m_marginBmpX
; 
 183     // The default size should not be adjusted, so the code is moved into the 
 184     // renderer. This is conceptual wrong but currently the only solution. 
 185     // (Otto Wyss, Patch 664399) 
 188     // for compatibility with other ports, the buttons default size is never 
 189     // less than the standard one, but not when display not PDAs. 
 190     if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA) 
 192         if ( !(GetWindowStyle() & wxBU_EXACTFIT) ) 
 194             wxSize szDef = GetDefaultSize(); 
 195             if ( width < szDef.x ) 
 200     return wxSize(width
, height
); 
 203 // ---------------------------------------------------------------------------- 
 205 // ---------------------------------------------------------------------------- 
 207 void wxButton::DoDraw(wxControlRenderer 
*renderer
) 
 209     if ( !(GetWindowStyle() & wxBORDER_NONE
) ) 
 211         renderer
->DrawButtonBorder(); 
 214     renderer
->DrawButtonLabel(m_bitmap
, m_marginBmpX
, m_marginBmpY
); 
 217 bool wxButton::DoDrawBackground(wxDC
& dc
) 
 220     wxSize size 
= GetSize(); 
 222     rect
.height 
= size
.y
; 
 224     if ( GetBackgroundBitmap().IsOk() ) 
 226         // get the bitmap and the flags 
 229         wxBitmap bmp 
= GetBackgroundBitmap(&alignment
, &stretch
); 
 230         wxControlRenderer::DrawBitmap(dc
, bmp
, rect
, alignment
, stretch
); 
 234         m_renderer
->DrawButtonSurface(dc
, wxTHEME_BG_COLOUR(this), 
 235                                       rect
, GetStateFlags()); 
 241 // ---------------------------------------------------------------------------- 
 243 // ---------------------------------------------------------------------------- 
 245 void wxButton::Press() 
 255 void wxButton::Release() 
 265 void wxButton::Toggle() 
 274         // releasing button after it had been pressed generates a click event 
 279 void wxButton::Click() 
 281     wxCommandEvent 
event(wxEVT_BUTTON
, GetId()); 
 282     InitCommandEvent(event
); 
 286 bool wxButton::PerformAction(const wxControlAction
& action
, 
 288                              const wxString
& strArg
) 
 290     if ( action 
== wxACTION_BUTTON_TOGGLE 
) 
 292     else if ( action 
== wxACTION_BUTTON_CLICK 
) 
 294     else if ( action 
== wxACTION_BUTTON_PRESS 
) 
 296     else if ( action 
== wxACTION_BUTTON_RELEASE 
) 
 299         return wxControl::PerformAction(action
, numArg
, strArg
); 
 305 wxInputHandler 
*wxButton::GetStdInputHandler(wxInputHandler 
*handlerDef
) 
 307     static wxStdButtonInputHandler 
s_handlerBtn(handlerDef
); 
 309     return &s_handlerBtn
; 
 312 // ---------------------------------------------------------------------------- 
 314 // ---------------------------------------------------------------------------- 
 316 void wxButton::DoSetBitmap(const wxBitmap
& bitmap
, State which
) 
 318     // we support only one bitmap right now, although this wouldn't be 
 319     // difficult to change 
 320     if ( which 
== State_Normal 
) 
 323     SetBitmapMargins(DEFAULT_BTN_MARGIN_X
, DEFAULT_BTN_MARGIN_Y
); 
 326 void wxButton::DoSetBitmapMargins(wxCoord x
, wxCoord y
) 
 328     m_marginBmpX 
= x 
+ 2; 
 329     m_marginBmpY 
= y 
+ 2; 
 331     SetInitialSize(wxDefaultSize
); 
 334 wxWindow 
*wxButton::SetDefault() 
 338     return wxButtonBase::SetDefault(); 
 341 // ============================================================================ 
 342 // wxStdButtonInputHandler 
 343 // ============================================================================ 
 345 wxStdButtonInputHandler::wxStdButtonInputHandler(wxInputHandler 
*handler
) 
 346                        : wxStdInputHandler(handler
) 
 349     m_winHasMouse 
= false; 
 352 bool wxStdButtonInputHandler::HandleKey(wxInputConsumer 
*consumer
, 
 353                                         const wxKeyEvent
& event
, 
 356     int keycode 
= event
.GetKeyCode(); 
 357     if ( keycode 
== WXK_SPACE 
|| keycode 
== WXK_RETURN 
) 
 359         consumer
->PerformAction(wxACTION_BUTTON_TOGGLE
); 
 364     return wxStdInputHandler::HandleKey(consumer
, event
, pressed
); 
 367 bool wxStdButtonInputHandler::HandleMouse(wxInputConsumer 
*consumer
, 
 368                                           const wxMouseEvent
& event
) 
 370     // the button has 2 states: pressed and normal with the following 
 371     // transitions between them: 
 373     //      normal -> left down -> capture mouse and go to pressed state 
 374     //      pressed -> left up inside -> generate click -> go to normal 
 375     //                         outside ------------------> 
 377     // the other mouse buttons are ignored 
 378     if ( event
.Button(1) ) 
 380         if ( event
.LeftDown() || event
.LeftDClick() ) 
 382             m_winCapture 
= consumer
->GetInputWindow(); 
 383             m_winCapture
->CaptureMouse(); 
 384             m_winHasMouse 
= true; 
 386             consumer
->PerformAction(wxACTION_BUTTON_PRESS
); 
 390         else if ( event
.LeftUp() ) 
 394                 m_winCapture
->ReleaseMouse(); 
 400                 // this will generate a click event 
 401                 consumer
->PerformAction(wxACTION_BUTTON_TOGGLE
); 
 405             //else: the mouse was released outside the window, this doesn't 
 408         //else: don't do anything special about the double click 
 411     return wxStdInputHandler::HandleMouse(consumer
, event
); 
 414 bool wxStdButtonInputHandler::HandleMouseMove(wxInputConsumer 
*consumer
, 
 415                                               const wxMouseEvent
& event
) 
 417     // we only have to do something when the mouse leaves/enters the pressed 
 418     // button and don't care about the other ones 
 419     if ( event
.GetEventObject() == m_winCapture 
) 
 421         // leaving the button should remove its pressed state 
 422         if ( event
.Leaving() ) 
 424             // remember that the mouse is now outside 
 425             m_winHasMouse 
= false; 
 427             // we do have a pressed button, so release it 
 428             consumer
->GetInputWindow()->SetCurrent(false); 
 429             consumer
->PerformAction(wxACTION_BUTTON_RELEASE
); 
 433         // and entering it back should make it pressed again if it had been 
 435         else if ( event
.Entering() ) 
 437             // the mouse is (back) inside the button 
 438             m_winHasMouse 
= true; 
 440             // we did have a pressed button which we released when leaving the 
 441             // window, press it again 
 442             consumer
->GetInputWindow()->SetCurrent(true); 
 443             consumer
->PerformAction(wxACTION_BUTTON_PRESS
); 
 449     return wxStdInputHandler::HandleMouseMove(consumer
, event
); 
 452 bool wxStdButtonInputHandler::HandleFocus(wxInputConsumer 
* WXUNUSED(consumer
), 
 453                                           const wxFocusEvent
& WXUNUSED(event
)) 
 455     // buttons change appearance when they get/lose focus, so return true to 
 460 bool wxStdButtonInputHandler::HandleActivation(wxInputConsumer 
*consumer
, 
 461                                                bool WXUNUSED(activated
)) 
 463     // the default button changes appearance when the app is [de]activated, so 
 464     // return true to refresh 
 465     return wxStaticCast(consumer
->GetInputWindow(), wxButton
)->IsDefault(); 
 468 #endif // wxUSE_BUTTON