1///////////////////////////////////////////////////////////////////////////// 2// Name: src/msw/spinbutt.cpp 3// Purpose: wxSpinButton 4// Author: Julian Smart 5// Modified by: 6// Created: 04/01/98 7// RCS-ID: $Id: spinbutt.cpp 42816 2006-10-31 08:50:17Z RD $ 8// Copyright: (c) Julian Smart 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27#ifndef WX_PRECOMP 28 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 29 #include "wx/app.h" 30#endif 31 32#if wxUSE_SPINBTN 33 34#include "wx/spinbutt.h" 35 36IMPLEMENT_DYNAMIC_CLASS(wxSpinEvent, wxNotifyEvent) 37 38#include "wx/msw/private.h" 39 40#ifndef UDM_SETRANGE32 41 #define UDM_SETRANGE32 (WM_USER+111) 42#endif 43 44#ifndef UDM_SETPOS32 45 #define UDM_SETPOS32 (WM_USER+113) 46 #define UDM_GETPOS32 (WM_USER+114) 47#endif 48 49// ============================================================================ 50// implementation 51// ============================================================================ 52 53// ---------------------------------------------------------------------------- 54// wxWin macros 55// ---------------------------------------------------------------------------- 56 57 58#if wxUSE_EXTENDED_RTTI 59WX_DEFINE_FLAGS( wxSpinButtonStyle ) 60 61wxBEGIN_FLAGS( wxSpinButtonStyle ) 62 // new style border flags, we put them first to 63 // use them for streaming out 64 wxFLAGS_MEMBER(wxBORDER_SIMPLE) 65 wxFLAGS_MEMBER(wxBORDER_SUNKEN) 66 wxFLAGS_MEMBER(wxBORDER_DOUBLE) 67 wxFLAGS_MEMBER(wxBORDER_RAISED) 68 wxFLAGS_MEMBER(wxBORDER_STATIC) 69 wxFLAGS_MEMBER(wxBORDER_NONE) 70 71 // old style border flags 72 wxFLAGS_MEMBER(wxSIMPLE_BORDER) 73 wxFLAGS_MEMBER(wxSUNKEN_BORDER) 74 wxFLAGS_MEMBER(wxDOUBLE_BORDER) 75 wxFLAGS_MEMBER(wxRAISED_BORDER) 76 wxFLAGS_MEMBER(wxSTATIC_BORDER) 77 wxFLAGS_MEMBER(wxBORDER) 78 79 // standard window styles 80 wxFLAGS_MEMBER(wxTAB_TRAVERSAL) 81 wxFLAGS_MEMBER(wxCLIP_CHILDREN) 82 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) 83 wxFLAGS_MEMBER(wxWANTS_CHARS) 84 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) 85 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) 86 wxFLAGS_MEMBER(wxVSCROLL) 87 wxFLAGS_MEMBER(wxHSCROLL) 88 89 wxFLAGS_MEMBER(wxSP_HORIZONTAL) 90 wxFLAGS_MEMBER(wxSP_VERTICAL) 91 wxFLAGS_MEMBER(wxSP_ARROW_KEYS) 92 wxFLAGS_MEMBER(wxSP_WRAP) 93 94wxEND_FLAGS( wxSpinButtonStyle ) 95 96IMPLEMENT_DYNAMIC_CLASS_XTI(wxSpinButton, wxControl,"wx/spinbut.h") 97 98wxBEGIN_PROPERTIES_TABLE(wxSpinButton) 99 wxEVENT_RANGE_PROPERTY( Spin , wxEVT_SCROLL_TOP , wxEVT_SCROLL_CHANGED , wxSpinEvent ) 100 101 wxPROPERTY( Value , int , SetValue, GetValue, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 102 wxPROPERTY( Min , int , SetMin, GetMin, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 103 wxPROPERTY( Max , int , SetMax, GetMax, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 104 wxPROPERTY_FLAGS( WindowStyle , wxSpinButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 105wxEND_PROPERTIES_TABLE() 106 107wxBEGIN_HANDLERS_TABLE(wxSpinButton) 108wxEND_HANDLERS_TABLE() 109 110wxCONSTRUCTOR_5( wxSpinButton , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle ) 111#else 112IMPLEMENT_DYNAMIC_CLASS(wxSpinButton, wxControl) 113#endif 114 115 116 117// ---------------------------------------------------------------------------- 118// wxSpinButton 119// ---------------------------------------------------------------------------- 120 121bool wxSpinButton::Create(wxWindow *parent, 122 wxWindowID id, 123 const wxPoint& pos, 124 const wxSize& size, 125 long style, 126 const wxString& name) 127{ 128 // basic initialization 129 m_windowId = (id == wxID_ANY) ? NewControlId() : id; 130 131 SetName(name); 132 133 int x = pos.x; 134 int y = pos.y; 135 int width = size.x; 136 int height = size.y; 137 138 m_windowStyle = style; 139 140 SetParent(parent); 141 142 // get the right size for the control 143 if ( width <= 0 || height <= 0 ) 144 { 145 wxSize size = DoGetBestSize(); 146 if ( width <= 0 ) 147 width = size.x; 148 if ( height <= 0 ) 149 height = size.y; 150 } 151 152 if ( x < 0 ) 153 x = 0; 154 if ( y < 0 ) 155 y = 0; 156 157 // translate the styles 158 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | /* WS_CLIPSIBLINGS | */ 159 UDS_NOTHOUSANDS | // never useful, sometimes harmful 160 UDS_SETBUDDYINT; // it doesn't harm if we don't have buddy 161 162 if ( m_windowStyle & wxCLIP_SIBLINGS ) 163 wstyle |= WS_CLIPSIBLINGS; 164 if ( m_windowStyle & wxSP_HORIZONTAL ) 165 wstyle |= UDS_HORZ; 166 if ( m_windowStyle & wxSP_ARROW_KEYS ) 167 wstyle |= UDS_ARROWKEYS; 168 if ( m_windowStyle & wxSP_WRAP ) 169 wstyle |= UDS_WRAP; 170 171 // create the UpDown control. 172 m_hWnd = (WXHWND)CreateUpDownControl 173 ( 174 wstyle, 175 x, y, width, height, 176 GetHwndOf(parent), 177 m_windowId, 178 wxGetInstance(), 179 NULL, // no buddy 180 m_max, m_min, 181 m_min // initial position 182 ); 183 184 if ( !m_hWnd ) 185 { 186 wxLogLastError(wxT("CreateUpDownControl")); 187 188 return false; 189 } 190 191 if ( parent ) 192 { 193 parent->AddChild(this); 194 } 195 196 SubclassWin(m_hWnd); 197 198 SetInitialSize(size); 199 200 return true; 201} 202 203wxSpinButton::~wxSpinButton() 204{ 205} 206 207// ---------------------------------------------------------------------------- 208// size calculation 209// ---------------------------------------------------------------------------- 210 211wxSize wxSpinButton::DoGetBestSize() const 212{ 213 return GetBestSpinnerSize( (GetWindowStyle() & wxSP_VERTICAL) != 0 ); 214} 215 216// ---------------------------------------------------------------------------- 217// Attributes 218// ---------------------------------------------------------------------------- 219 220int wxSpinButton::GetValue() const 221{ 222 int n; 223#ifdef UDM_GETPOS32 224 if ( wxApp::GetComCtl32Version() >= 580 ) 225 { 226 // use the full 32 bit range if available 227 n = ::SendMessage(GetHwnd(), UDM_GETPOS32, 0, 0); 228 } 229 else 230#endif // UDM_GETPOS32 231 { 232 // we're limited to 16 bit 233 n = (short)LOWORD(::SendMessage(GetHwnd(), UDM_GETPOS, 0, 0)); 234 } 235 236 if (n < m_min) n = m_min; 237 if (n > m_max) n = m_max; 238 239 return n; 240} 241 242void wxSpinButton::SetValue(int val) 243{ 244 // wxSpinButtonBase::SetValue(val); -- no, it is pure virtual 245 246#ifdef UDM_SETPOS32 247 if ( wxApp::GetComCtl32Version() >= 580 ) 248 { 249 // use the full 32 bit range if available 250 ::SendMessage(GetHwnd(), UDM_SETPOS32, 0, val); 251 } 252 else // we're limited to 16 bit 253#endif // UDM_SETPOS32 254 { 255 ::SendMessage(GetHwnd(), UDM_SETPOS, 0, MAKELONG((short) val, 0)); 256 } 257} 258 259void wxSpinButton::NormalizeValue() 260{ 261 SetValue( GetValue() ); 262} 263 264void wxSpinButton::SetRange(int minVal, int maxVal) 265{ 266 const bool hadRange = m_min < m_max; 267 268 wxSpinButtonBase::SetRange(minVal, maxVal); 269 270#ifdef UDM_SETRANGE32 271 if ( wxApp::GetComCtl32Version() >= 471 ) 272 { 273 // use the full 32 bit range if available 274 ::SendMessage(GetHwnd(), UDM_SETRANGE32, minVal, maxVal); 275 } 276 else // we're limited to 16 bit 277#endif // UDM_SETRANGE32 278 { 279 ::SendMessage(GetHwnd(), UDM_SETRANGE, 0, 280 (LPARAM) MAKELONG((short)maxVal, (short)minVal)); 281 } 282 283 // the current value might be out of the new range, force it to be in it 284 NormalizeValue(); 285 286 // if range was valid but becomes degenerated (min == max) now or vice 287 // versa then the spin buttons are automatically disabled/enabled back 288 // but don't update themselves for some reason, so do it manually 289 if ( hadRange != (m_min < m_max) ) 290 { 291 // update the visual state of the button 292 Refresh(); 293 } 294} 295 296bool wxSpinButton::MSWOnScroll(int WXUNUSED(orientation), WXWORD wParam, 297 WXWORD pos, WXHWND control) 298{ 299 wxCHECK_MSG( control, false, wxT("scrolling what?") ); 300 301 if ( wParam != SB_THUMBPOSITION ) 302 { 303 // probable SB_ENDSCROLL - we don't react to it 304 return false; 305 } 306 307 wxSpinEvent event(wxEVT_SCROLL_THUMBTRACK, m_windowId); 308 event.SetPosition((short)pos); // cast is important for negative values! 309 event.SetEventObject(this); 310 311 return GetEventHandler()->ProcessEvent(event); 312} 313 314bool wxSpinButton::MSWOnNotify(int WXUNUSED(idCtrl), WXLPARAM lParam, WXLPARAM *result) 315{ 316 NM_UPDOWN *lpnmud = (NM_UPDOWN *)lParam; 317 318 if (lpnmud->hdr.hwndFrom != GetHwnd()) // make sure it is the right control 319 return false; 320 321 wxSpinEvent event(lpnmud->iDelta > 0 ? wxEVT_SCROLL_LINEUP 322 : wxEVT_SCROLL_LINEDOWN, 323 m_windowId); 324 event.SetPosition(lpnmud->iPos + lpnmud->iDelta); 325 event.SetEventObject(this); 326 327 bool processed = GetEventHandler()->ProcessEvent(event); 328 329 *result = event.IsAllowed() ? 0 : 1; 330 331 return processed; 332} 333 334bool wxSpinButton::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD WXUNUSED(id)) 335{ 336 // No command messages 337 return false; 338} 339 340#endif // wxUSE_SPINBTN 341