X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/37df1f337058d50f5749797400a767cf6efa5db1..0c32c93044babd3315029af529ab4348b103b036:/src/generic/calctrl.cpp diff --git a/src/generic/calctrl.cpp b/src/generic/calctrl.cpp index ef305edb4c..61eeb94708 100644 --- a/src/generic/calctrl.cpp +++ b/src/generic/calctrl.cpp @@ -34,10 +34,13 @@ #include "wx/brush.h" #include "wx/combobox.h" #include "wx/stattext.h" + #include "wx/textctrl.h" #endif //WX_PRECOMP #if wxUSE_CALENDARCTRL +#include "wx/spinctrl.h" + #include "wx/calctrl.h" #define DEBUG_PAINT 0 @@ -64,6 +67,7 @@ class wxYearSpinCtrl : public wxSpinCtrl public: wxYearSpinCtrl(wxCalendarCtrl *cal); + void OnYearTextChange(wxCommandEvent& event) { m_cal->OnYearChange(event); } void OnYearChange(wxSpinEvent& event) { m_cal->OnYearChange(event); } private: @@ -90,6 +94,7 @@ BEGIN_EVENT_TABLE(wxMonthComboBox, wxComboBox) END_EVENT_TABLE() BEGIN_EVENT_TABLE(wxYearSpinCtrl, wxSpinCtrl) + EVT_TEXT(-1, wxYearSpinCtrl::OnYearTextChange) EVT_SPINCTRL(-1, wxYearSpinCtrl::OnYearChange) END_EVENT_TABLE() @@ -121,7 +126,7 @@ wxMonthComboBox::wxMonthComboBox(wxCalendarCtrl *cal) wxDefaultPosition, wxDefaultSize, 0, NULL, - wxCB_READONLY) + wxCB_READONLY | wxCLIP_SIBLINGS) { m_cal = cal; @@ -140,7 +145,7 @@ wxYearSpinCtrl::wxYearSpinCtrl(wxCalendarCtrl *cal) cal->GetDate().Format(_T("%Y")), wxDefaultPosition, wxDefaultSize, - wxSP_ARROW_KEYS, + wxSP_ARROW_KEYS | wxCLIP_SIBLINGS, -4300, 10000, cal->GetDate().GetYear()) { m_cal = cal; @@ -155,6 +160,8 @@ void wxCalendarCtrl::Init() m_comboMonth = NULL; m_spinYear = NULL; + m_userChangedYear = FALSE; + m_widthCol = m_heightRow = 0; @@ -169,9 +176,8 @@ void wxCalendarCtrl::Init() m_attrs[n] = NULL; } - wxSystemSettings ss; - m_colHighlightFg = ss.GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT); - m_colHighlightBg = ss.GetSystemColour(wxSYS_COLOUR_HIGHLIGHT); + m_colHighlightFg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + m_colHighlightBg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); m_colHolidayFg = *wxRED; // don't set m_colHolidayBg - by default, same as our bg colour @@ -189,7 +195,8 @@ bool wxCalendarCtrl::Create(wxWindow *parent, const wxString& name) { if ( !wxControl::Create(parent, id, pos, size, - style | wxWANTS_CHARS, wxDefaultValidator, name) ) + style | wxCLIP_CHILDREN | wxWANTS_CHARS, + wxDefaultValidator, name) ) { return FALSE; } @@ -202,7 +209,7 @@ bool wxCalendarCtrl::Create(wxWindow *parent, m_lowdate = wxDefaultDateTime; m_highdate = wxDefaultDateTime; - if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { m_spinYear = new wxYearSpinCtrl(this); m_staticYear = new wxStaticText(GetParent(), -1, m_date.Format(_T("%Y")), @@ -231,7 +238,10 @@ bool wxCalendarCtrl::Create(wxWindow *parent, sizeReal = size; } - SetSize(sizeReal); + // we need to set the position as well because the main control position + // is not the same as the one specified in pos if we have the controls + // above it + SetSize(pos.x, pos.y, sizeReal.x, sizeReal.y); SetBackgroundColour(*wxWHITE); SetFont(*wxSWISS_FONT); @@ -253,6 +263,25 @@ wxCalendarCtrl::~wxCalendarCtrl() // forward wxWin functions to subcontrols // ---------------------------------------------------------------------------- +bool wxCalendarCtrl::Destroy() +{ + if ( m_staticYear ) + m_staticYear->Destroy(); + if ( m_spinYear ) + m_spinYear->Destroy(); + if ( m_comboMonth ) + m_comboMonth->Destroy(); + if ( m_staticMonth ) + m_staticMonth->Destroy(); + + m_staticYear = NULL; + m_spinYear = NULL; + m_comboMonth = NULL; + m_staticMonth = NULL; + + return wxControl::Destroy(); +} + bool wxCalendarCtrl::Show(bool show) { if ( !wxControl::Show(show) ) @@ -294,7 +323,7 @@ bool wxCalendarCtrl::Enable(bool enable) void wxCalendarCtrl::ShowCurrentControls() { - if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { if ( AllowMonthChange() ) { @@ -361,7 +390,7 @@ void wxCalendarCtrl::EnableMonthChange(bool enable) else style |= wxCAL_NO_MONTH_CHANGE; SetWindowStyle(style); - + ShowCurrentControls(); if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION ) { @@ -376,7 +405,7 @@ void wxCalendarCtrl::EnableMonthChange(bool enable) bool wxCalendarCtrl::SetDate(const wxDateTime& date) { - bool retval = false; + bool retval = TRUE; bool sameMonth = m_date.GetMonth() == date.GetMonth(), sameYear = m_date.GetYear() == date.GetYear(); @@ -386,37 +415,40 @@ bool wxCalendarCtrl::SetDate(const wxDateTime& date) if ( sameMonth && sameYear ) { // just change the day - retval = true; ChangeDay(date); } else { - if ( !AllowMonthChange() || (!AllowYearChange() && !sameYear) ) - { - // forbidden - return retval; - } - - // change everything - retval = true; - m_date = date; - - if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + if ( AllowMonthChange() && (AllowYearChange() || sameYear) ) { - // update the controls - m_comboMonth->SetSelection(m_date.GetMonth()); + // change everything + m_date = date; - if ( AllowYearChange() ) + if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { - m_spinYear->SetValue(m_date.Format(_T("%Y"))); + // update the controls + m_comboMonth->SetSelection(m_date.GetMonth()); + + if ( AllowYearChange() ) + { + if ( !m_userChangedYear ) + m_spinYear->SetValue(m_date.Format(_T("%Y"))); + else // don't overwrite what the user typed in + m_userChangedYear = FALSE; + } } - } - // as the month changed, holidays did too - SetHolidayAttrs(); + // as the month changed, holidays did too + SetHolidayAttrs(); - // update the calendar - Refresh(); + // update the calendar + Refresh(); + } + else + { + // forbidden + retval = FALSE; + } } } @@ -469,15 +501,15 @@ void wxCalendarCtrl::SetDateAndNotify(const wxDateTime& date) bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime& date /* = wxDefaultDateTime */) { - bool retval = true; + bool retval = TRUE; - if ( !(date.IsValid()) || ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) ) + if ( !(date.IsValid()) || ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : TRUE ) ) { m_lowdate = date; } else { - retval = false; + retval = FALSE; } return retval; @@ -485,15 +517,15 @@ bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime& date /* = wxDefaultDate bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime& date /* = wxDefaultDateTime */) { - bool retval = true; + bool retval = TRUE; - if ( !(date.IsValid()) || ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : true ) ) + if ( !(date.IsValid()) || ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : TRUE ) ) { m_highdate = date; } else { - retval = false; + retval = FALSE; } return retval; @@ -501,20 +533,20 @@ bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime& date /* = wxDefaultDate bool wxCalendarCtrl::SetDateRange(const wxDateTime& lowerdate /* = wxDefaultDateTime */, const wxDateTime& upperdate /* = wxDefaultDateTime */) { - bool retval = true; + bool retval = TRUE; if ( - ( !( lowerdate.IsValid() ) || ( ( upperdate.IsValid() ) ? ( lowerdate <= upperdate ) : true ) ) && - ( !( upperdate.IsValid() ) || ( ( lowerdate.IsValid() ) ? ( upperdate >= lowerdate ) : true ) ) ) + ( !( lowerdate.IsValid() ) || ( ( upperdate.IsValid() ) ? ( lowerdate <= upperdate ) : TRUE ) ) && + ( !( upperdate.IsValid() ) || ( ( lowerdate.IsValid() ) ? ( upperdate >= lowerdate ) : TRUE ) ) ) { m_lowdate = lowerdate; m_highdate = upperdate; } else { - retval = false; + retval = FALSE; } - + return retval; } @@ -558,16 +590,16 @@ bool wxCalendarCtrl::IsDateShown(const wxDateTime& date) const bool wxCalendarCtrl::IsDateInRange(const wxDateTime& date) const { - bool retval = true; + bool retval = TRUE; // Check if the given date is in the range specified - retval = ( ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : true ) - && ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) ); + retval = ( ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : TRUE ) + && ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : TRUE ) ); return retval; } bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const { - bool retval = false; + bool retval = FALSE; if ( !(IsDateInRange(*target)) ) { @@ -576,7 +608,7 @@ bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const if ( target->GetYear() >= GetLowerDateLimit().GetYear() ) { *target = GetLowerDateLimit(); - retval = true; + retval = TRUE; } else { @@ -588,7 +620,7 @@ bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const if ( target->GetYear() <= GetUpperDateLimit().GetYear() ) { *target = GetUpperDateLimit(); - retval = true; + retval = TRUE; } else { @@ -598,7 +630,7 @@ bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const } else { - retval = true; + retval = TRUE; } return retval; @@ -606,11 +638,11 @@ bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const bool wxCalendarCtrl::ChangeMonth(wxDateTime* target) const { - bool retval = true; + bool retval = TRUE; if ( !(IsDateInRange(*target)) ) { - retval = false; + retval = FALSE; if ( target->GetMonth() < m_date.GetMonth() ) { @@ -641,13 +673,13 @@ size_t wxCalendarCtrl::GetWeek(const wxDateTime& date) const // rewind back datetest.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST ? wxDateTime::Mon : wxDateTime::Sun); - + if ( datetest.GetDay() == 1 ) { retval += 1; } } - + return retval; } @@ -665,30 +697,27 @@ size_t wxCalendarCtrl::GetWeek(const wxDateTime& date) const // the constants used for the layout #define VERT_MARGIN 5 // distance between combo and calendar +#ifdef __WXMAC__ +#define HORZ_MARGIN 5 // spin +#else #define HORZ_MARGIN 15 // spin - +#endif wxSize wxCalendarCtrl::DoGetBestSize() const { // calc the size of the calendar ((wxCalendarCtrl *)this)->RecalcGeometry(); // const_cast wxCoord width = 7*m_widthCol, - height = 7*m_heightRow + m_rowOffset; + height = 7*m_heightRow + m_rowOffset + VERT_MARGIN; - // the combobox doesn't report its height correctly (it returns the - // height including the drop down list) so don't use it - - if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - height += VERT_MARGIN + m_spinYear->GetBestSize().y; - } - else + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { - height += VERT_MARGIN; + // the combobox doesn't report its height correctly (it returns the + // height including the drop down list) so don't use it + height += m_spinYear->GetBestSize().y; } -// if ( GetWindowStyle() & (wxRAISED_BORDER | wxSUNKEN_BORDER) ) // This doesn't work. Default is wxBORDER_DEFAULT (0) - if ( !(GetWindowStyle() & wxBORDER_NONE) ) + if ( !HasFlag(wxBORDER_NONE) ) { // the border would clip the last line otherwise height += 6; @@ -707,27 +736,30 @@ void wxCalendarCtrl::DoSetSize(int x, int y, void wxCalendarCtrl::DoMoveWindow(int x, int y, int width, int height) { - int xDiff = 0; - int yDiff = 0; + int yDiff; - if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { wxSize sizeCombo = m_comboMonth->GetSize(); wxSize sizeStatic = m_staticMonth->GetSize(); int dy = (sizeCombo.y - sizeStatic.y) / 2; - + m_comboMonth->Move(x, y); m_staticMonth->SetSize(x, y + dy, sizeCombo.x, sizeStatic.y); - - xDiff = sizeCombo.x + HORZ_MARGIN; - + + int xDiff = sizeCombo.x + HORZ_MARGIN; + m_spinYear->SetSize(x + xDiff, y, width - xDiff, sizeCombo.y); m_staticYear->SetSize(x + xDiff, y + dy, width - xDiff, sizeStatic.y); wxSize sizeSpin = m_spinYear->GetSize(); yDiff = wxMax(sizeSpin.y, sizeCombo.y) + VERT_MARGIN; } + else // no controls on the top + { + yDiff = 0; + } wxControl::DoMoveWindow(x, y + yDiff, width, height - yDiff); } @@ -753,7 +785,7 @@ void wxCalendarCtrl::DoGetSize(int *width, int *height) const if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { // our real height is bigger - if ( height ) + if ( height && GetMonthControl()) { *height += GetMonthControl()->GetSize().y + VERT_MARGIN; } @@ -810,9 +842,7 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) wxCoord y = 0; -///////////////////////////////////////////////////////////////////////////////////////// - - if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { // draw the sequential month-selector @@ -824,20 +854,20 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) // Get extent of month-name + year wxCoord monthw, monthh; - wxString headertext = m_date.Format("%B %Y"); + wxString headertext = m_date.Format(wxT("%B %Y")); dc.GetTextExtent(headertext, &monthw, &monthh); // draw month-name centered above weekdays wxCoord monthx = ((m_widthCol * 7) - monthw) / 2; wxCoord monthy = ((m_heightRow - monthh) / 2) + y; - dc.DrawText(headertext, monthx, monthy); + dc.DrawText(headertext, monthx, monthy); // calculate the "month-arrows" wxPoint leftarrow[3]; wxPoint rightarrow[3]; int arrowheight = monthh / 2; - + leftarrow[0] = wxPoint(0, arrowheight / 2); leftarrow[1] = wxPoint(arrowheight / 2, 0); leftarrow[2] = wxPoint(arrowheight / 2, arrowheight - 1); @@ -858,7 +888,7 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxDateTime ldpm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) - wxDateSpan::Day(); // last day prev month // Check if range permits change - if ( IsDateInRange(ldpm) && ( ( ldpm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) ) + if ( IsDateInRange(ldpm) && ( ( ldpm.GetYear() == m_date.GetYear() ) ? TRUE : AllowYearChange() ) ) { m_leftArrowRect = wxRect(larrowx - 3, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6)); dc.SetBrush(wxBrush(*wxBLACK, wxSOLID)); @@ -868,7 +898,7 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) dc.DrawRectangle(m_leftArrowRect); } wxDateTime fdnm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) + wxDateSpan::Month(); // first day next month - if ( IsDateInRange(fdnm) && ( ( fdnm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) ) + if ( IsDateInRange(fdnm) && ( ( fdnm.GetYear() == m_date.GetYear() ) ? TRUE : AllowYearChange() ) ) { m_rightArrowRect = wxRect(rarrowx - 4, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6)); dc.SetBrush(wxBrush(*wxBLACK, wxSOLID)); @@ -882,8 +912,6 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) y += m_heightRow; } -///////////////////////////////////////////////////////////////////////////////////////// - // first draw the week days if ( IsExposed(0, y, 7*m_widthCol, m_heightRow) ) { @@ -895,7 +923,7 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) dc.SetTextForeground(m_colHeaderFg); dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID)); dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID)); - dc.DrawRectangle(0, y, 7*m_widthCol, m_heightRow); + dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow); bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0; for ( size_t wd = 0; wd < 7; wd++ ) @@ -907,7 +935,6 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) n = wd; wxCoord dayw, dayh; dc.GetTextExtent(m_weekdays[n], &dayw, &dayh); -// dc.DrawText(m_weekdays[n], wd*m_widthCol + 1, y); dc.DrawText(m_weekdays[n], (wd*m_widthCol) + ((m_widthCol- dayw) / 2), y); // center the day-name } } @@ -952,7 +979,7 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) bool changedColours = FALSE, changedFont = FALSE; - bool isSel = false; + bool isSel = FALSE; wxCalendarDateAttr *attr = NULL; if ( date.GetMonth() != m_date.GetMonth() || !IsDateInRange(date) ) @@ -1080,7 +1107,7 @@ void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) if ( !IsDateInRange(date) ) { wxDateTime firstOOR = GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range - + wxBrush oorbrush = *wxLIGHT_GREY_BRUSH; oorbrush.SetStyle(wxFDIAGONAL_HATCH); @@ -1141,7 +1168,7 @@ void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, { // do stuff // date-coordinates - int fd, fw; + int fd, fw; int td, tw; // implicit: both dates must be currently shown - checked by GetDateCoord @@ -1182,7 +1209,7 @@ void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, int cidx = 0; // "complex" polygon corners[cidx] = wxPoint((fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++; - + if ( fd > 1 ) { corners[cidx] = wxPoint((fd - 1) * m_widthCol, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++; @@ -1199,7 +1226,7 @@ void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, } corners[cidx] = wxPoint(7 * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++; - + numpoints = cidx; } @@ -1218,7 +1245,7 @@ void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) const { - bool retval = true; + bool retval = TRUE; #if DEBUG_PAINT wxLogDebug("+++ GetDateCoord: (%s) +++", date.Format("%d %m %Y")); @@ -1227,10 +1254,10 @@ bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) c if ( IsDateShown(date) ) { bool startOnMonday = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) != 0; - + // Find day *day = date.GetWeekDay(); - + if ( *day == 0 ) // sunday { *day = ( startOnMonday ) ? 7 : 1; @@ -1295,7 +1322,7 @@ bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) c { *day = -1; *week = -1; - retval = false; + retval = FALSE; } #if DEBUG_PAINT @@ -1373,7 +1400,7 @@ wxCalendarHitTestResult wxCalendarCtrl::HitTest(const wxPoint& pos, 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) == wxInRegion ) @@ -1488,16 +1515,26 @@ void wxCalendarCtrl::OnMonthChange(wxCommandEvent& event) SetDateAndNotify(target); } -void wxCalendarCtrl::OnYearChange(wxSpinEvent& event) +void wxCalendarCtrl::OnYearChange(wxCommandEvent& event) { + int year = (int)event.GetInt(); + if ( year == INT_MIN ) + { + // invalid year in the spin control, ignore it + return; + } + + // set the flag for SetDate(): otherwise it would overwrite the year + // typed in by the user + m_userChangedYear = TRUE; + wxDateTime::Tm tm = m_date.GetTm(); - int year = (int)event.GetInt(); 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) ) @@ -1510,7 +1547,6 @@ void wxCalendarCtrl::OnYearChange(wxSpinEvent& event) // inside the same year but a strange number of months forward/back.. m_spinYear->SetValue(target.GetYear()); } - } // ----------------------------------------------------------------------------