X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3e7fb41b4bf5836a5571321619cfaaedf6844361..4b04699b670b4ab4632229fa0264d154acd3bec1:/src/os2/spinctrl.cpp diff --git a/src/os2/spinctrl.cpp b/src/os2/spinctrl.cpp index 66b5fe5f99..8c2735901e 100644 --- a/src/os2/spinctrl.cpp +++ b/src/os2/spinctrl.cpp @@ -14,6 +14,11 @@ // ============================================================================ +#ifdef __GNUG__ + #pragma implementation "spinctrlbase.h" + #pragma implementation "spinctrl.h" +#endif + // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- @@ -26,6 +31,8 @@ #include "wx/wx.h" #endif +#if wxUSE_SPINBTN + #include "wx/spinctrl.h" #include "wx/os2/private.h" @@ -33,10 +40,17 @@ // macros // ---------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARY - IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl) -#endif +extern void wxAssociateWinWithHandle( HWND hWnd + ,wxWindowOS2* pWin + ); +static WXFARPROC fnWndProcSpinCtrl = (WXFARPROC)NULL; +wxArraySpins wxSpinCtrl::m_svAllSpins; + +IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl) +BEGIN_EVENT_TABLE(wxSpinCtrl, wxSpinButton) + EVT_SPIN(-1, wxSpinCtrl::OnSpinChange) +END_EVENT_TABLE() // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -47,113 +61,431 @@ static const int MARGIN_BETWEEN = 5; // ============================================================================ // implementation // ============================================================================ +MRESULT EXPENTRY wxSpinCtrlWndProc( + HWND hWnd +, UINT uMessage +, MPARAM wParam +, MPARAM lParam +) +{ + wxSpinCtrl* pSpin = (wxSpinCtrl *)::WinQueryWindowULong( hWnd + ,QWL_USER + ); + bool bProccesed = FALSE; + MRESULT rc = (MRESULT)0; + // + // Forward some messages (the key ones only so far) to the spin ctrl + // + switch (uMessage ) + { + case WM_CHAR: + pSpin->OS2WindowProc( uMessage + ,wParam + ,lParam + ); + + // + // The control may have been deleted at this point, so check. + // + if (!(::WinIsWindow(vHabmain, hWnd) && ((wxSpinCtrl *)::WinQueryWindowULong( hWnd + ,QWL_USER + ) + ) == pSpin)) + return 0; + break; + + } + return (fnWndProcSpinCtrl( hWnd + ,(ULONG)uMessage + ,(MPARAM)wParam + ,(MPARAM)lParam + ) + ); +} // end of wxSpinCtrlWndProc + +wxSpinCtrl::~wxSpinCtrl() +{ + m_svAllSpins.Remove(this); + + // This removes spurious memory leak reporting + if (m_svAllSpins.GetCount() == 0) + m_svAllSpins.Clear(); +} // end of wxSpinCtrl::~wxSpinCtrl // ---------------------------------------------------------------------------- // construction // ---------------------------------------------------------------------------- -bool wxSpinCtrl::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style, - int min, int max, int initial, - const wxString& name) -{ - // TODO: -/* - // before using DoGetBestSize(), have to set style to let the base class - // know whether this is a horizontal or vertical control (we're always - // vertical) - SetWindowStyle(style | wxSP_VERTICAL); - - // calculate the sizes: the size given is the toal size for both controls - // and we need to fit them both in the given width (height is the same) - wxSize sizeText(size), sizeBtn(size); - sizeBtn.x = wxSpinButton::DoGetBestSize().x; - sizeText.x -= sizeBtn.x + MARGIN_BETWEEN; - if ( sizeText.x <= 0 ) +bool wxSpinCtrl::Create( + wxWindow* pParent +, wxWindowID vId +, const wxString& rsValue +, const wxPoint& rPos +, const wxSize& rSize +, long lStyle +, int nMin +, int nMax +, int nInitial +, const wxString& rsName +) +{ + SWP vSwp; + + if (vId == -1) + m_windowId = NewControlId(); + else + m_windowId = vId; + m_backgroundColour = pParent->GetBackgroundColour(); + m_foregroundColour = pParent->GetForegroundColour(); + SetName(rsName); + SetParent(pParent); + m_windowStyle = lStyle; + + int lSstyle = 0L; + + lSstyle = WS_VISIBLE | + WS_TABSTOP | + SPBS_MASTER | // We use only single field spin buttons + SPBS_NUMERICONLY; // We default to numeric data + + if (m_windowStyle & wxCLIP_SIBLINGS ) + lSstyle |= WS_CLIPSIBLINGS; + + SPBCDATA vCtrlData; + + vCtrlData.cbSize = sizeof(SPBCDATA); + vCtrlData.ulTextLimit = 10L; + vCtrlData.lLowerLimit = 0L; + vCtrlData.lUpperLimit = 100L; + vCtrlData.idMasterSpb = vId; + vCtrlData.pHWXCtlData = NULL; + + m_hWnd = (WXHWND)::WinCreateWindow( GetWinHwnd(pParent) + ,WC_SPINBUTTON + ,(PSZ)NULL + ,lSstyle + ,0L, 0L, 0L, 0L + ,GetWinHwnd(pParent) + ,HWND_TOP + ,(HMENU)vId + ,(PVOID)&vCtrlData + ,NULL + ); + if (m_hWnd == 0) { - wxLogDebug(_T("not enough space for wxSpinCtrl!")); + return FALSE; } + m_hWndBuddy = m_hWnd; // One in the same for OS/2 + if(pParent) + pParent->AddChild((wxSpinButton *)this); + wxFont* pTextFont = new wxFont( 10 + ,wxMODERN + ,wxNORMAL + ,wxNORMAL + ); + SetFont(*pTextFont); + ::WinQueryWindowPos(m_hWnd, &vSwp); + SetXComp(vSwp.x); + SetYComp(vSwp.y); + SetSize( rPos.x + ,rPos.y + ,rSize.x + ,rSize.y + ); + + SetRange(nMin, nMax); + SetValue(nInitial); + + // + // For OS/2 we'll just set our handle into our long data + // + wxAssociateWinWithHandle( m_hWnd + ,(wxWindowOS2*)this + ); + ::WinSetWindowULong(GetHwnd(), QWL_USER, (LONG)this); + fnWndProcSpinCtrl = (WXFARPROC)::WinSubclassWindow(m_hWnd, (PFNWP)wxSpinCtrlWndProc); + m_svAllSpins.Add(this); + delete pTextFont; + return TRUE; +} // end of wxSpinCtrl::Create + +wxSize wxSpinCtrl::DoGetBestSize() const +{ + wxSize vSizeBtn = wxSpinButton::DoGetBestSize(); + int nHeight; + + vSizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN; - wxPoint posBtn(pos); - posBtn.x += sizeText.x + MARGIN_BETWEEN; + wxGetCharSize( GetHWND() + ,NULL + ,&nHeight + ,(wxFont*)&GetFont() + ); + nHeight = EDIT_HEIGHT_FROM_CHAR_HEIGHT(nHeight); - // create the spin button - if ( !wxSpinButton::Create(parent, id, posBtn, sizeBtn, style, name) ) + if (vSizeBtn.y < nHeight) { - return FALSE; + // + // Make the text tall enough + // + vSizeBtn.y = nHeight; } + return vSizeBtn; +} // end of wxSpinCtrl::DoGetBestSize + +void wxSpinCtrl::DoGetPosition( + int* pnX +, int* pnY +) const +{ + WXHWND hWnd = GetHWND(); - SetRange(min, max); - SetValue(initial); + wxConstCast(this, wxSpinCtrl)->m_hWnd = m_hWndBuddy; + wxSpinButton::DoGetPosition( pnX + ,pnY + ); + wxConstCast(this, wxSpinCtrl)->m_hWnd = hWnd; +} // end of wxpinCtrl::DoGetPosition - // create the text window - if ( sizeText.y <= 0 ) +void wxSpinCtrl::DoGetSize( + int* pnWidth +, int* pnHeight +) const +{ + RECTL vSpinrect; + + ::WinQueryWindowRect(GetHwnd(), &vSpinrect); + + if (pnWidth) + *pnWidth = vSpinrect.xRight - vSpinrect.xLeft; + if (pnHeight) + *pnHeight = vSpinrect.yTop - vSpinrect.yBottom; +} // end of wxSpinCtrl::DoGetSize + +void wxSpinCtrl::DoMoveWindow( + int nX +, int nY +, int nWidth +, int nHeight +) +{ + wxWindowOS2* pParent = (wxWindowOS2*)GetParent(); + + if (pParent) { - // make it the same height as the button then - int x, y; - wxSpinButton::DoGetSize(&x, &y); + int nOS2Height = GetOS2ParentHeight(pParent); - sizeText.y = y; + nY = nOS2Height - (nY + nHeight); } - - m_hwndBuddy = (WXHWND)::CreateWindowEx - ( - WS_EX_CLIENTEDGE, // sunken border - _T("EDIT"), // window class - NULL, // no window title - WS_CHILD | WS_VISIBLE | WS_BORDER, // style - pos.x, pos.y, // position - sizeText.x, sizeText.y, // size - GetHwndOf(parent), // parent - (HMENU)-1, // control id - wxGetInstance(), // app instance - NULL // unused client data - ); - - if ( !m_hwndBuddy ) + else { - wxLogLastError("CreateWindow(buddy text window)"); + RECTL vRect; + ::WinQueryWindowRect(HWND_DESKTOP, &vRect); + nY = vRect.yTop - (nY + nHeight); + } + ::WinSetWindowPos( GetHwnd() + ,HWND_TOP + ,nX + ,nY + ,nWidth + ,nHeight + ,SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW + ); +} // end of wxSpinCtrl::DoMoveWindow + +bool wxSpinCtrl::Enable( + bool bEnable +) +{ + if (!wxControl::Enable(bEnable)) + { return FALSE; } + ::WinEnableWindow(GetHwnd(), bEnable); + return TRUE; +} // end of wxSpinCtrl::Enable - // should have the same font as the other controls - WXHANDLE hFont = GetParent()->GetFont().GetResourceHandle(); - ::SendMessage((HWND)m_hwndBuddy, WM_SETFONT, (WPARAM)hFont, TRUE); +wxSpinCtrl* wxSpinCtrl::GetSpinForTextCtrl( + WXHWND hWndBuddy +) +{ + wxSpinCtrl* pSpin = (wxSpinCtrl *)::WinQueryWindowULong( (HWND)hWndBuddy + ,QWL_USER + ); + int i = m_svAllSpins.Index(pSpin); - // associate the text window with the spin button - (void)SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)m_hwndBuddy, 0); -*/ - return FALSE; -} + if (i == wxNOT_FOUND) + return NULL; -// ---------------------------------------------------------------------------- -// size calculations -// ---------------------------------------------------------------------------- + // sanity check + wxASSERT_MSG( pSpin->m_hWndBuddy == hWndBuddy, + _T("wxSpinCtrl has incorrect buddy HWND!") ); + + return pSpin; +} // end of wxSpinCtrl::GetSpinForTextCtrl + +int wxSpinCtrl::GetValue() const +{ + long lVal = 0L; + char zVal[10]; + + ::WinSendMsg( GetHwnd() + ,SPBM_QUERYVALUE + ,MPFROMP(zVal) + ,MPFROM2SHORT( (USHORT)10 + ,SPBQ_UPDATEIFVALID + ) + ); + lVal - atol(zVal); + return lVal; +} // end of wxSpinCtrl::GetValue + +void wxSpinCtrl::OnChar ( + wxKeyEvent& rEvent +) +{ + switch (rEvent.KeyCode()) + { + case WXK_RETURN: + { + wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_ENTER + ,m_windowId + ); + wxString sVal = wxGetWindowText(m_hWndBuddy); + + InitCommandEvent(vEvent); + vEvent.SetString((char*)sVal.c_str()); + vEvent.SetInt(GetValue()); + if (GetEventHandler()->ProcessEvent(vEvent)) + return; + break; + } + + case WXK_TAB: + // + // Always produce navigation event - even if we process TAB + // ourselves the fact that we got here means that the user code + // decided to skip processing of this TAB - probably to let it + // do its default job. + // + { + wxNavigationKeyEvent vEventNav; + + vEventNav.SetDirection(!rEvent.ShiftDown()); + vEventNav.SetWindowChange(rEvent.ControlDown()); + vEventNav.SetEventObject(this); + if (GetParent()->GetEventHandler()->ProcessEvent(vEventNav)) + return; + } + break; + } + + // + // No, we didn't process it + // + rEvent.Skip(); +} // end of wxSpinCtrl::OnChar + +void wxSpinCtrl::OnSpinChange( + wxSpinEvent& rEventSpin +) +{ + wxCommandEvent vEvent( wxEVT_COMMAND_SPINCTRL_UPDATED + ,GetId() + ); + + vEvent.SetEventObject(this); + vEvent.SetInt(rEventSpin.GetPosition()); + (void)GetEventHandler()->ProcessEvent(vEvent); + if (rEventSpin.GetSkipped()) + { + vEvent.Skip(); + } +} // end of wxSpinCtrl::OnSpinChange -void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height) +bool wxSpinCtrl::ProcessTextCommand( + WXWORD wCmd +, WXWORD wId +) { - int widthBtn = DoGetBestSize().x; - int widthText = width - widthBtn - MARGIN_BETWEEN; - if ( widthText <= 0 ) + switch (wCmd) { - wxLogDebug(_T("not enough space for wxSpinCtrl!")); + case SPBN_CHANGE: + { + wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED + ,GetId() + ); + vEvent.SetEventObject(this); + + wxString sVal = wxGetWindowText(m_hWndBuddy); + + vEvent.SetString((char*)sVal.c_str()); + vEvent.SetInt(GetValue()); + return (GetEventHandler()->ProcessEvent(vEvent)); + } + + case SPBN_SETFOCUS: + case SPBN_KILLFOCUS: + { + wxFocusEvent vEvent( wCmd == EN_KILLFOCUS ? wxEVT_KILL_FOCUS : wxEVT_SET_FOCUS + ,m_windowId + ); + + vEvent.SetEventObject(this); + return(GetEventHandler()->ProcessEvent(vEvent)); + } + default: + break; } -// TODO: -/* - if ( !::MoveWindow((HWND)m_hwndBuddy, x, y, widthText, height, TRUE) ) + + // + // Not processed + // + return FALSE; +} // end of wxSpinCtrl::ProcessTextCommand + +void wxSpinCtrl::SetFocus() +{ + ::WinSetFocus(HWND_DESKTOP, GetHwnd()); +} // end of wxSpinCtrl::SetFocus + +bool wxSpinCtrl::SetFont( + const wxFont& rFont +) +{ + if (!wxWindowBase::SetFont(rFont)) { - wxLogLastError("MoveWindow(buddy)"); + // nothing to do + return FALSE; } - x += widthText + MARGIN_BETWEEN; - if ( !::MoveWindow(GetHwnd(), x, y, widthBtn, height, TRUE) ) + WXHANDLE hFont = GetFont().GetResourceHandle(); + wxOS2SetFont( m_hWnd + ,rFont + ); + return TRUE; +} // end of wxSpinCtrl::SetFont + +void wxSpinCtrl::SetValue( + const wxString& rsText +) +{ + long lVal; + + lVal = atol(rsText.c_str()); + wxSpinButton::SetValue(lVal); +} // end of wxSpinCtrl::SetValue + +bool wxSpinCtrl::Show( + bool bShow +) +{ + if (!wxControl::Show(bShow)) { - wxLogLastError("MoveWindow"); + return FALSE; } -*/ -} + return TRUE; +} // end of wxSpinCtrl::Show + +#endif //wxUSE_SPINBTN \ No newline at end of file