1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      David Webster 
   8 // Copyright:   (c) David Webster 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  17     #include "wx/button.h" 
  20     #include "wx/bmpbuttn.h" 
  21     #include "wx/settings.h" 
  22     #include "wx/dcscreen.h" 
  23     #include "wx/scrolwin.h" 
  26 #include "wx/stockitem.h" 
  27 #include "wx/os2/private.h" 
  29 #define BUTTON_HEIGHT_FROM_CHAR_HEIGHT(cy) (11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)/10) 
  32 // Should be at the very least less than winDEFAULT_BUTTON_MARGIN 
  34 #define FOCUS_MARGIN 3 
  37 #define BST_CHECKED 0x0001 
  40 IMPLEMENT_DYNAMIC_CLASS(wxButton
, wxControl
) 
  44 bool wxButton::Create( 
  47 , const wxString
&                   rsLbl
 
  51 , const wxValidator
&                rValidator
 
  52 , const wxString
&                   rsName
 
  55     wxString 
rsLabel(rsLbl
); 
  56     if (rsLabel
.empty() && wxIsStockID(vId
)) 
  57         rsLabel 
= wxGetStockLabel(vId
); 
  59     wxString                        sLabel 
= ::wxPMTextToLabel(rsLabel
); 
  63     SetValidator(rValidator
); 
  65     m_windowStyle 
= lStyle
; 
  66     pParent
->AddChild((wxButton 
*)this); 
  68         m_windowId 
= NewControlId(); 
  71     lStyle 
= WS_VISIBLE 
| WS_TABSTOP 
| BS_PUSHBUTTON
; 
  74     // OS/2 PM does not have Right/Left/Top/Bottom styles. 
  75     // We will have to define an additional style when we implement notebooks 
  76     // for a notebook page button 
  78     if (m_windowStyle 
& wxCLIP_SIBLINGS 
) 
  79         lStyle 
|= WS_CLIPSIBLINGS
; 
  81     m_hWnd 
= (WXHWND
)::WinCreateWindow( GetHwndOf(pParent
)   // Parent handle 
  82                                        ,WC_BUTTON            
// A Button class window 
  83                                        ,(PSZ
)sLabel
.c_str()  // Button text 
  84                                        ,lStyle               
// Button style 
  85                                        ,0, 0, 0, 0           // Location and size 
  86                                        ,GetHwndOf(pParent
)   // Owner handle 
  87                                        ,HWND_TOP             
// Top of Z-Order 
  89                                        ,NULL                 
// No control data 
  90                                        ,NULL                 
// No Presentation parameters 
  98     // Subclass again for purposes of dialog editing mode 
 101     wxFont
*                          pButtonFont 
= new wxFont( 8 
 106     SetFont(*pButtonFont
); 
 116 } // end of wxButton::Create 
 118 wxButton::~wxButton() 
 120     wxPanel
*                        pPanel 
= wxDynamicCast(GetParent(), wxPanel
); 
 124         if (pPanel
->GetDefaultItem() == this) 
 127             // Don't leave the panel with invalid default item 
 129             pPanel
->SetDefaultItem(NULL
); 
 132 } // end of wxButton::~wxButton 
 134 // ---------------------------------------------------------------------------- 
 135 // size management including autosizing 
 136 // ---------------------------------------------------------------------------- 
 138 wxSize 
wxButton::DoGetBestSize() const 
 140     wxString                        rsLabel 
= wxGetWindowText(GetHWND()); 
 145     GetTextExtent( rsLabel
 
 150     wxGetCharSize( GetHWND() 
 157     // Add a margin - the button is wider than just its label 
 159     nWidthButton 
+= 3 * nWidthChar
; 
 162     // The button height is proportional to the height of the font used 
 164     int                             nHeightButton 
= BUTTON_HEIGHT_FROM_CHAR_HEIGHT(nHeightChar
); 
 167     // Need a little extra to make it look right 
 169     nHeightButton 
+= (int)(nHeightChar
/1.5); 
 171     if (!HasFlag(wxBU_EXACTFIT
)) 
 173         wxSize                      vSize 
= GetDefaultSize(); 
 175         if (nWidthButton 
> vSize
.x
) 
 176             vSize
.x 
= nWidthButton
; 
 177         if (nHeightButton 
> vSize
.y
) 
 178             vSize
.y 
= nHeightButton
; 
 181     return wxSize( nWidthButton
 
 184 } // end of wxButton::DoGetBestSize 
 187 wxSize 
wxButton::GetDefaultSize() 
 189     static wxSize                   vSizeBtn
; 
 195         vDc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 198         // The size of a standard button in the dialog units is 50x14, 
 199         // translate this to pixels 
 200         // NB1: the multipliers come from the Windows convention 
 201         // NB2: the extra +1/+2 were needed to get the size be the same as the 
 202         //      size of the buttons in the standard dialog - I don't know how 
 203         //      this happens, but on my system this size is 75x23 in pixels and 
 204         //      23*8 isn't even divisible by 14... Would be nice to understand 
 205         //      why these constants are needed though! 
 206         vSizeBtn
.x 
= (50 * (vDc
.GetCharWidth() + 1))/4; 
 207         vSizeBtn
.y 
= ((14 * vDc
.GetCharHeight()) + 2)/8; 
 210 } // end of wxButton::GetDefaultSize 
 212 void wxButton::Command ( 
 213   wxCommandEvent
&                   rEvent
 
 216     ProcessCommand (rEvent
); 
 217 } // end of wxButton::Command 
 219 // ---------------------------------------------------------------------------- 
 221 // ---------------------------------------------------------------------------- 
 223 bool wxButton::SendClickEvent() 
 225     wxCommandEvent                  
vEvent( wxEVT_COMMAND_BUTTON_CLICKED
 
 229     vEvent
.SetEventObject(this); 
 230     return ProcessCommand(vEvent
); 
 231 } // end of wxButton::SendClickEvent 
 233 void wxButton::SetDefault() 
 235     wxWindow
*                       pParent 
= GetParent(); 
 237     wxCHECK_RET( pParent
, _T("button without parent?") ); 
 240     // Set this one as the default button both for wxWidgets and Windows 
 242     wxWindow
*                       pWinOldDefault 
= pParent
->SetDefaultItem(this); 
 244     SetDefaultStyle( wxDynamicCast(pWinOldDefault
, wxButton
) 
 247     SetDefaultStyle( this 
 250 } // end of wxButton::SetDefault 
 252 void wxButton::SetTmpDefault() 
 254     wxWindow
*                       pParent 
= GetParent(); 
 256     wxCHECK_RET( pParent
, _T("button without parent?") ); 
 258     wxWindow
*                       pWinOldDefault 
= pParent
->GetDefaultItem(); 
 260     pParent
->SetTmpDefaultItem(this); 
 261     SetDefaultStyle( wxDynamicCast(pWinOldDefault
, wxButton
) 
 264     SetDefaultStyle( this 
 267 } // end of wxButton::SetTmpDefault 
 269 void wxButton::UnsetTmpDefault() 
 271     wxWindow
*                       pParent 
= GetParent(); 
 273     wxCHECK_RET( pParent
, _T("button without parent?") ); 
 275     pParent
->SetTmpDefaultItem(NULL
); 
 277     wxWindow
*                       pWinOldDefault 
= pParent
->GetDefaultItem(); 
 279     SetDefaultStyle( this 
 282     SetDefaultStyle( wxDynamicCast(pWinOldDefault
, wxButton
) 
 285 } // end of wxButton::UnsetTmpDefault 
 287 void wxButton::SetDefaultStyle( 
 294     // We may be called with NULL pointer -- simpler to do the check here than 
 295     // in the caller which does wxDynamicCast() 
 301     // First, let DefDlgProc() know about the new default button 
 305         if (!wxTheApp
->IsActive()) 
 309         // In OS/2 the dialog/panel doesn't really know it has a default 
 310         // button, the default button simply has that style.  We'll just 
 311         // simulate by setting focus to it 
 315     lStyle 
= ::WinQueryWindowULong(GetHwndOf(pBtn
), QWL_STYLE
); 
 316     if (!(lStyle 
& BS_DEFAULT
) == bOn
) 
 318         if ((lStyle 
& BS_USERBUTTON
) != BS_USERBUTTON
) 
 321                 lStyle 
|= BS_DEFAULT
; 
 323                 lStyle 
&= ~BS_DEFAULT
; 
 324             ::WinSetWindowULong(GetHwndOf(pBtn
), QWL_STYLE
, lStyle
); 
 329             // Redraw the button - it will notice itself that it's not the 
 330             // default one any longer 
 335 } // end of wxButton::UpdateDefaultStyle 
 337 // ---------------------------------------------------------------------------- 
 338 // event/message handlers 
 339 // ---------------------------------------------------------------------------- 
 341 bool wxButton::OS2Command( 
 346     bool                            bProcessed 
= FALSE
; 
 350         case BN_CLICKED
:            // normal buttons send this 
 351         case BN_DBLCLICKED
:         // owner-drawn ones also send this 
 352             bProcessed 
= SendClickEvent(); 
 356 } // end of wxButton::OS2Command 
 358 WXHBRUSH 
wxButton::OnCtlColor( 
 367     wxBrush
*                        pBackgroundBrush 
= wxTheBrushList
->FindOrCreateBrush( GetBackgroundColour() 
 371     return (WXHBRUSH
)pBackgroundBrush
->GetResourceHandle(); 
 372 } // end of wxButton::OnCtlColor 
 374 void wxButton::MakeOwnerDrawn() 
 378     lStyle 
= ::WinQueryWindowULong(GetHwnd(), QWL_STYLE
); 
 379     if ((lStyle 
& BS_USERBUTTON
) != BS_USERBUTTON
) 
 384         lStyle 
|= BS_USERBUTTON
; 
 385         ::WinSetWindowULong(GetHwnd(), QWL_STYLE
, lStyle
); 
 387 } // end of wxButton::MakeOwnerDrawn 
 389 WXDWORD 
wxButton::OS2GetStyle( 
 391 , WXDWORD
*                          pdwExstyle
 
 395     // Buttons never have an external border, they draw their own one 
 397     WXDWORD                         dwStyle 
= wxControl::OS2GetStyle( (lStyle 
& ~wxBORDER_MASK
) | wxBORDER_NONE
 
 402     // We must use WS_CLIPSIBLINGS with the buttons or they would draw over 
 403     // each other in any resizeable dialog which has more than one button in 
 406     dwStyle 
|= WS_CLIPSIBLINGS
; 
 408 } // end of wxButton::OS2GetStyle 
 410 MRESULT 
wxButton::WindowProc( 
 417     // When we receive focus, we want to temporary become the default button in 
 418     // our parent panel so that pressing "Enter" would activate us -- and when 
 419     // losing it we should restore the previous default button as well 
 421     if (uMsg 
== WM_SETFOCUS
) 
 423         if (SHORT1FROMMP(lParam
) == TRUE
) 
 429         // Let the default processign take place too 
 433     else if (uMsg 
== WM_BUTTON1DBLCLK
) 
 436         // Emulate a click event to force an owner-drawn button to change its 
 437         // appearance - without this, it won't do it 
 439         (void)wxControl::OS2WindowProc( WM_BUTTON1DOWN
 
 445         // And conitnue with processing the message normally as well 
 450     // Let the base class do all real processing 
 452     return (wxControl::OS2WindowProc( uMsg
 
 456 } // end of wxWindowProc