X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e78c4d503ecd57835502fb1bbd13a71cb99019d0..2bc4cc1ead29f6de1f0576a416025edadb13d7cc:/src/os2/button.cpp diff --git a/src/os2/button.cpp b/src/os2/button.cpp index c9a6387c1e..684ee92aa6 100644 --- a/src/os2/button.cpp +++ b/src/os2/button.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: button.cpp +// Name: src/os2/button.cpp // Purpose: wxButton // Author: David Webster // Modified by: @@ -12,61 +12,122 @@ // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" +#include "wx/button.h" + #ifndef WX_PRECOMP - #include "wx/button.h" + #include "wx/app.h" #include "wx/brush.h" #include "wx/panel.h" #include "wx/bmpbuttn.h" #include "wx/settings.h" #include "wx/dcscreen.h" + #include "wx/scrolwin.h" + #include "wx/toplevel.h" #endif +#include "wx/stockitem.h" #include "wx/os2/private.h" -#if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl) +#define BUTTON_HEIGHT_FROM_CHAR_HEIGHT(cy) (11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)/10) + +// +// Should be at the very least less than winDEFAULT_BUTTON_MARGIN +// +#define FOCUS_MARGIN 3 + +#ifndef BST_CHECKED +#define BST_CHECKED 0x0001 #endif // Button -bool wxButton::Create(wxWindow *parent, wxWindowID id, const wxString& label, - const wxPoint& pos, - const wxSize& size, long style, -#if wxUSE_VALIDATORS - const wxValidator& validator, -#endif - const wxString& name) +bool wxButton::Create( wxWindow* pParent, + wxWindowID vId, + const wxString& rsLbl, + const wxPoint& rPos, + const wxSize& rSize, + long lStyle, + const wxValidator& rValidator, + const wxString& rsName) { - SetName(name); -#if wxUSE_VALIDATORS - SetValidator(validator); -#endif - m_windowStyle = style; + wxString rsLabel(rsLbl); + if (rsLabel.empty() && wxIsStockID(vId)) + rsLabel = wxGetStockLabel(vId); - parent->AddChild((wxButton *)this); + wxString sLabel = ::wxPMTextToLabel(rsLabel); - if (id == -1) + SetName(rsName); +#if wxUSE_VALIDATORS + SetValidator(rValidator); +#endif + m_windowStyle = lStyle; + pParent->AddChild((wxButton *)this); + if (vId == -1) m_windowId = NewControlId(); else - m_windowId = id; - - // TODO: create button + m_windowId = vId; + lStyle = WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON; + + // + // OS/2 PM does not have Right/Left/Top/Bottom styles. + // We will have to define an additional style when we implement notebooks + // for a notebook page button + // + if (m_windowStyle & wxCLIP_SIBLINGS ) + lStyle |= WS_CLIPSIBLINGS; + + m_hWnd = (WXHWND)::WinCreateWindow( GetHwndOf(pParent) // Parent handle + ,WC_BUTTON // A Button class window + ,sLabel.c_str() // Button text + ,lStyle // Button style + ,0, 0, 0, 0 // Location and size + ,GetHwndOf(pParent) // Owner handle + ,HWND_TOP // Top of Z-Order + ,vId // Identifier + ,NULL // No control data + ,NULL // No Presentation parameters + ); + if (m_hWnd == 0) + { + return false; + } - return FALSE; -} + // + // Subclass again for purposes of dialog editing mode + // + SubclassWin(m_hWnd); + wxFont* pButtonFont = new wxFont( 8 + ,wxSWISS + ,wxNORMAL + ,wxNORMAL + ); + SetFont(*pButtonFont); + SetXComp(0); + SetYComp(0); + SetSize( rPos.x + ,rPos.y + ,rSize.x + ,rSize.y + ); + delete pButtonFont; + return true; +} // end of wxButton::Create wxButton::~wxButton() { - wxPanel *panel = wxDynamicCast(GetParent(), wxPanel); - if ( panel ) + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + + if (tlw) { - if ( panel->GetDefaultItem() == this ) + if (tlw->GetDefaultItem() == this) { - // don't leave the panel with invalid default item - panel->SetDefaultItem(NULL); + // + // Don't leave the panel with invalid default item + // + tlw->SetDefaultItem(NULL); } } -} +} // end of wxButton::~wxButton // ---------------------------------------------------------------------------- // size management including autosizing @@ -74,33 +135,66 @@ wxButton::~wxButton() wxSize wxButton::DoGetBestSize() const { - wxString label = wxGetWindowText(GetHWND()); - int wBtn; - GetTextExtent(label, &wBtn, NULL); - - int wChar, hChar; - wxGetCharSize(GetHWND(), &wChar, &hChar, (wxFont*)&GetFont()); - - // add a margin - the button is wider than just its label - wBtn += 3*wChar; - - // the button height is proportional to the height of the font used - int hBtn = 0;// TODO: BUTTON_HEIGHT_FROM_CHAR_HEIGHT(hChar); + wxString rsLabel = wxGetWindowText(GetHWND()); + int nWidthButton; + int nWidthChar; + int nHeightChar; + wxFont vFont = (wxFont)GetFont(); + + GetTextExtent( rsLabel + ,&nWidthButton + ,NULL + ); + + wxGetCharSize( GetHWND() + ,&nWidthChar + ,&nHeightChar + ,&vFont + ); + + // + // Add a margin - the button is wider than just its label + // + nWidthButton += 3 * nWidthChar; + + // + // The button height is proportional to the height of the font used + // + int nHeightButton = BUTTON_HEIGHT_FROM_CHAR_HEIGHT(nHeightChar); + + // + // Need a little extra to make it look right + // + nHeightButton += (int)(nHeightChar/1.5); + + if (!HasFlag(wxBU_EXACTFIT)) + { + wxSize vSize = GetDefaultSize(); - return wxSize(wBtn, hBtn); -} + if (nWidthButton > vSize.x) + vSize.x = nWidthButton; + if (nHeightButton > vSize.y) + vSize.y = nHeightButton; + return vSize; + } + return wxSize( nWidthButton + ,nHeightButton + ); +} // end of wxButton::DoGetBestSize /* static */ wxSize wxButton::GetDefaultSize() { - static wxSize s_sizeBtn; + static wxSize vSizeBtn; - if ( s_sizeBtn.x == 0 ) + if (vSizeBtn.x == 0) { - wxScreenDC dc; - dc.SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); + wxScreenDC vDc; + + vDc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - // the size of a standard button in the dialog units is 50x14, + // + // The size of a standard button in the dialog units is 50x14, // translate this to pixels // NB1: the multipliers come from the Windows convention // NB2: the extra +1/+2 were needed to get the size be the same as the @@ -108,17 +202,18 @@ wxSize wxButton::GetDefaultSize() // this happens, but on my system this size is 75x23 in pixels and // 23*8 isn't even divisible by 14... Would be nice to understand // why these constants are needed though! - s_sizeBtn.x = (50 * (dc.GetCharWidth() + 1))/4; - s_sizeBtn.y = ((14 * dc.GetCharHeight()) + 2)/8; + vSizeBtn.x = (50 * (vDc.GetCharWidth() + 1))/4; + vSizeBtn.y = ((14 * vDc.GetCharHeight()) + 2)/8; } + return vSizeBtn; +} // end of wxButton::GetDefaultSize - return s_sizeBtn; -} - -void wxButton::Command (wxCommandEvent & event) +void wxButton::Command ( + wxCommandEvent& rEvent +) { - ProcessCommand (event); -} + ProcessCommand (rEvent); +} // end of wxButton::Command // ---------------------------------------------------------------------------- // helpers @@ -126,53 +221,215 @@ void wxButton::Command (wxCommandEvent & event) bool wxButton::SendClickEvent() { - wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId()); - event.SetEventObject(this); + wxCommandEvent vEvent( wxEVT_COMMAND_BUTTON_CLICKED + ,GetId() + ); - return ProcessCommand(event); -} + vEvent.SetEventObject(this); + return ProcessCommand(vEvent); +} // end of wxButton::SendClickEvent -void wxButton::SetDefault() +wxWindow *wxButton::SetDefault() { - wxWindow *parent = GetParent(); - wxButton *btnOldDefault = NULL; - wxPanel *panel = wxDynamicCast(parent, wxPanel); - if (panel) - panel->SetDefaultItem(this); + // + // Set this one as the default button both for wxWidgets and Windows + // + wxWindow* pWinOldDefault = wxButtonBase::SetDefault(); + + SetDefaultStyle( wxDynamicCast(pWinOldDefault, wxButton), false); + SetDefaultStyle( this, true ); + + return pWinOldDefault; +} // end of wxButton::SetDefault + +void wxButton::SetTmpDefault() +{ + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + + wxCHECK_RET( tlw, wxT("button without top level window?") ); + + wxWindow* pWinOldDefault = tlw->GetDefaultItem(); + + tlw->SetTmpDefaultItem(this); + SetDefaultStyle( wxDynamicCast(pWinOldDefault, wxButton), false); + SetDefaultStyle( this, true ); +} // end of wxButton::SetTmpDefault + +void wxButton::UnsetTmpDefault() +{ + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + + wxCHECK_RET( tlw, wxT("button without top level window?") ); - // TODO: make button the default -} + tlw->SetTmpDefaultItem(NULL); + + wxWindow* pWinOldDefault = tlw->GetDefaultItem(); + + SetDefaultStyle( this, false ); + SetDefaultStyle( wxDynamicCast(pWinOldDefault, wxButton), true ); +} // end of wxButton::UnsetTmpDefault + +void wxButton::SetDefaultStyle( + wxButton* pBtn +, bool bOn +) +{ + long lStyle; + // + // We may be called with NULL pointer -- simpler to do the check here than + // in the caller which does wxDynamicCast() + // + if (!pBtn) + return; + + // + // First, let DefDlgProc() know about the new default button + // + if (bOn) + { + if (!wxTheApp->IsActive()) + return; + + // + // In OS/2 the dialog/panel doesn't really know it has a default + // button, the default button simply has that style. We'll just + // simulate by setting focus to it + // + pBtn->SetFocus(); + } + lStyle = ::WinQueryWindowULong(GetHwndOf(pBtn), QWL_STYLE); + if (!(lStyle & BS_DEFAULT) == bOn) + { + if ((lStyle & BS_USERBUTTON) != BS_USERBUTTON) + { + if (bOn) + lStyle |= BS_DEFAULT; + else + lStyle &= ~BS_DEFAULT; + ::WinSetWindowULong(GetHwndOf(pBtn), QWL_STYLE, lStyle); + } + else + { + // + // Redraw the button - it will notice itself that it's not the + // default one any longer + // + pBtn->Refresh(); + } + } +} // end of wxButton::UpdateDefaultStyle // ---------------------------------------------------------------------------- // event/message handlers // ---------------------------------------------------------------------------- -bool wxButton::OS2Command(WXUINT param, WXWORD id) +bool wxButton::OS2Command(WXUINT uParam, WXWORD WXUNUSED(wId)) { - bool processed = FALSE; - // TODO - /* - switch ( param ) + bool bProcessed = false; + + switch (uParam) { - case 1: // 1 for accelerator - case BN_CLICKED: - processed = SendClickEvent(); + case BN_CLICKED: // normal buttons send this + case BN_DBLCLICKED: // owner-drawn ones also send this + bProcessed = SendClickEvent(); break; } - */ - return processed; -} - -WXHBRUSH wxButton::OnCtlColor(WXHDC pDC, - WXHWND pWnd, - WXUINT nCtlColor, - WXUINT message, - WXWPARAM wParam, - WXLPARAM lParam) + + return bProcessed; +} // end of wxButton::OS2Command + +WXHBRUSH wxButton::OnCtlColor( WXHDC WXUNUSED(pDC), + WXHWND WXUNUSED(pWnd), + WXUINT WXUNUSED(nCtlColor), + WXUINT WXUNUSED(uMessage), + WXWPARAM WXUNUSED(wParam), + WXLPARAM WXUNUSED(lParam) ) +{ + wxBrush* pBackgroundBrush = wxTheBrushList->FindOrCreateBrush( GetBackgroundColour() + ,wxSOLID + ); + + return (WXHBRUSH)pBackgroundBrush->GetResourceHandle(); +} // end of wxButton::OnCtlColor + +void wxButton::MakeOwnerDrawn() { - wxBrush *backgroundBrush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID); + long lStyle = 0L; + + lStyle = ::WinQueryWindowULong(GetHwnd(), QWL_STYLE); + if ((lStyle & BS_USERBUTTON) != BS_USERBUTTON) + { + // + // Make it so + // + lStyle |= BS_USERBUTTON; + ::WinSetWindowULong(GetHwnd(), QWL_STYLE, lStyle); + } +} // end of wxButton::MakeOwnerDrawn - return (WXHBRUSH) backgroundBrush->GetResourceHandle(); -} +WXDWORD wxButton::OS2GetStyle( + long lStyle +, WXDWORD* pdwExstyle +) const +{ + // + // Buttons never have an external border, they draw their own one + // + WXDWORD dwStyle = wxControl::OS2GetStyle( (lStyle & ~wxBORDER_MASK) | wxBORDER_NONE + ,pdwExstyle + ); + + // + // We must use WS_CLIPSIBLINGS with the buttons or they would draw over + // each other in any resizable dialog which has more than one button in + // the bottom + // + dwStyle |= WS_CLIPSIBLINGS; + return dwStyle; +} // end of wxButton::OS2GetStyle + +MRESULT wxButton::WindowProc( WXUINT uMsg, + WXWPARAM wParam, + WXLPARAM lParam ) +{ + // + // When we receive focus, we want to temporary become the default button in + // our parent panel so that pressing "Enter" would activate us -- and when + // losing it we should restore the previous default button as well + // + if (uMsg == WM_SETFOCUS) + { + if (SHORT1FROMMP(lParam) == TRUE) + SetTmpDefault(); + else + UnsetTmpDefault(); + + // + // Let the default processign take place too + // + } + else if (uMsg == WM_BUTTON1DBLCLK) + { + // + // Emulate a click event to force an owner-drawn button to change its + // appearance - without this, it won't do it + // + (void)wxControl::OS2WindowProc( WM_BUTTON1DOWN + ,wParam + ,lParam + ); + + // + // And conitnue with processing the message normally as well + // + } + // + // Let the base class do all real processing + // + return (wxControl::OS2WindowProc( uMsg + ,wParam + ,lParam + )); +} // end of wxWindowProc