1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/os2/button.cpp 
   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" 
  15 #include "wx/button.h" 
  21     #include "wx/bmpbuttn.h" 
  22     #include "wx/settings.h" 
  23     #include "wx/dcscreen.h" 
  24     #include "wx/scrolwin.h" 
  25     #include "wx/toplevel.h" 
  28 #include "wx/stockitem.h" 
  29 #include "wx/os2/private.h" 
  31 #define BUTTON_HEIGHT_FROM_CHAR_HEIGHT(cy) (11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)/10) 
  34 // Should be at the very least less than winDEFAULT_BUTTON_MARGIN 
  36 #define FOCUS_MARGIN 3 
  39 #define BST_CHECKED 0x0001 
  42 IMPLEMENT_DYNAMIC_CLASS(wxButton
, wxControl
) 
  46 bool wxButton::Create( wxWindow
*          pParent
, 
  48                        const wxString
&    rsLbl
, 
  52                        const wxValidator
& rValidator
, 
  53                        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     wxTopLevelWindow 
*tlw 
= wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow
); 
 124         if (tlw
->GetDefaultItem() == this) 
 127             // Don't leave the panel with invalid default item 
 129             tlw
->SetDefaultItem(NULL
); 
 132 } // end of wxButton::~wxButton 
 134 // ---------------------------------------------------------------------------- 
 135 // size management including autosizing 
 136 // ---------------------------------------------------------------------------- 
 138 wxSize 
wxButton::DoGetBestSize() const 
 140     wxString                        rsLabel 
= wxGetWindowText(GetHWND()); 
 144     wxFont                          vFont 
= (wxFont
)GetFont(); 
 146     GetTextExtent( rsLabel
 
 151     wxGetCharSize( GetHWND() 
 158     // Add a margin - the button is wider than just its label 
 160     nWidthButton 
+= 3 * nWidthChar
; 
 163     // The button height is proportional to the height of the font used 
 165     int                             nHeightButton 
= BUTTON_HEIGHT_FROM_CHAR_HEIGHT(nHeightChar
); 
 168     // Need a little extra to make it look right 
 170     nHeightButton 
+= (int)(nHeightChar
/1.5); 
 172     if (!HasFlag(wxBU_EXACTFIT
)) 
 174         wxSize                      vSize 
= GetDefaultSize(); 
 176         if (nWidthButton 
> vSize
.x
) 
 177             vSize
.x 
= nWidthButton
; 
 178         if (nHeightButton 
> vSize
.y
) 
 179             vSize
.y 
= nHeightButton
; 
 182     return wxSize( nWidthButton
 
 185 } // end of wxButton::DoGetBestSize 
 188 wxSize 
wxButton::GetDefaultSize() 
 190     static wxSize                   vSizeBtn
; 
 196         vDc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 199         // The size of a standard button in the dialog units is 50x14, 
 200         // translate this to pixels 
 201         // NB1: the multipliers come from the Windows convention 
 202         // NB2: the extra +1/+2 were needed to get the size be the same as the 
 203         //      size of the buttons in the standard dialog - I don't know how 
 204         //      this happens, but on my system this size is 75x23 in pixels and 
 205         //      23*8 isn't even divisible by 14... Would be nice to understand 
 206         //      why these constants are needed though! 
 207         vSizeBtn
.x 
= (50 * (vDc
.GetCharWidth() + 1))/4; 
 208         vSizeBtn
.y 
= ((14 * vDc
.GetCharHeight()) + 2)/8; 
 211 } // end of wxButton::GetDefaultSize 
 213 void wxButton::Command ( 
 214   wxCommandEvent
&                   rEvent
 
 217     ProcessCommand (rEvent
); 
 218 } // end of wxButton::Command 
 220 // ---------------------------------------------------------------------------- 
 222 // ---------------------------------------------------------------------------- 
 224 bool wxButton::SendClickEvent() 
 226     wxCommandEvent                  
vEvent( wxEVT_COMMAND_BUTTON_CLICKED
 
 230     vEvent
.SetEventObject(this); 
 231     return ProcessCommand(vEvent
); 
 232 } // end of wxButton::SendClickEvent 
 234 void wxButton::SetDefault() 
 236     wxTopLevelWindow 
*tlw 
= wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow
); 
 238     wxCHECK_RET( tlw
, _T("button without top level window?") ); 
 241     // Set this one as the default button both for wxWidgets and Windows 
 243     wxWindow
*                       pWinOldDefault 
= tlw
->SetDefaultItem(this); 
 245     SetDefaultStyle( wxDynamicCast(pWinOldDefault
, wxButton
), false); 
 246     SetDefaultStyle( this, true ); 
 247 } // end of wxButton::SetDefault 
 249 void wxButton::SetTmpDefault() 
 251     wxTopLevelWindow 
*tlw 
= wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow
); 
 253     wxCHECK_RET( tlw
, _T("button without top level window?") ); 
 255     wxWindow
*                       pWinOldDefault 
= tlw
->GetDefaultItem(); 
 257     tlw
->SetTmpDefaultItem(this); 
 258     SetDefaultStyle( wxDynamicCast(pWinOldDefault
, wxButton
), false); 
 259     SetDefaultStyle( this, true ); 
 260 } // end of wxButton::SetTmpDefault 
 262 void wxButton::UnsetTmpDefault() 
 264     wxTopLevelWindow 
*tlw 
= wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow
); 
 266     wxCHECK_RET( tlw
, _T("button without top level window?") ); 
 268     tlw
->SetTmpDefaultItem(NULL
); 
 270     wxWindow
*                       pWinOldDefault 
= tlw
->GetDefaultItem(); 
 272     SetDefaultStyle( this, false ); 
 273     SetDefaultStyle( wxDynamicCast(pWinOldDefault
, wxButton
), true ); 
 274 } // end of wxButton::UnsetTmpDefault 
 276 void wxButton::SetDefaultStyle( 
 283     // We may be called with NULL pointer -- simpler to do the check here than 
 284     // in the caller which does wxDynamicCast() 
 290     // First, let DefDlgProc() know about the new default button 
 294         if (!wxTheApp
->IsActive()) 
 298         // In OS/2 the dialog/panel doesn't really know it has a default 
 299         // button, the default button simply has that style.  We'll just 
 300         // simulate by setting focus to it 
 304     lStyle 
= ::WinQueryWindowULong(GetHwndOf(pBtn
), QWL_STYLE
); 
 305     if (!(lStyle 
& BS_DEFAULT
) == bOn
) 
 307         if ((lStyle 
& BS_USERBUTTON
) != BS_USERBUTTON
) 
 310                 lStyle 
|= BS_DEFAULT
; 
 312                 lStyle 
&= ~BS_DEFAULT
; 
 313             ::WinSetWindowULong(GetHwndOf(pBtn
), QWL_STYLE
, lStyle
); 
 318             // Redraw the button - it will notice itself that it's not the 
 319             // default one any longer 
 324 } // end of wxButton::UpdateDefaultStyle 
 326 // ---------------------------------------------------------------------------- 
 327 // event/message handlers 
 328 // ---------------------------------------------------------------------------- 
 330 bool wxButton::OS2Command(WXUINT uParam
, WXWORD 
WXUNUSED(wId
)) 
 332     bool bProcessed 
= false; 
 336         case BN_CLICKED
:            // normal buttons send this 
 337         case BN_DBLCLICKED
:         // owner-drawn ones also send this 
 338             bProcessed 
= SendClickEvent(); 
 343 } // end of wxButton::OS2Command 
 345 WXHBRUSH 
wxButton::OnCtlColor( WXHDC    
WXUNUSED(pDC
), 
 346                                WXHWND   
WXUNUSED(pWnd
), 
 347                                WXUINT   
WXUNUSED(nCtlColor
), 
 348                                WXUINT   
WXUNUSED(uMessage
), 
 349                                WXWPARAM 
WXUNUSED(wParam
), 
 350                                WXLPARAM 
WXUNUSED(lParam
) ) 
 352     wxBrush
* pBackgroundBrush 
= wxTheBrushList
->FindOrCreateBrush( GetBackgroundColour() 
 356     return (WXHBRUSH
)pBackgroundBrush
->GetResourceHandle(); 
 357 } // end of wxButton::OnCtlColor 
 359 void wxButton::MakeOwnerDrawn() 
 363     lStyle 
= ::WinQueryWindowULong(GetHwnd(), QWL_STYLE
); 
 364     if ((lStyle 
& BS_USERBUTTON
) != BS_USERBUTTON
) 
 369         lStyle 
|= BS_USERBUTTON
; 
 370         ::WinSetWindowULong(GetHwnd(), QWL_STYLE
, lStyle
); 
 372 } // end of wxButton::MakeOwnerDrawn 
 374 WXDWORD 
wxButton::OS2GetStyle( 
 376 , WXDWORD
*                          pdwExstyle
 
 380     // Buttons never have an external border, they draw their own one 
 382     WXDWORD                         dwStyle 
= wxControl::OS2GetStyle( (lStyle 
& ~wxBORDER_MASK
) | wxBORDER_NONE
 
 387     // We must use WS_CLIPSIBLINGS with the buttons or they would draw over 
 388     // each other in any resizeable dialog which has more than one button in 
 391     dwStyle 
|= WS_CLIPSIBLINGS
; 
 393 } // end of wxButton::OS2GetStyle 
 395 MRESULT 
wxButton::WindowProc( WXUINT   uMsg
, 
 400     // When we receive focus, we want to temporary become the default button in 
 401     // our parent panel so that pressing "Enter" would activate us -- and when 
 402     // losing it we should restore the previous default button as well 
 404     if (uMsg 
== WM_SETFOCUS
) 
 406         if (SHORT1FROMMP(lParam
) == TRUE
) 
 412         // Let the default processign take place too 
 416     else if (uMsg 
== WM_BUTTON1DBLCLK
) 
 419         // Emulate a click event to force an owner-drawn button to change its 
 420         // appearance - without this, it won't do it 
 422         (void)wxControl::OS2WindowProc( WM_BUTTON1DOWN
 
 428         // And conitnue with processing the message normally as well 
 433     // Let the base class do all real processing 
 435     return (wxControl::OS2WindowProc( uMsg
 
 439 } // end of wxWindowProc