Sizing fixes according to patch #1523304.
[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
175 SetFont(*wxSMALL_FONT);
176 SetXComp(0);
177 SetYComp(0);
178 SetSize( rPos.x
179 ,rPos.y
180 ,rSize.x
181 ,rSize.y
182 );
183
184 SetRange(nMin, nMax);
185 SetValue(nInitial);
186
187 //
188 // For OS/2 we'll just set our handle into our long data
189 //
190 wxAssociateWinWithHandle( m_hWnd
191 ,(wxWindowOS2*)this
192 );
193 ::WinSetWindowULong(GetHwnd(), QWL_USER, (LONG)this);
194 fnWndProcSpinCtrl = (WXFARPROC)::WinSubclassWindow(m_hWnd, (PFNWP)wxSpinCtrlWndProc);
195 m_svAllSpins.Add(this);
196 return true;
197 } // end of wxSpinCtrl::Create
198
199 wxSize wxSpinCtrl::DoGetBestSize() const
200 {
201 wxSize vSizeBtn = wxSpinButton::DoGetBestSize();
202 int nHeight;
203 wxFont vFont = (wxFont)GetFont();
204
205 vSizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN;
206
207 wxGetCharSize( GetHWND()
208 ,NULL
209 ,&nHeight
210 ,&vFont
211 );
212 nHeight = EDIT_HEIGHT_FROM_CHAR_HEIGHT(nHeight)+4;
213
214 if (vSizeBtn.y < nHeight)
215 {
216 //
217 // Make the text tall enough
218 //
219 vSizeBtn.y = nHeight;
220 }
221 return vSizeBtn;
222 } // end of wxSpinCtrl::DoGetBestSize
223
224 void wxSpinCtrl::DoGetPosition(
225 int* pnX
226 , int* pnY
227 ) const
228 {
229 wxSpinButton::DoGetPosition( pnX,pnY );
230 } // end of wxpinCtrl::DoGetPosition
231
232 void wxSpinCtrl::DoGetSize(
233 int* pnWidth
234 , int* pnHeight
235 ) const
236 {
237 RECTL vSpinrect;
238
239 ::WinQueryWindowRect(GetHwnd(), &vSpinrect);
240
241 if (pnWidth)
242 *pnWidth = vSpinrect.xRight - vSpinrect.xLeft;
243 if (pnHeight)
244 *pnHeight = vSpinrect.yTop - vSpinrect.yBottom;
245 } // end of wxSpinCtrl::DoGetSize
246
247 void wxSpinCtrl::DoMoveWindow(
248 int nX
249 , int nY
250 , int nWidth
251 , int nHeight
252 )
253 {
254 wxWindowOS2* pParent = (wxWindowOS2*)GetParent();
255
256 if (pParent)
257 {
258 int nOS2Height = GetOS2ParentHeight(pParent);
259
260 nY = nOS2Height - (nY + nHeight);
261 }
262 else
263 {
264 RECTL vRect;
265
266 ::WinQueryWindowRect(HWND_DESKTOP, &vRect);
267 nY = vRect.yTop - (nY + nHeight);
268 }
269 ::WinSetWindowPos( GetHwnd()
270 ,HWND_TOP
271 ,nX
272 ,nY
273 ,nWidth
274 ,nHeight
275 ,SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_SHOW
276 );
277 } // end of wxSpinCtrl::DoMoveWindow
278
279 bool wxSpinCtrl::Enable(
280 bool bEnable
281 )
282 {
283 if (!wxControl::Enable(bEnable))
284 {
285 return false;
286 }
287 ::WinEnableWindow(GetHwnd(), bEnable);
288 return true;
289 } // end of wxSpinCtrl::Enable
290
291 wxSpinCtrl* wxSpinCtrl::GetSpinForTextCtrl(
292 WXHWND hWndBuddy
293 )
294 {
295 wxSpinCtrl* pSpin = (wxSpinCtrl *)::WinQueryWindowULong( (HWND)hWndBuddy
296 ,QWL_USER
297 );
298 int i = m_svAllSpins.Index(pSpin);
299
300 if (i == wxNOT_FOUND)
301 return NULL;
302
303 // sanity check
304 wxASSERT_MSG( pSpin->m_hWndBuddy == hWndBuddy,
305 _T("wxSpinCtrl has incorrect buddy HWND!") );
306
307 return pSpin;
308 } // end of wxSpinCtrl::GetSpinForTextCtrl
309
310 int wxSpinCtrl::GetValue() const
311 {
312 long lVal = 0L;
313 char zVal[10];
314
315 ::WinSendMsg( GetHwnd()
316 ,SPBM_QUERYVALUE
317 ,MPFROMP(zVal)
318 ,MPFROM2SHORT( (USHORT)10
319 ,SPBQ_UPDATEIFVALID
320 )
321 );
322 lVal = atol(zVal);
323 return (int)lVal;
324 } // end of wxSpinCtrl::GetValue
325
326 void wxSpinCtrl::OnChar (
327 wxKeyEvent& rEvent
328 )
329 {
330 switch (rEvent.GetKeyCode())
331 {
332 case WXK_RETURN:
333 {
334 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_ENTER
335 ,m_windowId
336 );
337 wxString sVal = wxGetWindowText(m_hWndBuddy);
338
339 InitCommandEvent(vEvent);
340 vEvent.SetString(sVal);
341 vEvent.SetInt(GetValue());
342 if (GetEventHandler()->ProcessEvent(vEvent))
343 return;
344 break;
345 }
346
347 case WXK_TAB:
348 //
349 // Always produce navigation event - even if we process TAB
350 // ourselves the fact that we got here means that the user code
351 // decided to skip processing of this TAB - probably to let it
352 // do its default job.
353 //
354 {
355 wxNavigationKeyEvent vEventNav;
356
357 vEventNav.SetDirection(!rEvent.ShiftDown());
358 vEventNav.SetWindowChange(rEvent.ControlDown());
359 vEventNav.SetEventObject(this);
360 if (GetParent()->GetEventHandler()->ProcessEvent(vEventNav))
361 return;
362 }
363 break;
364 }
365
366 //
367 // No, we didn't process it
368 //
369 rEvent.Skip();
370 } // end of wxSpinCtrl::OnChar
371
372 void wxSpinCtrl::OnSpinChange(
373 wxSpinEvent& rEventSpin
374 )
375 {
376 wxCommandEvent vEvent( wxEVT_COMMAND_SPINCTRL_UPDATED
377 ,GetId()
378 );
379
380 vEvent.SetEventObject(this);
381 vEvent.SetInt(rEventSpin.GetPosition());
382 (void)GetEventHandler()->ProcessEvent(vEvent);
383 if (rEventSpin.GetSkipped())
384 {
385 vEvent.Skip();
386 }
387 } // end of wxSpinCtrl::OnSpinChange
388
389 void wxSpinCtrl::OnSetFocus (
390 wxFocusEvent& rEvent
391 )
392 {
393 //
394 // When we get focus, give it to our buddy window as it needs it more than
395 // we do
396 //
397 ::WinSetFocus(HWND_DESKTOP, (HWND)m_hWndBuddy);
398 rEvent.Skip();
399 } // end of wxSpinCtrl::OnSetFocus
400
401 bool wxSpinCtrl::ProcessTextCommand( WXWORD wCmd,
402 WXWORD WXUNUSED(wId) )
403 {
404 switch (wCmd)
405 {
406 case SPBN_CHANGE:
407 {
408 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED, GetId() );
409 vEvent.SetEventObject(this);
410
411 wxString sVal = wxGetWindowText(m_hWndBuddy);
412
413 vEvent.SetString(sVal);
414 vEvent.SetInt(GetValue());
415 return (GetEventHandler()->ProcessEvent(vEvent));
416 }
417
418 case SPBN_SETFOCUS:
419 case SPBN_KILLFOCUS:
420 {
421 wxFocusEvent vEvent( wCmd == EN_KILLFOCUS ? wxEVT_KILL_FOCUS : wxEVT_SET_FOCUS
422 ,m_windowId
423 );
424
425 vEvent.SetEventObject(this);
426 return(GetEventHandler()->ProcessEvent(vEvent));
427 }
428 default:
429 break;
430 }
431
432 //
433 // Not processed
434 //
435 return false;
436 } // end of wxSpinCtrl::ProcessTextCommand
437
438 void wxSpinCtrl::SetFocus()
439 {
440 ::WinSetFocus(HWND_DESKTOP, GetHwnd());
441 } // end of wxSpinCtrl::SetFocus
442
443 bool wxSpinCtrl::SetFont(
444 const wxFont& rFont
445 )
446 {
447 if (!wxWindowBase::SetFont(rFont))
448 {
449 // nothing to do
450 return false;
451 }
452
453 wxOS2SetFont( m_hWnd
454 ,rFont
455 );
456 return true;
457 } // end of wxSpinCtrl::SetFont
458
459 void wxSpinCtrl::SetValue(
460 const wxString& rsText
461 )
462 {
463 long lVal;
464
465 lVal = atol((char*)rsText.c_str());
466 wxSpinButton::SetValue(lVal);
467 } // end of wxSpinCtrl::SetValue
468
469 bool wxSpinCtrl::Show(
470 bool bShow
471 )
472 {
473 if (!wxControl::Show(bShow))
474 {
475 return false;
476 }
477 return true;
478 } // end of wxSpinCtrl::Show
479
480 void wxSpinCtrl::SetSelection (
481 long lFrom
482 , long lTo
483 )
484 {
485 //
486 // If from and to are both -1, it means (in wxWidgets) that all text should
487 // be selected - translate into Windows convention
488 //
489 if ((lFrom == -1) && (lTo == -1))
490 {
491 lFrom = 0;
492 }
493 ::WinSendMsg(m_hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), (MPARAM)0);
494 } // end of wxSpinCtrl::SetSelection
495
496 #endif //wxUSE_SPINCTRL