Fixed a linking problem as some virtuals and static not properly defined
[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 if (vId == -1)
133 m_windowId = NewControlId();
134 else
135 m_windowId = vId;
136 m_backgroundColour = pParent->GetBackgroundColour();
137 m_foregroundColour = pParent->GetForegroundColour();
138 SetName(rsName);
139 SetParent(pParent);
140 m_windowStyle = lStyle;
141
142 int lSstyle = 0L;
143
144 lSstyle = WS_VISIBLE |
145 WS_TABSTOP |
146 SPBS_MASTER | // We use only single field spin buttons
147 SPBS_NUMERICONLY; // We default to numeric data
148
149 if (m_windowStyle & wxCLIP_SIBLINGS )
150 lSstyle |= WS_CLIPSIBLINGS;
151
152 SPBCDATA vCtrlData;
153
154 vCtrlData.cbSize = sizeof(SPBCDATA);
155 vCtrlData.ulTextLimit = 10L;
156 vCtrlData.lLowerLimit = 0L;
157 vCtrlData.lUpperLimit = 100L;
158 vCtrlData.idMasterSpb = vId;
159 vCtrlData.pHWXCtlData = NULL;
160
161 m_hWnd = (WXHWND)::WinCreateWindow( GetWinHwnd(pParent)
162 ,WC_SPINBUTTON
163 ,(PSZ)NULL
164 ,lSstyle
165 ,0L, 0L, 0L, 0L
166 ,GetWinHwnd(pParent)
167 ,HWND_TOP
168 ,(HMENU)vId
169 ,(PVOID)&vCtrlData
170 ,NULL
171 );
172 if (m_hWnd == 0)
173 {
174 return FALSE;
175 }
176 m_hWndBuddy = m_hWnd; // One in the same for OS/2
177 if(pParent)
178 pParent->AddChild((wxSpinButton *)this);
179 SetFont(pParent->GetFont());
180 SetSize( rPos.x
181 ,rPos.y
182 ,rSize.x
183 ,rSize.y
184 );
185
186 SetRange(nMin, nMax);
187 SetValue(nInitial);
188
189 //
190 // For OS/2 we'll just set our handle into our long data
191 //
192 wxAssociateWinWithHandle( m_hWnd
193 ,(wxWindowOS2*)this
194 );
195 ::WinSetWindowULong(GetHwnd(), QWL_USER, (LONG)this);
196 fnWndProcSpinCtrl = (WXFARPROC)::WinSubclassWindow(m_hWnd, (PFNWP)wxSpinCtrlWndProc);
197 m_svAllSpins.Add(this);
198 return TRUE;
199 } // end of wxSpinCtrl::Create
200
201 wxSize wxSpinCtrl::DoGetBestSize() const
202 {
203 wxSize vSizeBtn = wxSpinButton::DoGetBestSize();
204 int nHeight;
205
206 vSizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN;
207
208 wxGetCharSize( GetHWND()
209 ,NULL
210 ,&nHeight
211 ,(wxFont*)&GetFont()
212 );
213 nHeight = EDIT_HEIGHT_FROM_CHAR_HEIGHT(nHeight);
214
215 if (vSizeBtn.y < nHeight)
216 {
217 //
218 // Make the text tall enough
219 //
220 vSizeBtn.y = nHeight;
221 }
222 return vSizeBtn;
223 } // end of wxSpinCtrl::DoGetBestSize
224
225 void wxSpinCtrl::DoGetPosition(
226 int* pnX
227 , int* pnY
228 ) const
229 {
230 WXHWND hWnd = GetHWND();
231
232 wxConstCast(this, wxSpinCtrl)->m_hWnd = m_hWndBuddy;
233 wxSpinButton::DoGetPosition( pnX
234 ,pnY
235 );
236 wxConstCast(this, wxSpinCtrl)->m_hWnd = hWnd;
237 } // end of wxpinCtrl::DoGetPosition
238
239 void wxSpinCtrl::DoGetSize(
240 int* pnWidth
241 , int* pnHeight
242 ) const
243 {
244 RECTL vSpinrect;
245
246 ::WinQueryWindowRect(GetHwnd(), &vSpinrect);
247
248 if (pnWidth)
249 *pnWidth = vSpinrect.xRight - vSpinrect.xLeft;
250 if (pnHeight)
251 *pnHeight = vSpinrect.yTop - vSpinrect.yBottom;
252 } // end of wxSpinCtrl::DoGetSize
253
254 void wxSpinCtrl::DoMoveWindow(
255 int nX
256 , int nY
257 , int nWidth
258 , int nHeight
259 )
260 {
261 wxWindowOS2* pParent = (wxWindowOS2*)GetParent();
262
263 if (pParent)
264 {
265 if (pParent->IsKindOf(CLASSINFO(wxFrame)))
266 {
267 nY = pParent->GetClientSize().y - (nY + nHeight);
268 }
269 else
270 nY = pParent->GetSize().y - (nY + nHeight);
271 }
272 else
273 {
274 RECTL vRect;
275
276 ::WinQueryWindowRect(HWND_DESKTOP, &vRect);
277 nY = vRect.yTop - (nY + nHeight);
278 }
279 ::WinSetWindowPos( GetHwnd()
280 ,HWND_TOP
281 ,nX
282 ,nY
283 ,nWidth
284 ,nHeight
285 ,SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW
286 );
287 } // end of wxSpinCtrl::DoMoveWindow
288
289 bool wxSpinCtrl::Enable(
290 bool bEnable
291 )
292 {
293 if (!wxControl::Enable(bEnable))
294 {
295 return FALSE;
296 }
297 ::WinEnableWindow(GetHwnd(), bEnable);
298 return TRUE;
299 } // end of wxSpinCtrl::Enable
300
301 wxSpinCtrl* wxSpinCtrl::GetSpinForTextCtrl(
302 WXHWND hWndBuddy
303 )
304 {
305 wxSpinCtrl* pSpin = (wxSpinCtrl *)::WinQueryWindowULong( (HWND)hWndBuddy
306 ,QWL_USER
307 );
308 int i = m_svAllSpins.Index(pSpin);
309
310 if (i == wxNOT_FOUND)
311 return NULL;
312
313 // sanity check
314 wxASSERT_MSG( pSpin->m_hWndBuddy == hWndBuddy,
315 _T("wxSpinCtrl has incorrect buddy HWND!") );
316
317 return pSpin;
318 } // end of wxSpinCtrl::GetSpinForTextCtrl
319
320 int wxSpinCtrl::GetValue() const
321 {
322 long lVal = 0L;
323 char zVal[10];
324
325 ::WinSendMsg( GetHwnd()
326 ,SPBM_QUERYVALUE
327 ,MPFROMP(zVal)
328 ,MPFROM2SHORT( (USHORT)10
329 ,SPBQ_UPDATEIFVALID
330 )
331 );
332 lVal - atol(zVal);
333 return lVal;
334 } // end of wxSpinCtrl::GetValue
335
336 void wxSpinCtrl::OnChar (
337 wxKeyEvent& rEvent
338 )
339 {
340 switch (rEvent.KeyCode())
341 {
342 case WXK_RETURN:
343 {
344 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_ENTER
345 ,m_windowId
346 );
347 wxString sVal = wxGetWindowText(m_hWndBuddy);
348
349 InitCommandEvent(vEvent);
350 vEvent.SetString((char*)sVal.c_str());
351 vEvent.SetInt(GetValue());
352 if (GetEventHandler()->ProcessEvent(vEvent))
353 return;
354 break;
355 }
356
357 case WXK_TAB:
358 //
359 // Always produce navigation event - even if we process TAB
360 // ourselves the fact that we got here means that the user code
361 // decided to skip processing of this TAB - probably to let it
362 // do its default job.
363 //
364 {
365 wxNavigationKeyEvent vEventNav;
366
367 vEventNav.SetDirection(!rEvent.ShiftDown());
368 vEventNav.SetWindowChange(rEvent.ControlDown());
369 vEventNav.SetEventObject(this);
370 if (GetParent()->GetEventHandler()->ProcessEvent(vEventNav))
371 return;
372 }
373 break;
374 }
375
376 //
377 // No, we didn't process it
378 //
379 rEvent.Skip();
380 } // end of wxSpinCtrl::OnChar
381
382 void wxSpinCtrl::OnSpinChange(
383 wxSpinEvent& rEventSpin
384 )
385 {
386 wxCommandEvent vEvent( wxEVT_COMMAND_SPINCTRL_UPDATED
387 ,GetId()
388 );
389
390 vEvent.SetEventObject(this);
391 vEvent.SetInt(rEventSpin.GetPosition());
392 (void)GetEventHandler()->ProcessEvent(vEvent);
393 if (rEventSpin.GetSkipped())
394 {
395 vEvent.Skip();
396 }
397 } // end of wxSpinCtrl::OnSpinChange
398
399 bool wxSpinCtrl::ProcessTextCommand(
400 WXWORD wCmd
401 , WXWORD wId
402 )
403 {
404 switch (wCmd)
405 {
406 case SPBN_CHANGE:
407 {
408 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED
409 ,GetId()
410 );
411 vEvent.SetEventObject(this);
412
413 wxString sVal = wxGetWindowText(m_hWndBuddy);
414
415 vEvent.SetString((char*)sVal.c_str());
416 vEvent.SetInt(GetValue());
417 return (GetEventHandler()->ProcessEvent(vEvent));
418 }
419
420 case SPBN_SETFOCUS:
421 case SPBN_KILLFOCUS:
422 {
423 wxFocusEvent vEvent( wCmd == EN_KILLFOCUS ? wxEVT_KILL_FOCUS : wxEVT_SET_FOCUS
424 ,m_windowId
425 );
426
427 vEvent.SetEventObject(this);
428 return(GetEventHandler()->ProcessEvent(vEvent));
429 }
430 default:
431 break;
432 }
433
434 //
435 // Not processed
436 //
437 return FALSE;
438 } // end of wxSpinCtrl::ProcessTextCommand
439
440 void wxSpinCtrl::SetFocus()
441 {
442 ::WinSetFocus(HWND_DESKTOP, GetHwnd());
443 } // end of wxSpinCtrl::SetFocus
444
445 bool wxSpinCtrl::SetFont(
446 const wxFont& rFont
447 )
448 {
449 if (!wxWindowBase::SetFont(rFont))
450 {
451 // nothing to do
452 return FALSE;
453 }
454
455 WXHANDLE hFont = GetFont().GetResourceHandle();
456 wxOS2SetFont( m_hWnd
457 ,rFont
458 );
459 return TRUE;
460 } // end of wxSpinCtrl::SetFont
461
462 void wxSpinCtrl::SetValue(
463 const wxString& rsText
464 )
465 {
466 long lVal;
467
468 lVal = atol(rsText.c_str());
469 wxSpinButton::SetValue(lVal);
470 } // end of wxSpinCtrl::SetValue
471
472 bool wxSpinCtrl::Show(
473 bool bShow
474 )
475 {
476 if (!wxControl::Show(bShow))
477 {
478 return FALSE;
479 }
480 return TRUE;
481 } // end of wxSpinCtrl::Show
482
483 #endif //wxUSE_SPINBTN