~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to src/msw/spinctrl.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        src/msw/spinctrl.cpp
 
3
// Purpose:     wxSpinCtrl class implementation for Win32
 
4
// Author:      Vadim Zeitlin
 
5
// Modified by:
 
6
// Created:     22.07.99
 
7
// RCS-ID:      $Id: spinctrl.cpp 71640 2012-06-03 19:16:59Z VZ $
 
8
// Copyright:   (c) 1999-2005 Vadim Zeitlin
 
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
#ifdef __BORLANDC__
 
24
    #pragma hdrstop
 
25
#endif
 
26
 
 
27
#if wxUSE_SPINCTRL
 
28
 
 
29
#include "wx/spinctrl.h"
 
30
 
 
31
#ifndef WX_PRECOMP
 
32
    #include "wx/hashmap.h"
 
33
    #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
 
34
    #include "wx/event.h"
 
35
    #include "wx/textctrl.h"
 
36
    #include "wx/wxcrtvararg.h"
 
37
#endif
 
38
 
 
39
#include "wx/msw/private.h"
 
40
 
 
41
#if wxUSE_TOOLTIPS
 
42
    #include "wx/tooltip.h"
 
43
#endif // wxUSE_TOOLTIPS
 
44
 
 
45
#include <limits.h>         // for INT_MIN
 
46
 
 
47
// ----------------------------------------------------------------------------
 
48
// macros
 
49
// ----------------------------------------------------------------------------
 
50
 
 
51
BEGIN_EVENT_TABLE(wxSpinCtrl, wxSpinButton)
 
52
    EVT_CHAR(wxSpinCtrl::OnChar)
 
53
    EVT_SET_FOCUS(wxSpinCtrl::OnSetFocus)
 
54
    EVT_KILL_FOCUS(wxSpinCtrl::OnKillFocus)
 
55
END_EVENT_TABLE()
 
56
 
 
57
#define GetBuddyHwnd()      (HWND)(m_hwndBuddy)
 
58
 
 
59
// ----------------------------------------------------------------------------
 
60
// constants
 
61
// ----------------------------------------------------------------------------
 
62
 
 
63
// the margin between the up-down control and its buddy (can be arbitrary,
 
64
// choose what you like - or may be decide during run-time depending on the
 
65
// font size?)
 
66
static const int MARGIN_BETWEEN = 1;
 
67
 
 
68
 
 
69
// ---------------------------------------------------------------------------
 
70
// global vars
 
71
// ---------------------------------------------------------------------------
 
72
 
 
73
namespace
 
74
{
 
75
 
 
76
// Global hash used to find the spin control corresponding to the given buddy
 
77
// text control HWND.
 
78
WX_DECLARE_HASH_MAP(HWND, wxSpinCtrl *,
 
79
                    wxPointerHash, wxPointerEqual,
 
80
                    SpinForTextCtrl);
 
81
 
 
82
SpinForTextCtrl gs_spinForTextCtrl;
 
83
 
 
84
} // anonymous namespace
 
85
 
 
86
// ============================================================================
 
87
// implementation
 
88
// ============================================================================
 
89
 
 
90
// ----------------------------------------------------------------------------
 
91
// wnd proc for the buddy text ctrl
 
92
// ----------------------------------------------------------------------------
 
93
 
 
94
LRESULT APIENTRY _EXPORT wxBuddyTextWndProc(HWND hwnd,
 
95
                                            UINT message,
 
96
                                            WPARAM wParam,
 
97
                                            LPARAM lParam)
 
98
{
 
99
    wxSpinCtrl * const spin = wxSpinCtrl::GetSpinForTextCtrl(hwnd);
 
100
 
 
101
    // forward some messages (mostly the key and focus ones) to the spin ctrl
 
102
    switch ( message )
 
103
    {
 
104
        case WM_SETFOCUS:
 
105
            // if the focus comes from the spin control itself, don't set it
 
106
            // back to it -- we don't want to go into an infinite loop
 
107
            if ( (WXHWND)wParam == spin->GetHWND() )
 
108
                break;
 
109
            //else: fall through
 
110
 
 
111
        case WM_KILLFOCUS:
 
112
        case WM_CHAR:
 
113
        case WM_DEADCHAR:
 
114
        case WM_KEYUP:
 
115
        case WM_KEYDOWN:
 
116
#ifdef WM_HELP
 
117
        // we need to forward WM_HELP too to ensure that the context help
 
118
        // associated with wxSpinCtrl is shown when the text control part of it
 
119
        // is clicked with the "?" cursor
 
120
        case WM_HELP:
 
121
#endif
 
122
            {
 
123
                WXLRESULT result;
 
124
                if ( spin->MSWHandleMessage(&result, message, wParam, lParam) )
 
125
                {
 
126
                    // Do not let the message be processed by the window proc
 
127
                    // of the text control if it had been already handled at wx
 
128
                    // level, this is consistent with what happens for normal,
 
129
                    // non-composite controls.
 
130
                    return 0;
 
131
                }
 
132
 
 
133
                // The control may have been deleted at this point, so check.
 
134
                if ( !::IsWindow(hwnd) )
 
135
                    return 0;
 
136
            }
 
137
            break;
 
138
 
 
139
        case WM_GETDLGCODE:
 
140
            if ( spin->HasFlag(wxTE_PROCESS_ENTER) )
 
141
            {
 
142
                long dlgCode = ::CallWindowProc
 
143
                                 (
 
144
                                    CASTWNDPROC spin->GetBuddyWndProc(),
 
145
                                    hwnd,
 
146
                                    message,
 
147
                                    wParam,
 
148
                                    lParam
 
149
                                 );
 
150
                dlgCode |= DLGC_WANTMESSAGE;
 
151
                return dlgCode;
 
152
            }
 
153
            break;
 
154
    }
 
155
 
 
156
    return ::CallWindowProc(CASTWNDPROC spin->GetBuddyWndProc(),
 
157
                            hwnd, message, wParam, lParam);
 
158
}
 
159
 
 
160
/* static */
 
161
wxSpinCtrl *wxSpinCtrl::GetSpinForTextCtrl(WXHWND hwndBuddy)
 
162
{
 
163
    const SpinForTextCtrl::const_iterator
 
164
        it = gs_spinForTextCtrl.find(hwndBuddy);
 
165
    if ( it == gs_spinForTextCtrl.end() )
 
166
        return NULL;
 
167
 
 
168
    wxSpinCtrl * const spin = it->second;
 
169
 
 
170
    // sanity check
 
171
    wxASSERT_MSG( spin->m_hwndBuddy == hwndBuddy,
 
172
                  wxT("wxSpinCtrl has incorrect buddy HWND!") );
 
173
 
 
174
    return spin;
 
175
}
 
176
 
 
177
// process a WM_COMMAND generated by the buddy text control
 
178
bool wxSpinCtrl::ProcessTextCommand(WXWORD cmd, WXWORD WXUNUSED(id))
 
179
{
 
180
    if ( (cmd == EN_CHANGE) && (!m_blockEvent ))
 
181
    {
 
182
        wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
 
183
        event.SetEventObject(this);
 
184
        wxString val = wxGetWindowText(m_hwndBuddy);
 
185
        event.SetString(val);
 
186
        event.SetInt(GetValue());
 
187
        return HandleWindowEvent(event);
 
188
    }
 
189
 
 
190
    // not processed
 
191
    return false;
 
192
}
 
193
 
 
194
void wxSpinCtrl::OnChar(wxKeyEvent& event)
 
195
{
 
196
    switch ( event.GetKeyCode() )
 
197
    {
 
198
        case WXK_RETURN:
 
199
            {
 
200
                wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
 
201
                InitCommandEvent(event);
 
202
                wxString val = wxGetWindowText(m_hwndBuddy);
 
203
                event.SetString(val);
 
204
                event.SetInt(GetValue());
 
205
                if ( HandleWindowEvent(event) )
 
206
                    return;
 
207
                break;
 
208
            }
 
209
 
 
210
        case WXK_TAB:
 
211
            // always produce navigation event - even if we process TAB
 
212
            // ourselves the fact that we got here means that the user code
 
213
            // decided to skip processing of this TAB - probably to let it
 
214
            // do its default job.
 
215
            {
 
216
                wxNavigationKeyEvent eventNav;
 
217
                eventNav.SetDirection(!event.ShiftDown());
 
218
                eventNav.SetWindowChange(event.ControlDown());
 
219
                eventNav.SetEventObject(this);
 
220
 
 
221
                if ( GetParent()->HandleWindowEvent(eventNav) )
 
222
                    return;
 
223
            }
 
224
            break;
 
225
    }
 
226
 
 
227
    // no, we didn't process it
 
228
    event.Skip();
 
229
}
 
230
 
 
231
void wxSpinCtrl::OnKillFocus(wxFocusEvent& event)
 
232
{
 
233
    // ensure that a correct value is shown by the control
 
234
    NormalizeValue();
 
235
    event.Skip();
 
236
}
 
237
 
 
238
void wxSpinCtrl::OnSetFocus(wxFocusEvent& event)
 
239
{
 
240
    // when we get focus, give it to our buddy window as it needs it more than
 
241
    // we do
 
242
    ::SetFocus((HWND)m_hwndBuddy);
 
243
 
 
244
    event.Skip();
 
245
}
 
246
 
 
247
void wxSpinCtrl::NormalizeValue()
 
248
{
 
249
    const int value = GetValue();
 
250
    const bool changed = value != m_oldValue;
 
251
 
 
252
    // notice that we have to call SetValue() even if the value didn't change
 
253
    // because otherwise we could be left with empty buddy control when value
 
254
    // is 0, see comment in SetValue()
 
255
    SetValue(value);
 
256
 
 
257
    if ( changed )
 
258
    {
 
259
        SendSpinUpdate(value);
 
260
    }
 
261
}
 
262
 
 
263
// ----------------------------------------------------------------------------
 
264
// construction
 
265
// ----------------------------------------------------------------------------
 
266
 
 
267
void wxSpinCtrl::Init()
 
268
{
 
269
    m_blockEvent = false;
 
270
    m_hwndBuddy = NULL;
 
271
    m_wndProcBuddy = NULL;
 
272
    m_oldValue = INT_MIN;
 
273
}
 
274
 
 
275
bool wxSpinCtrl::Create(wxWindow *parent,
 
276
                        wxWindowID id,
 
277
                        const wxString& value,
 
278
                        const wxPoint& pos,
 
279
                        const wxSize& size,
 
280
                        long style,
 
281
                        int min, int max, int initial,
 
282
                        const wxString& name)
 
283
{
 
284
    // before using DoGetBestSize(), have to set style to let the base class
 
285
    // know whether this is a horizontal or vertical control (we're always
 
286
    // vertical)
 
287
    style |= wxSP_VERTICAL;
 
288
 
 
289
    if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT )
 
290
#ifdef __WXWINCE__
 
291
        style |= wxBORDER_SIMPLE;
 
292
#else
 
293
        style |= wxBORDER_SUNKEN;
 
294
#endif
 
295
 
 
296
    SetWindowStyle(style);
 
297
 
 
298
    WXDWORD exStyle = 0;
 
299
    WXDWORD msStyle = MSWGetStyle(GetWindowStyle(), & exStyle) ;
 
300
 
 
301
    // Scroll text automatically if there is not enough space to show all of
 
302
    // it, this is better than not allowing to enter more digits at all.
 
303
    msStyle |= ES_AUTOHSCROLL;
 
304
 
 
305
    // propagate text alignment style to text ctrl
 
306
    if ( style & wxALIGN_RIGHT )
 
307
        msStyle |= ES_RIGHT;
 
308
    else if ( style & wxALIGN_CENTER )
 
309
        msStyle |= ES_CENTER;
 
310
 
 
311
    // calculate the sizes: the size given is the total size for both controls
 
312
    // and we need to fit them both in the given width (height is the same)
 
313
    wxSize sizeText(size), sizeBtn(size);
 
314
    sizeBtn.x = wxSpinButton::DoGetBestSize().x;
 
315
    if ( sizeText.x <= 0 )
 
316
    {
 
317
        // DEFAULT_ITEM_WIDTH is the default width for the text control
 
318
        sizeText.x = DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN + sizeBtn.x;
 
319
    }
 
320
 
 
321
    sizeText.x -= sizeBtn.x + MARGIN_BETWEEN;
 
322
    if ( sizeText.x <= 0 )
 
323
    {
 
324
        wxLogDebug(wxT("not enough space for wxSpinCtrl!"));
 
325
    }
 
326
 
 
327
    wxPoint posBtn(pos);
 
328
    posBtn.x += sizeText.x + MARGIN_BETWEEN;
 
329
 
 
330
    // we must create the text control before the spin button for the purpose
 
331
    // of the dialog navigation: if there is a static text just before the spin
 
332
    // control, activating it by Alt-letter should give focus to the text
 
333
    // control, not the spin and the dialog navigation code will give focus to
 
334
    // the next control (at Windows level), not the one after it
 
335
 
 
336
    // create the text window
 
337
 
 
338
    m_hwndBuddy = (WXHWND)::CreateWindowEx
 
339
                    (
 
340
                     exStyle,                // sunken border
 
341
                     wxT("EDIT"),             // window class
 
342
                     NULL,                   // no window title
 
343
                     msStyle,                // style (will be shown later)
 
344
                     pos.x, pos.y,           // position
 
345
                     0, 0,                   // size (will be set later)
 
346
                     GetHwndOf(parent),      // parent
 
347
                     (HMENU)-1,              // control id
 
348
                     wxGetInstance(),        // app instance
 
349
                     NULL                    // unused client data
 
350
                    );
 
351
 
 
352
    if ( !m_hwndBuddy )
 
353
    {
 
354
        wxLogLastError(wxT("CreateWindow(buddy text window)"));
 
355
 
 
356
        return false;
 
357
    }
 
358
 
 
359
 
 
360
    // create the spin button
 
361
    if ( !wxSpinButton::Create(parent, id, posBtn, sizeBtn, style, name) )
 
362
    {
 
363
        return false;
 
364
    }
 
365
 
 
366
    wxSpinButtonBase::SetRange(min, max);
 
367
 
 
368
    // subclass the text ctrl to be able to intercept some events
 
369
    gs_spinForTextCtrl[GetBuddyHwnd()] = this;
 
370
 
 
371
    m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(),
 
372
                                                wxBuddyTextWndProc);
 
373
 
 
374
    // set up fonts and colours  (This is nomally done in MSWCreateControl)
 
375
    InheritAttributes();
 
376
    if (!m_hasFont)
 
377
        SetFont(GetDefaultAttributes().font);
 
378
 
 
379
    // set the size of the text window - can do it only now, because we
 
380
    // couldn't call DoGetBestSize() before as font wasn't set
 
381
    if ( sizeText.y <= 0 )
 
382
    {
 
383
        int cx, cy;
 
384
        wxGetCharSize(GetHWND(), &cx, &cy, GetFont());
 
385
 
 
386
        sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
 
387
    }
 
388
 
 
389
    SetInitialSize(size);
 
390
 
 
391
    (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW);
 
392
 
 
393
    // associate the text window with the spin button
 
394
    (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)m_hwndBuddy, 0);
 
395
 
 
396
    // If the initial text value is actually a number, it overrides the
 
397
    // "initial" argument specified later.
 
398
    long initialFromText;
 
399
    if ( value.ToLong(&initialFromText) )
 
400
        initial = initialFromText;
 
401
 
 
402
    SetValue(initial);
 
403
 
 
404
    m_oldValue = initial;
 
405
 
 
406
    // Set the range in the native control
 
407
    SetRange(min, max);
 
408
 
 
409
    // Also set the text part of the control if it was specified independently
 
410
    // but don't generate an event for this, it would be unexpected.
 
411
    m_blockEvent = true;
 
412
    if ( !value.empty() )
 
413
        SetValue(value);
 
414
    m_blockEvent = false;
 
415
 
 
416
    return true;
 
417
}
 
418
 
 
419
wxSpinCtrl::~wxSpinCtrl()
 
420
{
 
421
    // destroy the buddy window because this pointer which wxBuddyTextWndProc
 
422
    // uses will not soon be valid any more
 
423
    ::DestroyWindow( GetBuddyHwnd() );
 
424
 
 
425
    gs_spinForTextCtrl.erase(GetBuddyHwnd());
 
426
}
 
427
 
 
428
// ----------------------------------------------------------------------------
 
429
// wxTextCtrl-like methods
 
430
// ----------------------------------------------------------------------------
 
431
 
 
432
void wxSpinCtrl::SetValue(const wxString& text)
 
433
{
 
434
    if ( !::SetWindowText(GetBuddyHwnd(), text.c_str()) )
 
435
    {
 
436
        wxLogLastError(wxT("SetWindowText(buddy)"));
 
437
    }
 
438
}
 
439
 
 
440
void  wxSpinCtrl::SetValue(int val)
 
441
{
 
442
    m_blockEvent = true;
 
443
 
 
444
    wxSpinButton::SetValue(val);
 
445
 
 
446
    // normally setting the value of the spin button is enough as it updates
 
447
    // its buddy control automatically ...
 
448
    if ( wxGetWindowText(m_hwndBuddy).empty() )
 
449
    {
 
450
        // ... but sometimes it doesn't, notably when the value is 0 and the
 
451
        // text control is currently empty, the spin button seems to be happy
 
452
        // to leave it like this, while we really want to always show the
 
453
        // current value in the control, so do it manually
 
454
        ::SetWindowText(GetBuddyHwnd(),
 
455
                        wxString::Format(wxT("%d"), val).t_str());
 
456
    }
 
457
 
 
458
    m_oldValue = GetValue();
 
459
 
 
460
    m_blockEvent = false;
 
461
}
 
462
 
 
463
int wxSpinCtrl::GetValue() const
 
464
{
 
465
    wxString val = wxGetWindowText(m_hwndBuddy);
 
466
 
 
467
    long n;
 
468
    if ( (wxSscanf(val, wxT("%ld"), &n) != 1) )
 
469
        n = INT_MIN;
 
470
 
 
471
    if ( n < m_min )
 
472
        n = m_min;
 
473
    if ( n > m_max )
 
474
        n = m_max;
 
475
 
 
476
    return n;
 
477
}
 
478
 
 
479
void wxSpinCtrl::SetSelection(long from, long to)
 
480
{
 
481
    // if from and to are both -1, it means (in wxWidgets) that all text should
 
482
    // be selected - translate into Windows convention
 
483
    if ( (from == -1) && (to == -1) )
 
484
    {
 
485
        from = 0;
 
486
    }
 
487
 
 
488
    ::SendMessage(GetBuddyHwnd(), EM_SETSEL, (WPARAM)from, (LPARAM)to);
 
489
}
 
490
 
 
491
// ----------------------------------------------------------------------------
 
492
// wxSpinButton methods
 
493
// ----------------------------------------------------------------------------
 
494
 
 
495
void wxSpinCtrl::SetRange(int minVal, int maxVal)
 
496
{
 
497
    wxSpinButton::SetRange(minVal, maxVal);
 
498
 
 
499
    // this control is used for numeric entry so restrict the input to numeric
 
500
    // keys only -- but only if we don't need to be able to enter "-" in it as
 
501
    // otherwise this would become impossible
 
502
    const DWORD styleOld = ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE);
 
503
    DWORD styleNew;
 
504
    if ( minVal < 0 )
 
505
        styleNew = styleOld & ~ES_NUMBER;
 
506
    else
 
507
        styleNew = styleOld | ES_NUMBER;
 
508
 
 
509
    if ( styleNew != styleOld )
 
510
        ::SetWindowLong(GetBuddyHwnd(), GWL_STYLE, styleNew);
 
511
}
 
512
 
 
513
// ----------------------------------------------------------------------------
 
514
// forward some methods to subcontrols
 
515
// ----------------------------------------------------------------------------
 
516
 
 
517
bool wxSpinCtrl::SetFont(const wxFont& font)
 
518
{
 
519
    if ( !wxWindowBase::SetFont(font) )
 
520
    {
 
521
        // nothing to do
 
522
        return false;
 
523
    }
 
524
 
 
525
    WXHANDLE hFont = GetFont().GetResourceHandle();
 
526
    (void)::SendMessage(GetBuddyHwnd(), WM_SETFONT, (WPARAM)hFont, TRUE);
 
527
 
 
528
    return true;
 
529
}
 
530
 
 
531
bool wxSpinCtrl::Show(bool show)
 
532
{
 
533
    if ( !wxControl::Show(show) )
 
534
    {
 
535
        return false;
 
536
    }
 
537
 
 
538
    ::ShowWindow(GetBuddyHwnd(), show ? SW_SHOW : SW_HIDE);
 
539
 
 
540
    return true;
 
541
}
 
542
 
 
543
bool wxSpinCtrl::Reparent(wxWindowBase *newParent)
 
544
{
 
545
    // Reparenting both the updown control and its buddy does not seem to work:
 
546
    // they continue to be connected somehow, but visually there is no feedback
 
547
    // on the buddy edit control. To avoid this problem, we reparent the buddy
 
548
    // window normally, but we recreate the updown control and reassign its
 
549
    // buddy.
 
550
 
 
551
    // Get the position before changing the parent as it would be offset after
 
552
    // changing it.
 
553
    const wxRect rect = GetRect();
 
554
 
 
555
    if ( !wxWindowBase::Reparent(newParent) )
 
556
        return false;
 
557
 
 
558
    newParent->GetChildren().DeleteObject(this);
 
559
 
 
560
    // destroy the old spin button after detaching it from this wxWindow object
 
561
    // (notice that m_hWnd will be reset by UnsubclassWin() so save it first)
 
562
    const HWND hwndOld = GetHwnd();
 
563
    UnsubclassWin();
 
564
    if ( !::DestroyWindow(hwndOld) )
 
565
    {
 
566
        wxLogLastError(wxT("DestroyWindow"));
 
567
    }
 
568
 
 
569
    // create and initialize the new one
 
570
    if ( !wxSpinButton::Create(GetParent(), GetId(),
 
571
                               rect.GetPosition(), rect.GetSize(),
 
572
                               GetWindowStyle(), GetName()) )
 
573
        return false;
 
574
 
 
575
    // reapply our values to wxSpinButton
 
576
    wxSpinButton::SetValue(GetValue());
 
577
    SetRange(m_min, m_max);
 
578
 
 
579
    // also set the size again with wxSIZE_ALLOW_MINUS_ONE flag: this is
 
580
    // necessary if our original position used -1 for either x or y
 
581
    SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
 
582
 
 
583
    // associate it with the buddy control again
 
584
    ::SetParent(GetBuddyHwnd(), GetHwndOf(GetParent()));
 
585
    (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)GetBuddyHwnd(), 0);
 
586
 
 
587
    return true;
 
588
}
 
589
 
 
590
bool wxSpinCtrl::Enable(bool enable)
 
591
{
 
592
    if ( !wxControl::Enable(enable) )
 
593
    {
 
594
        return false;
 
595
    }
 
596
 
 
597
    MSWEnableHWND(GetBuddyHwnd(), enable);
 
598
 
 
599
    return true;
 
600
}
 
601
 
 
602
void wxSpinCtrl::SetFocus()
 
603
{
 
604
    ::SetFocus(GetBuddyHwnd());
 
605
}
 
606
 
 
607
#if wxUSE_TOOLTIPS
 
608
 
 
609
void wxSpinCtrl::DoSetToolTip(wxToolTip *tip)
 
610
{
 
611
    wxSpinButton::DoSetToolTip(tip);
 
612
 
 
613
    if ( tip )
 
614
        tip->AddOtherWindow(m_hwndBuddy);
 
615
}
 
616
 
 
617
#endif // wxUSE_TOOLTIPS
 
618
 
 
619
// ----------------------------------------------------------------------------
 
620
// events processing and generation
 
621
// ----------------------------------------------------------------------------
 
622
 
 
623
void wxSpinCtrl::SendSpinUpdate(int value)
 
624
{
 
625
    wxCommandEvent event(wxEVT_COMMAND_SPINCTRL_UPDATED, GetId());
 
626
    event.SetEventObject(this);
 
627
    event.SetInt(value);
 
628
 
 
629
    (void)HandleWindowEvent(event);
 
630
 
 
631
    m_oldValue = value;
 
632
}
 
633
 
 
634
bool wxSpinCtrl::MSWOnScroll(int WXUNUSED(orientation), WXWORD wParam,
 
635
                               WXWORD pos, WXHWND control)
 
636
{
 
637
    wxCHECK_MSG( control, false, wxT("scrolling what?") );
 
638
 
 
639
    if ( wParam != SB_THUMBPOSITION )
 
640
    {
 
641
        // probable SB_ENDSCROLL - we don't react to it
 
642
        return false;
 
643
    }
 
644
 
 
645
    int new_value = (short) pos;
 
646
    if (m_oldValue != new_value)
 
647
       SendSpinUpdate( new_value );
 
648
 
 
649
    return TRUE;
 
650
}
 
651
 
 
652
bool wxSpinCtrl::MSWOnNotify(int WXUNUSED(idCtrl), WXLPARAM lParam, WXLPARAM *result)
 
653
{
 
654
    NM_UPDOWN *lpnmud = (NM_UPDOWN *)lParam;
 
655
 
 
656
    if (lpnmud->hdr.hwndFrom != GetHwnd()) // make sure it is the right control
 
657
        return false;
 
658
 
 
659
    *result = 0;  // never reject UP and DOWN events
 
660
 
 
661
    return TRUE;
 
662
}
 
663
 
 
664
 
 
665
// ----------------------------------------------------------------------------
 
666
// size calculations
 
667
// ----------------------------------------------------------------------------
 
668
 
 
669
wxSize wxSpinCtrl::DoGetBestSize() const
 
670
{
 
671
    wxSize sizeBtn = wxSpinButton::DoGetBestSize();
 
672
    sizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN;
 
673
 
 
674
    int y;
 
675
    wxGetCharSize(GetHWND(), NULL, &y, GetFont());
 
676
    y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(y);
 
677
 
 
678
    // JACS: we should always use the height calculated
 
679
    // from above, because otherwise we'll get a spin control
 
680
    // that's too big. So never use the height calculated
 
681
    // from wxSpinButton::DoGetBestSize().
 
682
 
 
683
    // if ( sizeBtn.y < y )
 
684
    {
 
685
        // make the text tall enough
 
686
        sizeBtn.y = y;
 
687
    }
 
688
 
 
689
    return sizeBtn;
 
690
}
 
691
 
 
692
void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
 
693
{
 
694
    int widthBtn = wxSpinButton::DoGetBestSize().x;
 
695
    int widthText = width - widthBtn - MARGIN_BETWEEN;
 
696
    if ( widthText <= 0 )
 
697
    {
 
698
        wxLogDebug(wxT("not enough space for wxSpinCtrl!"));
 
699
    }
 
700
 
 
701
    // 1) The buddy window
 
702
    DoMoveSibling(m_hwndBuddy, x, y, widthText, height);
 
703
 
 
704
    // 2) The button window
 
705
    x += widthText + MARGIN_BETWEEN;
 
706
    wxSpinButton::DoMoveWindow(x, y, widthBtn, height);
 
707
}
 
708
 
 
709
// get total size of the control
 
710
void wxSpinCtrl::DoGetSize(int *x, int *y) const
 
711
{
 
712
    RECT spinrect, textrect, ctrlrect;
 
713
    GetWindowRect(GetHwnd(), &spinrect);
 
714
    GetWindowRect(GetBuddyHwnd(), &textrect);
 
715
    UnionRect(&ctrlrect,&textrect, &spinrect);
 
716
 
 
717
    if ( x )
 
718
        *x = ctrlrect.right - ctrlrect.left;
 
719
    if ( y )
 
720
        *y = ctrlrect.bottom - ctrlrect.top;
 
721
}
 
722
 
 
723
void wxSpinCtrl::DoGetClientSize(int *x, int *y) const
 
724
{
 
725
    RECT spinrect = wxGetClientRect(GetHwnd());
 
726
    RECT textrect = wxGetClientRect(GetBuddyHwnd());
 
727
    RECT ctrlrect;
 
728
    UnionRect(&ctrlrect,&textrect, &spinrect);
 
729
 
 
730
    if ( x )
 
731
        *x = ctrlrect.right - ctrlrect.left;
 
732
    if ( y )
 
733
        *y = ctrlrect.bottom - ctrlrect.top;
 
734
}
 
735
 
 
736
void wxSpinCtrl::DoGetPosition(int *x, int *y) const
 
737
{
 
738
    // hack: pretend that our HWND is the text control just for a moment
 
739
    WXHWND hWnd = GetHWND();
 
740
    wxConstCast(this, wxSpinCtrl)->m_hWnd = m_hwndBuddy;
 
741
 
 
742
    wxSpinButton::DoGetPosition(x, y);
 
743
 
 
744
    wxConstCast(this, wxSpinCtrl)->m_hWnd = hWnd;
 
745
}
 
746
 
 
747
#endif // wxUSE_SPINCTRL