]> git.saurik.com Git - wxWidgets.git/blob - src/os2/spinctrl.cpp
Make SetLocal actually work instead of crashing immediately; due to required longevit...
[wxWidgets.git] / src / os2 / spinctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: os2/spinctrl.cpp
3 // Purpose: wxSpinCtrl class implementation for OS/2
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/15/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
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
24 #ifndef WX_PRECOMP
25 #include "wx/wx.h"
26 #endif
27
28 #if wxUSE_SPINCTRL
29
30 #include "wx/spinctrl.h"
31 #include "wx/os2/private.h"
32
33 // ----------------------------------------------------------------------------
34 // macros
35 // ----------------------------------------------------------------------------
36
37 extern void wxAssociateWinWithHandle( HWND hWnd
38 ,wxWindowOS2* pWin
39 );
40 static WXFARPROC fnWndProcSpinCtrl = (WXFARPROC)NULL;
41 wxArraySpins wxSpinCtrl::m_svAllSpins;
42
43 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl)
44
45 BEGIN_EVENT_TABLE(wxSpinCtrl, wxSpinButton)
46 EVT_CHAR(wxSpinCtrl::OnChar)
47 EVT_SPIN(wxID_ANY, wxSpinCtrl::OnSpinChange)
48 EVT_SET_FOCUS(wxSpinCtrl::OnSetFocus)
49 END_EVENT_TABLE()
50 // ----------------------------------------------------------------------------
51 // constants
52 // ----------------------------------------------------------------------------
53
54 // the margin between the up-down control and its buddy
55 static const int MARGIN_BETWEEN = 5;
56
57 // ============================================================================
58 // implementation
59 // ============================================================================
60 MRESULT EXPENTRY wxSpinCtrlWndProc(
61 HWND hWnd
62 , UINT uMessage
63 , MPARAM wParam
64 , MPARAM lParam
65 )
66 {
67 wxSpinCtrl* pSpin = (wxSpinCtrl *)::WinQueryWindowULong( hWnd
68 ,QWL_USER
69 );
70
71 //
72 // Forward some messages (the key ones only so far) to the spin ctrl
73 //
74 switch (uMessage )
75 {
76 case WM_CHAR:
77 pSpin->OS2WindowProc( uMessage
78 ,wParam
79 ,lParam
80 );
81
82 //
83 // The control may have been deleted at this point, so check.
84 //
85 if (!(::WinIsWindow(vHabmain, hWnd) && ((wxSpinCtrl *)::WinQueryWindowULong( hWnd
86 ,QWL_USER
87 )
88 ) == pSpin))
89 return 0;
90 break;
91
92 }
93 return (fnWndProcSpinCtrl( hWnd
94 ,(ULONG)uMessage
95 ,(MPARAM)wParam
96 ,(MPARAM)lParam
97 )
98 );
99 } // end of wxSpinCtrlWndProc
100
101 wxSpinCtrl::~wxSpinCtrl()
102 {
103 m_svAllSpins.Remove(this);
104
105 // This removes spurious memory leak reporting
106 if (m_svAllSpins.GetCount() == 0)
107 m_svAllSpins.Clear();
108 } // end of wxSpinCtrl::~wxSpinCtrl
109
110 // ----------------------------------------------------------------------------
111 // construction
112 // ----------------------------------------------------------------------------
113
114 bool wxSpinCtrl::Create( wxWindow* pParent,
115 wxWindowID vId,
116 const wxString& WXUNUSED(rsValue),
117 const wxPoint& rPos,
118 const wxSize& rSize,
119 long lStyle,
120 int nMin,
121 int nMax,
122 int nInitial,
123 const wxString& rsName )
124 {
125 SWP vSwp;
126
127 if (vId == wxID_ANY)
128 m_windowId = NewControlId();
129 else
130 m_windowId = vId;
131 m_backgroundColour = pParent->GetBackgroundColour();
132 m_foregroundColour = pParent->GetForegroundColour();
133 SetName(rsName);
134 SetParent(pParent);
135 m_windowStyle = lStyle;
136
137 int lSstyle = 0L;
138
139 lSstyle = WS_VISIBLE |
140 WS_TABSTOP |
141 SPBS_MASTER | // We use only single field spin buttons
142 SPBS_NUMERICONLY; // We default to numeric data
143
144 if (m_windowStyle & wxCLIP_SIBLINGS )
145 lSstyle |= WS_CLIPSIBLINGS;
146
147 SPBCDATA vCtrlData;
148
149 vCtrlData.cbSize = sizeof(SPBCDATA);
150 vCtrlData.ulTextLimit = 10L;
151 vCtrlData.lLowerLimit = 0L;
152 vCtrlData.lUpperLimit = 100L;
153 vCtrlData.idMasterSpb = vId;
154 vCtrlData.pHWXCtlData = NULL;
155
156 m_hWnd = (WXHWND)::WinCreateWindow( GetWinHwnd(pParent)
157 ,WC_SPINBUTTON
158 ,(PSZ)NULL
159 ,lSstyle
160 ,0L, 0L, 0L, 0L
161 ,GetWinHwnd(pParent)
162 ,HWND_TOP
163 ,(HMENU)vId
164 ,(PVOID)&vCtrlData
165 ,NULL
166 );
167 if (m_hWnd == 0)
168 {
169 return false;
170 }
171 m_hWndBuddy = m_hWnd; // One in the same for OS/2
172 if(pParent)
173 pParent->AddChild((wxSpinButton *)this);
174 wxFont* pTextFont = new wxFont( 10
175 ,wxMODERN
176 ,wxNORMAL
177 ,wxNORMAL
178 );
179 SetFont(*pTextFont);
180 ::WinQueryWindowPos(m_hWnd, &vSwp);
181 SetXComp(vSwp.x);
182 SetYComp(vSwp.y);
183 SetSize( rPos.x
184 ,rPos.y
185 ,rSize.x
186 ,rSize.y
187 );
188
189 SetRange(nMin, nMax);
190 SetValue(nInitial);
191
192 //
193 // For OS/2 we'll just set our handle into our long data
194 //
195 wxAssociateWinWithHandle( m_hWnd
196 ,(wxWindowOS2*)this
197 );
198 ::WinSetWindowULong(GetHwnd(), QWL_USER, (LONG)this);
199 fnWndProcSpinCtrl = (WXFARPROC)::WinSubclassWindow(m_hWnd, (PFNWP)wxSpinCtrlWndProc);
200 m_svAllSpins.Add(this);
201 delete pTextFont;
202 return true;
203 } // end of wxSpinCtrl::Create
204
205 wxSize wxSpinCtrl::DoGetBestSize() const
206 {
207 wxSize vSizeBtn = wxSpinButton::DoGetBestSize();
208 int nHeight;
209 wxFont vFont = (wxFont)GetFont();
210
211 vSizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN;
212
213 wxGetCharSize( GetHWND()
214 ,NULL
215 ,&nHeight
216 ,&vFont
217 );
218 nHeight = EDIT_HEIGHT_FROM_CHAR_HEIGHT(nHeight);
219
220 if (vSizeBtn.y < nHeight)
221 {
222 //
223 // Make the text tall enough
224 //
225 vSizeBtn.y = nHeight;
226 }
227 return vSizeBtn;
228 } // end of wxSpinCtrl::DoGetBestSize
229
230 void wxSpinCtrl::DoGetPosition(
231 int* pnX
232 , int* pnY
233 ) const
234 {
235 WXHWND hWnd = GetHWND();
236
237 wxConstCast(this, wxSpinCtrl)->m_hWnd = m_hWndBuddy;
238 wxSpinButton::DoGetPosition( pnX
239 ,pnY
240 );
241 wxConstCast(this, wxSpinCtrl)->m_hWnd = hWnd;
242 } // end of wxpinCtrl::DoGetPosition
243
244 void wxSpinCtrl::DoGetSize(
245 int* pnWidth
246 , int* pnHeight
247 ) const
248 {
249 RECTL vSpinrect;
250
251 ::WinQueryWindowRect(GetHwnd(), &vSpinrect);
252
253 if (pnWidth)
254 *pnWidth = vSpinrect.xRight - vSpinrect.xLeft;
255 if (pnHeight)
256 *pnHeight = vSpinrect.yTop - vSpinrect.yBottom;
257 } // end of wxSpinCtrl::DoGetSize
258
259 void wxSpinCtrl::DoMoveWindow(
260 int nX
261 , int nY
262 , int nWidth
263 , int nHeight
264 )
265 {
266 wxWindowOS2* pParent = (wxWindowOS2*)GetParent();
267
268 if (pParent)
269 {
270 int nOS2Height = GetOS2ParentHeight(pParent);
271
272 nY = nOS2Height - (nY + nHeight);
273 }
274 else
275 {
276 RECTL vRect;
277
278 ::WinQueryWindowRect(HWND_DESKTOP, &vRect);
279 nY = vRect.yTop - (nY + nHeight);
280 }
281 ::WinSetWindowPos( GetHwnd()
282 ,HWND_TOP
283 ,nX
284 ,nY
285 ,nWidth
286 ,nHeight
287 ,SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW
288 );
289 } // end of wxSpinCtrl::DoMoveWindow
290
291 bool wxSpinCtrl::Enable(
292 bool bEnable
293 )
294 {
295 if (!wxControl::Enable(bEnable))
296 {
297 return false;
298 }
299 ::WinEnableWindow(GetHwnd(), bEnable);
300 return true;
301 } // end of wxSpinCtrl::Enable
302
303 wxSpinCtrl* wxSpinCtrl::GetSpinForTextCtrl(
304 WXHWND hWndBuddy
305 )
306 {
307 wxSpinCtrl* pSpin = (wxSpinCtrl *)::WinQueryWindowULong( (HWND)hWndBuddy
308 ,QWL_USER
309 );
310 int i = m_svAllSpins.Index(pSpin);
311
312 if (i == wxNOT_FOUND)
313 return NULL;
314
315 // sanity check
316 wxASSERT_MSG( pSpin->m_hWndBuddy == hWndBuddy,
317 _T("wxSpinCtrl has incorrect buddy HWND!") );
318
319 return pSpin;
320 } // end of wxSpinCtrl::GetSpinForTextCtrl
321
322 int wxSpinCtrl::GetValue() const
323 {
324 long lVal = 0L;
325 char zVal[10];
326
327 ::WinSendMsg( GetHwnd()
328 ,SPBM_QUERYVALUE
329 ,MPFROMP(zVal)
330 ,MPFROM2SHORT( (USHORT)10
331 ,SPBQ_UPDATEIFVALID
332 )
333 );
334 lVal = atol(zVal);
335 return (int)lVal;
336 } // end of wxSpinCtrl::GetValue
337
338 void wxSpinCtrl::OnChar (
339 wxKeyEvent& rEvent
340 )
341 {
342 switch (rEvent.GetKeyCode())
343 {
344 case WXK_RETURN:
345 {
346 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_ENTER
347 ,m_windowId
348 );
349 wxString sVal = wxGetWindowText(m_hWndBuddy);
350
351 InitCommandEvent(vEvent);
352 vEvent.SetString(sVal);
353 vEvent.SetInt(GetValue());
354 if (GetEventHandler()->ProcessEvent(vEvent))
355 return;
356 break;
357 }
358
359 case WXK_TAB:
360 //
361 // Always produce navigation event - even if we process TAB
362 // ourselves the fact that we got here means that the user code
363 // decided to skip processing of this TAB - probably to let it
364 // do its default job.
365 //
366 {
367 wxNavigationKeyEvent vEventNav;
368
369 vEventNav.SetDirection(!rEvent.ShiftDown());
370 vEventNav.SetWindowChange(rEvent.ControlDown());
371 vEventNav.SetEventObject(this);
372 if (GetParent()->GetEventHandler()->ProcessEvent(vEventNav))
373 return;
374 }
375 break;
376 }
377
378 //
379 // No, we didn't process it
380 //
381 rEvent.Skip();
382 } // end of wxSpinCtrl::OnChar
383
384 void wxSpinCtrl::OnSpinChange(
385 wxSpinEvent& rEventSpin
386 )
387 {
388 wxCommandEvent vEvent( wxEVT_COMMAND_SPINCTRL_UPDATED
389 ,GetId()
390 );
391
392 vEvent.SetEventObject(this);
393 vEvent.SetInt(rEventSpin.GetPosition());
394 (void)GetEventHandler()->ProcessEvent(vEvent);
395 if (rEventSpin.GetSkipped())
396 {
397 vEvent.Skip();
398 }
399 } // end of wxSpinCtrl::OnSpinChange
400
401 void wxSpinCtrl::OnSetFocus (
402 wxFocusEvent& rEvent
403 )
404 {
405 //
406 // When we get focus, give it to our buddy window as it needs it more than
407 // we do
408 //
409 ::WinSetFocus(HWND_DESKTOP, (HWND)m_hWndBuddy);
410 rEvent.Skip();
411 } // end of wxSpinCtrl::OnSetFocus
412
413 bool wxSpinCtrl::ProcessTextCommand( WXWORD wCmd,
414 WXWORD WXUNUSED(wId) )
415 {
416 switch (wCmd)
417 {
418 case SPBN_CHANGE:
419 {
420 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED, GetId() );
421 vEvent.SetEventObject(this);
422
423 wxString sVal = wxGetWindowText(m_hWndBuddy);
424
425 vEvent.SetString(sVal);
426 vEvent.SetInt(GetValue());
427 return (GetEventHandler()->ProcessEvent(vEvent));
428 }
429
430 case SPBN_SETFOCUS:
431 case SPBN_KILLFOCUS:
432 {
433 wxFocusEvent vEvent( wCmd == EN_KILLFOCUS ? wxEVT_KILL_FOCUS : wxEVT_SET_FOCUS
434 ,m_windowId
435 );
436
437 vEvent.SetEventObject(this);
438 return(GetEventHandler()->ProcessEvent(vEvent));
439 }
440 default:
441 break;
442 }
443
444 //
445 // Not processed
446 //
447 return false;
448 } // end of wxSpinCtrl::ProcessTextCommand
449
450 void wxSpinCtrl::SetFocus()
451 {
452 ::WinSetFocus(HWND_DESKTOP, GetHwnd());
453 } // end of wxSpinCtrl::SetFocus
454
455 bool wxSpinCtrl::SetFont(
456 const wxFont& rFont
457 )
458 {
459 if (!wxWindowBase::SetFont(rFont))
460 {
461 // nothing to do
462 return false;
463 }
464
465 wxOS2SetFont( m_hWnd
466 ,rFont
467 );
468 return true;
469 } // end of wxSpinCtrl::SetFont
470
471 void wxSpinCtrl::SetValue(
472 const wxString& rsText
473 )
474 {
475 long lVal;
476
477 lVal = atol((char*)rsText.c_str());
478 wxSpinButton::SetValue(lVal);
479 } // end of wxSpinCtrl::SetValue
480
481 bool wxSpinCtrl::Show(
482 bool bShow
483 )
484 {
485 if (!wxControl::Show(bShow))
486 {
487 return false;
488 }
489 return true;
490 } // end of wxSpinCtrl::Show
491
492 void wxSpinCtrl::SetSelection (
493 long lFrom
494 , long lTo
495 )
496 {
497 //
498 // If from and to are both -1, it means (in wxWidgets) that all text should
499 // be selected - translate into Windows convention
500 //
501 if ((lFrom == -1) && (lTo == -1))
502 {
503 lFrom = 0;
504 }
505 ::WinSendMsg(m_hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), (MPARAM)0);
506 } // end of wxSpinCtrl::SetSelection
507
508 #endif //wxUSE_SPINCTRL