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