]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/timectrl.cpp
Rename src/generic/timectrl.cpp to timectrlg.cpp.
[wxWidgets.git] / src / generic / timectrl.cpp
diff --git a/src/generic/timectrl.cpp b/src/generic/timectrl.cpp
deleted file mode 100644 (file)
index b3d0e5a..0000000
+++ /dev/null
@@ -1,668 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// Name:        src/generic/timectrl.cpp
-// Purpose:     Generic implementation of wxTimePickerCtrl.
-// Author:      Paul Breen, Vadim Zeitlin
-// Created:     2011-09-22
-// RCS-ID:      $Id: wxhead.cpp,v 1.11 2010-04-22 12:44:51 zeitlin Exp $
-// Copyright:   (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
-// Licence:     wxWindows licence
-///////////////////////////////////////////////////////////////////////////////
-
-// ============================================================================
-// declarations
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// headers
-// ----------------------------------------------------------------------------
-
-// for compilers that support precompilation, includes "wx.h".
-#include "wx/wxprec.h"
-
-#ifdef __BORLANDC__
-    #pragma hdrstop
-#endif
-
-#if wxUSE_TIMEPICKCTRL
-
-#ifndef WX_PRECOMP
-    #include "wx/textctrl.h"
-#endif // WX_PRECOMP
-
-#include "wx/timectrl.h"
-
-// This class is only compiled if there is no native version or if we
-// explicitly want to use both the native and generic one (this is useful for
-// testing but not much otherwise and so by default we don't use the generic
-// implementation if a native one is available).
-#if !defined(wxHAS_NATIVE_TIMEPICKERCTRL) || wxUSE_TIMEPICKCTRL_GENERIC
-
-#include "wx/generic/timectrl.h"
-
-#include "wx/dateevt.h"
-#include "wx/spinbutt.h"
-
-#ifndef wxHAS_NATIVE_TIMEPICKERCTRL
-    IMPLEMENT_DYNAMIC_CLASS(wxTimePickerCtrl, wxControl)
-#endif
-
-// ----------------------------------------------------------------------------
-// Constants
-// ----------------------------------------------------------------------------
-
-enum
-{
-    // Horizontal margin between the text and spin control.
-    HMARGIN_TEXT_SPIN = 2
-};
-
-// ----------------------------------------------------------------------------
-// wxTimePickerGenericImpl: used to implement wxTimePickerCtrlGeneric
-// ----------------------------------------------------------------------------
-
-class wxTimePickerGenericImpl : public wxEvtHandler
-{
-public:
-    wxTimePickerGenericImpl(wxTimePickerCtrlGeneric* ctrl)
-    {
-        m_text = new wxTextCtrl(ctrl, wxID_ANY, wxString());
-
-        // As this text can't be edited, don't use the standard cursor for it
-        // to avoid misleading the user. Ideally we'd also hide the caret but
-        // this is not currently supported by wxTextCtrl.
-        m_text->SetCursor(wxCURSOR_ARROW);
-
-        m_btn = new wxSpinButton(ctrl, wxID_ANY,
-                                 wxDefaultPosition, wxDefaultSize,
-                                 wxSP_VERTICAL | wxSP_WRAP);
-
-        m_currentField = Field_Hour;
-        m_isFirstDigit = true;
-
-        // We don't support arbitrary formats currently as this requires
-        // significantly more work both here and also in wxLocale::GetInfo().
-        //
-        // For now just use either "%H:%M:%S" or "%I:%M:%S %p". It would be
-        // nice to add support to "%k" and "%l" (hours with leading blanks
-        // instead of zeros) too as this is the most common unsupported case in
-        // practice.
-        m_useAMPM = wxLocale::GetInfo(wxLOCALE_TIME_FMT).Contains("%p");
-
-        m_text->Connect
-                (
-                    wxEVT_SET_FOCUS,
-                    wxFocusEventHandler(wxTimePickerGenericImpl::OnTextSetFocus),
-                    NULL,
-                    this
-                );
-        m_text->Connect
-                (
-                    wxEVT_KEY_DOWN,
-                    wxKeyEventHandler(wxTimePickerGenericImpl::OnTextKeyDown),
-                    NULL,
-                    this
-                );
-        m_text->Connect
-                (
-                    wxEVT_LEFT_DOWN,
-                    wxMouseEventHandler(wxTimePickerGenericImpl::OnTextClick),
-                    NULL,
-                    this
-                );
-
-        m_btn->Connect
-               (
-                    wxEVT_SPIN_UP,
-                    wxSpinEventHandler(wxTimePickerGenericImpl::OnArrowUp),
-                    NULL,
-                    this
-               );
-        m_btn->Connect
-               (
-                    wxEVT_SPIN_DOWN,
-                    wxSpinEventHandler(wxTimePickerGenericImpl::OnArrowDown),
-                    NULL,
-                    this
-               );
-    }
-
-    // Set the new value.
-    void SetValue(const wxDateTime& time)
-    {
-        m_time = time.IsValid() ? time : wxDateTime::Now();
-
-        UpdateTextWithoutEvent();
-    }
-
-
-    // The text part of the control.
-    wxTextCtrl* m_text;
-
-    // The spin button used to change the text fields.
-    wxSpinButton* m_btn;
-
-    // The current time (date part is ignored).
-    wxDateTime m_time;
-
-private:
-    // The logical fields of the text control (AM/PM one may not be present).
-    enum Field
-    {
-        Field_Hour,
-        Field_Min,
-        Field_Sec,
-        Field_AMPM,
-        Field_Max
-    };
-
-    // Direction of change of time fields.
-    enum Direction
-    {
-        // Notice that the enum elements values matter.
-        Dir_Down = -1,
-        Dir_Up   = +1
-    };
-
-    // A range of character positions ("from" is inclusive, "to" -- exclusive).
-    struct CharRange
-    {
-        int from,
-            to;
-    };
-
-    // Event handlers for various events in our controls.
-    void OnTextSetFocus(wxFocusEvent& event)
-    {
-        HighlightCurrentField();
-
-        event.Skip();
-    }
-
-    // Keyboard interface here is modelled over MSW native control and may need
-    // adjustments for other platforms.
-    void OnTextKeyDown(wxKeyEvent& event)
-    {
-        const int key = event.GetKeyCode();
-
-        switch ( key )
-        {
-            case WXK_DOWN:
-                ChangeCurrentFieldBy1(Dir_Down);
-                break;
-
-            case WXK_UP:
-                ChangeCurrentFieldBy1(Dir_Up);
-                break;
-
-            case WXK_LEFT:
-                CycleCurrentField(Dir_Down);
-                break;
-
-            case WXK_RIGHT:
-                CycleCurrentField(Dir_Up);
-                break;
-
-            case WXK_HOME:
-                ResetCurrentField(Dir_Down);
-                break;
-
-            case WXK_END:
-                ResetCurrentField(Dir_Up);
-                break;
-
-            case '0':
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-                // The digits work in all keys except AM/PM.
-                if ( m_currentField != Field_AMPM )
-                {
-                    AppendDigitToCurrentField(key - '0');
-                }
-                break;
-
-            case 'A':
-            case 'P':
-                // These keys only work to toggle AM/PM field.
-                if ( m_currentField == Field_AMPM )
-                {
-                    unsigned hour = m_time.GetHour();
-                    if ( key == 'A' )
-                    {
-                        if ( hour >= 12 )
-                            hour -= 12;
-                    }
-                    else // PM
-                    {
-                        if ( hour < 12 )
-                            hour += 12;
-                    }
-
-                    if ( hour != m_time.GetHour() )
-                    {
-                        m_time.SetHour(hour);
-                        UpdateText();
-                    }
-                }
-                break;
-
-            // Do not skip the other events, just consume them to prevent the
-            // user from editing the text directly.
-        }
-    }
-
-    void OnTextClick(wxMouseEvent& event)
-    {
-        Field field wxDUMMY_INITIALIZE(Field_Max);
-        long pos;
-        switch ( m_text->HitTest(event.GetPosition(), &pos) )
-        {
-            case wxTE_HT_UNKNOWN:
-                // Don't do anything, it's better than doing something wrong.
-                return;
-
-            case wxTE_HT_BEFORE:
-                // Select the first field.
-                field = Field_Hour;
-                break;
-
-            case wxTE_HT_ON_TEXT:
-                // Find the field containing this position.
-                for ( field = Field_Hour; field <= GetLastField(); )
-                {
-                    const CharRange range = GetFieldRange(field);
-
-                    // Normally the "to" end is exclusive but we want to give
-                    // focus to some field when the user clicks between them so
-                    // count it as part of the preceding field here.
-                    if ( range.from <= pos && pos <= range.to )
-                        break;
-
-                    field = static_cast<Field>(field + 1);
-                }
-                break;
-
-            case wxTE_HT_BELOW:
-                // This shouldn't happen for single line control.
-                wxFAIL_MSG( "Unreachable" );
-                // fall through
-
-            case wxTE_HT_BEYOND:
-                // Select the last field.
-                field = GetLastField();
-                break;
-        }
-
-        ChangeCurrentField(field);
-    }
-
-    void OnArrowUp(wxSpinEvent& WXUNUSED(event))
-    {
-        ChangeCurrentFieldBy1(Dir_Up);
-    }
-
-    void OnArrowDown(wxSpinEvent& WXUNUSED(event))
-    {
-        ChangeCurrentFieldBy1(Dir_Down);
-    }
-
-
-    // Get the range of the given field in character positions ("from" is
-    // inclusive, "to" exclusive).
-    static CharRange GetFieldRange(Field field)
-    {
-        // Currently we can just hard code the ranges as they are the same for
-        // both supported formats, if we want to support arbitrary formats in
-        // the future, we'd need to determine them dynamically by examining the
-        // format here.
-        static const CharRange ranges[] =
-        {
-            { 0, 2 },
-            { 3, 5 },
-            { 6, 8 },
-            { 9, 11},
-        };
-
-        wxCOMPILE_TIME_ASSERT( WXSIZEOF(ranges) == Field_Max,
-                               FieldRangesMismatch );
-
-        return ranges[field];
-    }
-
-    // Get the last field used depending on m_useAMPM.
-    Field GetLastField() const
-    {
-        return m_useAMPM ? Field_AMPM : Field_Sec;
-    }
-
-    // Change the current field. For convenience, accept int field here as this
-    // allows us to use arithmetic operations in the caller.
-    void ChangeCurrentField(int field)
-    {
-        if ( field == m_currentField )
-            return;
-
-        wxCHECK_RET( field <= GetLastField(), "Invalid field" );
-
-        m_currentField = static_cast<Field>(field);
-        m_isFirstDigit = true;
-
-        HighlightCurrentField();
-    }
-
-    // Go to the next (Dir_Up) or previous (Dir_Down) field, wrapping if
-    // necessary.
-    void CycleCurrentField(Direction dir)
-    {
-        const unsigned numFields = GetLastField() + 1;
-
-        ChangeCurrentField((m_currentField + numFields + dir) % numFields);
-    }
-
-    // Select the currently actively field.
-    void HighlightCurrentField()
-    {
-        m_text->SetFocus();
-
-        const CharRange range = GetFieldRange(m_currentField);
-
-        m_text->SetSelection(range.from, range.to);
-    }
-
-    // Decrement or increment the value of the current field (wrapping if
-    // necessary).
-    void ChangeCurrentFieldBy1(Direction dir)
-    {
-        switch ( m_currentField )
-        {
-            case Field_Hour:
-                m_time.SetHour((m_time.GetHour() + 24 + dir) % 24);
-                break;
-
-            case Field_Min:
-                m_time.SetMinute((m_time.GetMinute() + 60 + dir) % 60);
-                break;
-
-            case Field_Sec:
-                m_time.SetSecond((m_time.GetSecond() + 60 + dir) % 60);
-                break;
-
-            case Field_AMPM:
-                m_time.SetHour((m_time.GetHour() + 12) % 24);
-                break;
-
-            case Field_Max:
-                wxFAIL_MSG( "Invalid field" );
-        }
-
-        UpdateText();
-    }
-
-    // Set the current field to its minimal or maximal value.
-    void ResetCurrentField(Direction dir)
-    {
-        switch ( m_currentField )
-        {
-            case Field_Hour:
-            case Field_AMPM:
-                // In 12-hour mode setting the hour to the minimal value
-                // also changes the suffix to AM and, correspondingly,
-                // setting it to the maximal one changes the suffix to PM.
-                // And, for consistency with the native MSW behaviour, we
-                // also do the same thing when changing AM/PM field itself,
-                // so change hours in any case.
-                m_time.SetHour(dir == Dir_Down ? 0 : 23);
-                break;
-
-            case Field_Min:
-                m_time.SetMinute(dir == Dir_Down ? 0 : 59);
-                break;
-
-            case Field_Sec:
-                m_time.SetSecond(dir == Dir_Down ? 0 : 59);
-                break;
-
-            case Field_Max:
-                wxFAIL_MSG( "Invalid field" );
-        }
-
-        UpdateText();
-    }
-
-    // Append the given digit (from 0 to 9) to the current value of the current
-    // field.
-    void AppendDigitToCurrentField(int n)
-    {
-        bool moveToNextField = false;
-
-        if ( !m_isFirstDigit )
-        {
-            // The first digit simply replaces the existing field contents,
-            // but the second one should be combined with the previous one,
-            // otherwise entering 2-digit numbers would be impossible.
-            int currentValue wxDUMMY_INITIALIZE(0),
-                maxValue wxDUMMY_INITIALIZE(0);
-
-            switch ( m_currentField )
-            {
-                case Field_Hour:
-                    currentValue = m_time.GetHour();
-                    maxValue = 23;
-                    break;
-
-                case Field_Min:
-                    currentValue = m_time.GetMinute();
-                    maxValue = 59;
-                    break;
-
-                case Field_Sec:
-                    currentValue = m_time.GetSecond();
-                    maxValue = 59;
-                    break;
-
-                case Field_AMPM:
-                case Field_Max:
-                    wxFAIL_MSG( "Invalid field" );
-            }
-
-            // Check if the new value is acceptable. If not, we just handle
-            // this digit as if it were the first one.
-            int newValue = currentValue*10 + n;
-            if ( newValue < maxValue )
-            {
-                n = newValue;
-
-                // If we're not on the seconds field, advance to the next one.
-                // This makes it more convenient to enter times as you can just
-                // press all digits one after one without touching the cursor
-                // arrow keys at all.
-                //
-                // Notice that MSW native control doesn't do this but it seems
-                // so useful that we intentionally diverge from it here.
-                moveToNextField = true;
-
-                // We entered both digits so the next one will be "first" again.
-                m_isFirstDigit = true;
-            }
-        }
-        else // First digit entered.
-        {
-            // The next one won't be first any more.
-            m_isFirstDigit = false;
-        }
-
-        switch ( m_currentField )
-        {
-            case Field_Hour:
-                m_time.SetHour(n);
-                break;
-
-            case Field_Min:
-                m_time.SetMinute(n);
-                break;
-
-            case Field_Sec:
-                m_time.SetSecond(n);
-                break;
-
-            case Field_AMPM:
-            case Field_Max:
-                wxFAIL_MSG( "Invalid field" );
-        }
-
-        if ( moveToNextField && m_currentField < Field_Sec )
-            CycleCurrentField(Dir_Up);
-
-        UpdateText();
-    }
-
-    // Update the text value to correspond to the current time. By default also
-    // generate an event but this can be avoided by calling the "WithoutEvent"
-    // variant.
-    void UpdateText()
-    {
-        UpdateTextWithoutEvent();
-
-        wxWindow* const ctrl = m_text->GetParent();
-
-        wxDateEvent event(ctrl, m_time, wxEVT_TIME_CHANGED);
-        ctrl->HandleWindowEvent(event);
-    }
-
-    void UpdateTextWithoutEvent()
-    {
-        m_text->SetValue(m_time.Format(m_useAMPM ? "%I:%M:%S %p" : "%H:%M:%S"));
-
-        HighlightCurrentField();
-    }
-
-
-    // The current field of the text control: this is the one affected by
-    // pressing arrow keys or spin button.
-    Field m_currentField;
-
-    // Flag indicating whether we use AM/PM indicator or not.
-    bool m_useAMPM;
-
-    // Flag indicating whether the next digit pressed by user will be the first
-    // digit of the current field or the second one. This is necessary because
-    // the first digit replaces the current field contents while the second one
-    // is appended to it (if possible, e.g. pressing '7' in a field already
-    // containing '8' will still replace it as "78" would be invalid).
-    bool m_isFirstDigit;
-
-    wxDECLARE_NO_COPY_CLASS(wxTimePickerGenericImpl);
-};
-
-// ============================================================================
-// wxTimePickerCtrlGeneric implementation
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// wxTimePickerCtrlGeneric creation
-// ----------------------------------------------------------------------------
-
-void wxTimePickerCtrlGeneric::Init()
-{
-    m_impl = NULL;
-}
-
-bool
-wxTimePickerCtrlGeneric::Create(wxWindow *parent,
-                                wxWindowID id,
-                                const wxDateTime& date,
-                                const wxPoint& pos,
-                                const wxSize& size,
-                                long style,
-                                const wxValidator& validator,
-                                const wxString& name)
-{
-    // The text control we use already has a border, so we don't need one
-    // ourselves.
-    style &= ~wxBORDER_MASK;
-    style |= wxBORDER_NONE;
-
-    if ( !Base::Create(parent, id, pos, size, style, validator, name) )
-        return false;
-
-    m_impl = new wxTimePickerGenericImpl(this);
-    m_impl->SetValue(date);
-
-    InvalidateBestSize();
-    SetInitialSize(size);
-
-    return true;
-}
-
-wxTimePickerCtrlGeneric::~wxTimePickerCtrlGeneric()
-{
-    delete m_impl;
-}
-
-wxWindowList wxTimePickerCtrlGeneric::GetCompositeWindowParts() const
-{
-    wxWindowList parts;
-    if ( m_impl )
-    {
-        parts.push_back(m_impl->m_text);
-        parts.push_back(m_impl->m_btn);
-    }
-    return parts;
-}
-
-// ----------------------------------------------------------------------------
-// wxTimePickerCtrlGeneric value
-// ----------------------------------------------------------------------------
-
-void wxTimePickerCtrlGeneric::SetValue(const wxDateTime& date)
-{
-    wxCHECK_RET( m_impl, "Must create first" );
-
-    m_impl->SetValue(date);
-}
-
-wxDateTime wxTimePickerCtrlGeneric::GetValue() const
-{
-    wxCHECK_MSG( m_impl, wxDateTime(), "Must create first" );
-
-    return m_impl->m_time;
-}
-
-// ----------------------------------------------------------------------------
-// wxTimePickerCtrlGeneric geometry
-// ----------------------------------------------------------------------------
-
-void wxTimePickerCtrlGeneric::DoMoveWindow(int x, int y, int width, int height)
-{
-    Base::DoMoveWindow(x, y, width, height);
-
-    if ( !m_impl )
-        return;
-
-    const int widthBtn = m_impl->m_btn->GetSize().x;
-    const int widthText = width - widthBtn - HMARGIN_TEXT_SPIN;
-
-    m_impl->m_text->SetSize(0, 0, widthText, height);
-    m_impl->m_btn->SetSize(widthText + HMARGIN_TEXT_SPIN, 0, widthBtn, height);
-}
-
-wxSize wxTimePickerCtrlGeneric::DoGetBestSize() const
-{
-    if ( !m_impl )
-        return Base::DoGetBestSize();
-
-    wxSize size = m_impl->m_text->GetBestSize();
-    size.x += m_impl->m_btn->GetBestSize().x + HMARGIN_TEXT_SPIN;
-
-    return size;
-}
-
-#endif // !wxHAS_NATIVE_TIMEPICKERCTRL || wxUSE_TIMEPICKCTRL_GENERIC
-
-#endif // wxUSE_TIMEPICKCTRL