'Y' positioning fixes for OS/2 controls
[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 SPBCDATA vCtrlData;
155
156 vCtrlData.cbSize = sizeof(SPBCDATA);
157 vCtrlData.ulTextLimit = 10L;
158 vCtrlData.lLowerLimit = 0L;
159 vCtrlData.lUpperLimit = 100L;
160 vCtrlData.idMasterSpb = vId;
161 vCtrlData.pHWXCtlData = NULL;
162
163 m_hWnd = (WXHWND)::WinCreateWindow( GetWinHwnd(pParent)
164 ,WC_SPINBUTTON
165 ,(PSZ)NULL
166 ,lSstyle
167 ,0L, 0L, 0L, 0L
168 ,GetWinHwnd(pParent)
169 ,HWND_TOP
170 ,(HMENU)vId
171 ,(PVOID)&vCtrlData
172 ,NULL
173 );
174 if (m_hWnd == 0)
175 {
176 return FALSE;
177 }
178 m_hWndBuddy = m_hWnd; // One in the same for OS/2
179 if(pParent)
180 pParent->AddChild((wxSpinButton *)this);
181 SetFont(pParent->GetFont());
182 ::WinQueryWindowPos(m_hWnd, &vSwp);
183 SetXComp(vSwp.x);
184 SetYComp(vSwp.y);
185 SetSize( rPos.x
186 ,rPos.y
187 ,rSize.x
188 ,rSize.y
189 );
190
191 SetRange(nMin, nMax);
192 SetValue(nInitial);
193
194 //
195 // For OS/2 we'll just set our handle into our long data
196 //
197 wxAssociateWinWithHandle( m_hWnd
198 ,(wxWindowOS2*)this
199 );
200 ::WinSetWindowULong(GetHwnd(), QWL_USER, (LONG)this);
201 fnWndProcSpinCtrl = (WXFARPROC)::WinSubclassWindow(m_hWnd, (PFNWP)wxSpinCtrlWndProc);
202 m_svAllSpins.Add(this);
203 return TRUE;
204 } // end of wxSpinCtrl::Create
205
206 wxSize wxSpinCtrl::DoGetBestSize() const
207 {
208 wxSize vSizeBtn = wxSpinButton::DoGetBestSize();
209 int nHeight;
210
211 vSizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN;
212
213 wxGetCharSize( GetHWND()
214 ,NULL
215 ,&nHeight
216 ,(wxFont*)&GetFont()
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 lVal;
336 } // end of wxSpinCtrl::GetValue
337
338 void wxSpinCtrl::OnChar (
339 wxKeyEvent& rEvent
340 )
341 {
342 switch (rEvent.KeyCode())
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((char*)sVal.c_str());
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 bool wxSpinCtrl::ProcessTextCommand(
402 WXWORD wCmd
403 , WXWORD wId
404 )
405 {
406 switch (wCmd)
407 {
408 case SPBN_CHANGE:
409 {
410 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED
411 ,GetId()
412 );
413 vEvent.SetEventObject(this);
414
415 wxString sVal = wxGetWindowText(m_hWndBuddy);
416
417 vEvent.SetString((char*)sVal.c_str());
418 vEvent.SetInt(GetValue());
419 return (GetEventHandler()->ProcessEvent(vEvent));
420 }
421
422 case SPBN_SETFOCUS:
423 case SPBN_KILLFOCUS:
424 {
425 wxFocusEvent vEvent( wCmd == EN_KILLFOCUS ? wxEVT_KILL_FOCUS : wxEVT_SET_FOCUS
426 ,m_windowId
427 );
428
429 vEvent.SetEventObject(this);
430 return(GetEventHandler()->ProcessEvent(vEvent));
431 }
432 default:
433 break;
434 }
435
436 //
437 // Not processed
438 //
439 return FALSE;
440 } // end of wxSpinCtrl::ProcessTextCommand
441
442 void wxSpinCtrl::SetFocus()
443 {
444 ::WinSetFocus(HWND_DESKTOP, GetHwnd());
445 } // end of wxSpinCtrl::SetFocus
446
447 bool wxSpinCtrl::SetFont(
448 const wxFont& rFont
449 )
450 {
451 if (!wxWindowBase::SetFont(rFont))
452 {
453 // nothing to do
454 return FALSE;
455 }
456
457 WXHANDLE hFont = GetFont().GetResourceHandle();
458 wxOS2SetFont( m_hWnd
459 ,rFont
460 );
461 return TRUE;
462 } // end of wxSpinCtrl::SetFont
463
464 void wxSpinCtrl::SetValue(
465 const wxString& rsText
466 )
467 {
468 long lVal;
469
470 lVal = atol(rsText.c_str());
471 wxSpinButton::SetValue(lVal);
472 } // end of wxSpinCtrl::SetValue
473
474 bool wxSpinCtrl::Show(
475 bool bShow
476 )
477 {
478 if (!wxControl::Show(bShow))
479 {
480 return FALSE;
481 }
482 return TRUE;
483 } // end of wxSpinCtrl::Show
484
485 #endif //wxUSE_SPINBTN