calctrl.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,791 行 · 第 1/4 页

CPP
1,791
字号
                wxLogDebug("     +++ LDOM +++");
#endif
                GetDateCoord(ldcm.SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear()), &lastday, &lastweek);
#if DEBUG_PAINT
                wxLogDebug("     --- LDOM ---");
#endif

                wxTimeSpan span = date - ldcm;

                int daysfromlast = span.GetDays();
#if DEBUG_PAINT
                wxLogDebug("daysfromlast: %i", daysfromlast);
#endif
                if ( daysfromlast + lastday > 7 ) // past week boundary
                {
                    int wholeweeks = (daysfromlast / 7);
                    *week = wholeweeks + lastweek;
                    if ( (daysfromlast - (7 * wholeweeks) + lastday) > 7 )
                    {
                        *week += 1;
                    }
                }
                else
                {
                    *week = lastweek;
                }
            }
        }
    }
    else
    {
        *day = -1;
        *week = -1;
        retval = false;
    }

#if DEBUG_PAINT
    wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date.Format("%d %m %Y"), *day, *week);
#endif

    return retval;
}

// ----------------------------------------------------------------------------
// mouse handling
// ----------------------------------------------------------------------------

void wxCalendarCtrl::OnDClick(wxMouseEvent& event)
{
    if ( HitTest(event.GetPosition()) != wxCAL_HITTEST_DAY )
    {
        event.Skip();
    }
    else
    {
        GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
    }
}

void wxCalendarCtrl::OnClick(wxMouseEvent& event)
{
    wxDateTime date;
    wxDateTime::WeekDay wday;
    switch ( HitTest(event.GetPosition(), &date, &wday) )
    {
        case wxCAL_HITTEST_DAY:
            if ( IsDateInRange(date) )
            {
                ChangeDay(date);

                GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED,
                               wxEVT_CALENDAR_SEL_CHANGED);
            }
            break;

        case wxCAL_HITTEST_HEADER:
            {
                wxCalendarEvent eventWd(this, wxEVT_CALENDAR_WEEKDAY_CLICKED);
                eventWd.m_wday = wday;
                (void)GetEventHandler()->ProcessEvent(eventWd);
            }
            break;

        case wxCAL_HITTEST_DECMONTH:
        case wxCAL_HITTEST_INCMONTH:
        case wxCAL_HITTEST_SURROUNDING_WEEK:
            SetDateAndNotify(date); // we probably only want to refresh the control. No notification.. (maybe as an option?)
            break;

        default:
            wxFAIL_MSG(_T("unknown hittest code"));
            // fall through

        case wxCAL_HITTEST_NOWHERE:
            event.Skip();
            break;
    }
}

wxCalendarHitTestResult wxCalendarCtrl::HitTest(const wxPoint& pos,
                                                wxDateTime *date,
                                                wxDateTime::WeekDay *wd)
{
    RecalcGeometry();
    // use the correct x-pos 
    wxCoord x0 = wxMax((GetSize().x - m_widthCol*7) /2, 0);
    wxPoint pos_corr = pos;
    pos_corr.x -= x0;

    wxCoord y = pos_corr.y;

///////////////////////////////////////////////////////////////////////////////////////////////////////
    if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
    {
        // Header: month

        // we need to find out if the hit is on left arrow, on month or on right arrow
        // left arrow?
        if ( wxRegion(m_leftArrowRect).Contains(pos_corr) == wxInRegion )
        {
            if ( date )
            {
                if ( IsDateInRange(m_date - wxDateSpan::Month()) )
                {
                    *date = m_date - wxDateSpan::Month();
                }
                else
                {
                    *date = GetLowerDateLimit();
                }
            }

            return wxCAL_HITTEST_DECMONTH;
        }

        if ( wxRegion(m_rightArrowRect).Contains(pos_corr) == wxInRegion )
        {
            if ( date )
            {
                if ( IsDateInRange(m_date + wxDateSpan::Month()) )
                {
                    *date = m_date + wxDateSpan::Month();
                }
                else
                {
                    *date = GetUpperDateLimit();
                }
            }

            return wxCAL_HITTEST_INCMONTH;
        }

    }

///////////////////////////////////////////////////////////////////////////////////////////////////////
    // Header: Days

    int wday = pos_corr.x / m_widthCol;
//    if ( y < m_heightRow )
    if ( y < (m_heightRow + m_rowOffset) )
    {
        if ( y > m_rowOffset )
        {
            if ( wd )
            {
                if ( GetWindowStyle() & wxCAL_MONDAY_FIRST )
                {
                    wday = wday == 6 ? 0 : wday + 1;
                }

                *wd = (wxDateTime::WeekDay)wday;
            }

            return wxCAL_HITTEST_HEADER;
        }
        else
        {
            return wxCAL_HITTEST_NOWHERE;
        }
    }

//    int week = (y - m_heightRow) / m_heightRow;
    int week = (y - (m_heightRow + m_rowOffset)) / m_heightRow;
    if ( week >= 6 || wday >= 7 )
    {
        return wxCAL_HITTEST_NOWHERE;
    }

    wxDateTime dt = GetStartDate() + wxDateSpan::Days(7*week + wday);

    if ( IsDateShown(dt) )
    {
        if ( date )
            *date = dt;

        if ( dt.GetMonth() == m_date.GetMonth() )
        {

            return wxCAL_HITTEST_DAY;
        }
        else
        {
            return wxCAL_HITTEST_SURROUNDING_WEEK;
        }
    }
    else
    {
        return wxCAL_HITTEST_NOWHERE;
    }
}

// ----------------------------------------------------------------------------
// subcontrols events handling
// ----------------------------------------------------------------------------

void wxCalendarCtrl::OnMonthChange(wxCommandEvent& event)
{
    wxDateTime::Tm tm = m_date.GetTm();

    wxDateTime::Month mon = (wxDateTime::Month)event.GetInt();
    if ( tm.mday > wxDateTime::GetNumberOfDays(mon, tm.year) )
    {
        tm.mday = wxDateTime::GetNumberOfDays(mon, tm.year);
    }

    wxDateTime target = wxDateTime(tm.mday, mon, tm.year);

    ChangeMonth(&target);
    SetDateAndNotify(target);
}

void wxCalendarCtrl::OnYearChange(wxCommandEvent& event)
{
    int year = (int)event.GetInt();
    if ( year == INT_MIN )
    {
        // invalid year in the spin control, ignore it
        return;
    }

    wxDateTime::Tm tm = m_date.GetTm();

    if ( tm.mday > wxDateTime::GetNumberOfDays(tm.mon, year) )
    {
        tm.mday = wxDateTime::GetNumberOfDays(tm.mon, year);
    }

    wxDateTime target = wxDateTime(tm.mday, tm.mon, year);

    if ( ChangeYear(&target) )
    {
        SetDateAndNotify(target);
    }
    else
    {
        // In this case we don't want to change the date. That would put us
        // inside the same year but a strange number of months forward/back..
        m_spinYear->SetValue(target.GetYear());
    }
}

void wxCalendarCtrl::OnYearTextChange(wxCommandEvent& event)
{
    SetUserChangedYear();
    OnYearChange(event);
}

// ----------------------------------------------------------------------------
// keyboard interface
// ----------------------------------------------------------------------------

void wxCalendarCtrl::OnChar(wxKeyEvent& event)
{
    wxDateTime target;
    switch ( event.GetKeyCode() )
    {
        case _T('+'):
        case WXK_ADD:
            target = m_date + wxDateSpan::Year();
            if ( ChangeYear(&target) )
            {
                SetDateAndNotify(target);
            }
            break;

        case _T('-'):
        case WXK_SUBTRACT:
            target = m_date - wxDateSpan::Year();
            if ( ChangeYear(&target) )
            {
                SetDateAndNotify(target);
            }
            break;

        case WXK_PRIOR:
            target = m_date - wxDateSpan::Month();
            ChangeMonth(&target);
            SetDateAndNotify(target); // always
            break;

        case WXK_NEXT:
            target = m_date + wxDateSpan::Month();
            ChangeMonth(&target);
            SetDateAndNotify(target); // always
            break;

        case WXK_RIGHT:
            if ( event.ControlDown() )
            {
                target = wxDateTime(m_date).SetToNextWeekDay(
                                 GetWindowStyle() & wxCAL_MONDAY_FIRST
                                 ? wxDateTime::Sun : wxDateTime::Sat);
                if ( !IsDateInRange(target) )
                {
                    target = GetUpperDateLimit();
                }
                SetDateAndNotify(target);
            }
            else
                SetDateAndNotify(m_date + wxDateSpan::Day());
            break;

        case WXK_LEFT:
            if ( event.ControlDown() )
            {
                target = wxDateTime(m_date).SetToPrevWeekDay(
                                 GetWindowStyle() & wxCAL_MONDAY_FIRST
                                 ? wxDateTime::Mon : wxDateTime::Sun);
                if ( !IsDateInRange(target) )
                {
                    target = GetLowerDateLimit();
                }
                SetDateAndNotify(target);
            }
            else
                SetDateAndNotify(m_date - wxDateSpan::Day());
            break;

        case WXK_UP:
            SetDateAndNotify(m_date - wxDateSpan::Week());
            break;

        case WXK_DOWN:
            SetDateAndNotify(m_date + wxDateSpan::Week());
            break;

        case WXK_HOME:
            if ( event.ControlDown() )
                SetDateAndNotify(wxDateTime::Today());
            else
                SetDateAndNotify(wxDateTime(1, m_date.GetMonth(), m_date.GetYear()));
            break;

        case WXK_END:
            SetDateAndNotify(wxDateTime(m_date).SetToLastMonthDay());
            break;

        case WXK_RETURN:
            GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
            break;

        default:
            event.Skip();
    }
}

// ----------------------------------------------------------------------------
// holidays handling
// ----------------------------------------------------------------------------

void wxCalendarCtrl::EnableHolidayDisplay(bool display)
{
    long style = GetWindowStyle();
    if ( display )
        style |= wxCAL_SHOW_HOLIDAYS;
    else
        style &= ~wxCAL_SHOW_HOLIDAYS;

    SetWindowStyle(style);

    if ( display )
        SetHolidayAttrs();
    else
        ResetHolidayAttrs();

    Refresh();
}

void wxCalendarCtrl::SetHolidayAttrs()
{
    if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS )
    {
        ResetHolidayAttrs();

        wxDateTime::Tm tm = m_date.GetTm();
        wxDateTime dtStart(1, tm.mon, tm.year),
                   dtEnd = dtStart.GetLastMonthDay();

        wxDateTimeArray hol;
        wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol);

        size_t count = hol.GetCount();
        for ( size_t n = 0; n < count; n++ )
        {
            SetHoliday(hol[n].GetDay());
        }
    }
}

void wxCalendarCtrl::SetHoliday(size_t day)
{
    wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") );

    wxCalendarDateAttr *attr = GetAttr(day);
    if ( !attr )
    {
        attr = new wxCalendarDateAttr;
    }

    attr->SetHoliday(true);

    // can't use SetAttr() because it would delete this pointer
    m_attrs[day - 1] = attr;
}

void wxCalendarCtrl::ResetHolidayAttrs()
{
    for ( size_t day = 0; day < 31; day++ )
    {
        if ( m_attrs[day] )
        {
            m_attrs[day]->SetHoliday(false);
        }
    }
}


//static
wxVisualAttributes
wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant)
{
    // Use the same color scheme as wxListBox
    return wxListBox::GetClassDefaultAttributes(variant);
}

#endif // wxUSE_CALENDARCTRL

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?