]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/calctrl.cpp
Cache HDC used for painting for the entire duration of WM_PAINT processing.
[wxWidgets.git] / src / gtk / calctrl.cpp
index 2da9293d0bb3f35f1272bcf9e0f50dac88e79557..35b064567e6426f2b6f4acef91a7e460dc15f2b9 100644 (file)
     #pragma hdrstop
 #endif
 
+#if wxUSE_CALENDARCTRL
+
 #ifndef WX_PRECOMP
 #endif //WX_PRECOMP
 
-#if wxUSE_CALENDARCTRL
-
-#include "wx/gtk/private.h"
 #include "wx/calctrl.h"
-#include "wx/gtk/calctrl.h"
 
+#include <gtk/gtk.h>
 
 extern "C" {
 
 static void gtk_day_selected_callback(GtkWidget *WXUNUSED(widget),
                                       wxGtkCalendarCtrl *cal)
 {
-    wxDateTime date = cal->GetDate();
-    if (cal->m_selectedDate == date)
-        return;
-
-    cal->m_selectedDate = date;
-
-    cal->GenerateEvent(wxEVT_CALENDAR_SEL_CHANGED);
-    // send deprecated event
-    cal->GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED);
+    cal->GTKGenerateEvent(wxEVT_CALENDAR_SEL_CHANGED);
 }
 
 static void gtk_day_selected_double_click_callback(GtkWidget *WXUNUSED(widget),
                                                    wxGtkCalendarCtrl *cal)
 {
-    cal->GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
+    cal->GTKGenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
 }
 
 static void gtk_month_changed_callback(GtkWidget *WXUNUSED(widget),
                                        wxGtkCalendarCtrl *cal)
 {
-    cal->GenerateEvent(wxEVT_CALENDAR_PAGE_CHANGED);
+    cal->GTKGenerateEvent(wxEVT_CALENDAR_PAGE_CHANGED);
 }
 
 // callbacks that send deprecated events
@@ -56,13 +47,13 @@ static void gtk_month_changed_callback(GtkWidget *WXUNUSED(widget),
 static void gtk_prev_month_callback(GtkWidget *WXUNUSED(widget),
                                     wxGtkCalendarCtrl *cal)
 {
-    cal->GenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED);
+    cal->GTKGenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED);
 }
 
 static void gtk_prev_year_callback(GtkWidget *WXUNUSED(widget),
                                     wxGtkCalendarCtrl *cal)
 {
-    cal->GenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED);
+    cal->GTKGenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED);
 }
 
 }
@@ -127,6 +118,74 @@ bool wxGtkCalendarCtrl::Create(wxWindow *parent,
     return true;
 }
 
+void wxGtkCalendarCtrl::GTKGenerateEvent(wxEventType type)
+{
+    // First check if the new date is in the specified range.
+    wxDateTime dt = GetDate();
+    if ( !IsInValidRange(dt) )
+    {
+        if ( m_validStart.IsValid() && dt < m_validStart )
+            dt = m_validStart;
+        else
+            dt = m_validEnd;
+
+        SetDate(dt);
+
+        return;
+    }
+
+    if ( type == wxEVT_CALENDAR_SEL_CHANGED )
+    {
+        // Don't generate this event if the new date is the same as the old
+        // one.
+        if ( m_selectedDate == dt )
+            return;
+
+        m_selectedDate = dt;
+
+        GenerateEvent(type);
+
+        // Also send the deprecated event together with the new one.
+        GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED);
+    }
+    else
+    {
+        GenerateEvent(type);
+    }
+}
+
+bool wxGtkCalendarCtrl::IsInValidRange(const wxDateTime& dt) const
+{
+    return (!m_validStart.IsValid() || m_validStart <= dt) &&
+                (!m_validEnd.IsValid() || dt <= m_validEnd);
+}
+
+bool
+wxGtkCalendarCtrl::SetDateRange(const wxDateTime& lowerdate,
+                                const wxDateTime& upperdate)
+{
+    if ( lowerdate.IsValid() && upperdate.IsValid() && lowerdate >= upperdate )
+        return false;
+
+    m_validStart = lowerdate;
+    m_validEnd = upperdate;
+
+    return true;
+}
+
+bool
+wxGtkCalendarCtrl::GetDateRange(wxDateTime *lowerdate,
+                                wxDateTime *upperdate) const
+{
+    if ( lowerdate )
+        *lowerdate = m_validStart;
+    if ( upperdate )
+        *upperdate = m_validEnd;
+
+    return m_validStart.IsValid() || m_validEnd.IsValid();
+}
+
+
 bool wxGtkCalendarCtrl::EnableMonthChange(bool enable)
 {
     if ( !wxCalendarCtrlBase::EnableMonthChange(enable) )
@@ -140,27 +199,47 @@ bool wxGtkCalendarCtrl::EnableMonthChange(bool enable)
 
 bool wxGtkCalendarCtrl::SetDate(const wxDateTime& date)
 {
+    if ( date.IsValid() && !IsInValidRange(date) )
+        return false;
+
     g_signal_handlers_block_by_func(m_widget,
         (gpointer) gtk_day_selected_callback, this);
-        
+    g_signal_handlers_block_by_func(m_widget,
+        (gpointer) gtk_month_changed_callback, this);
+
     m_selectedDate = date;
     int year = date.GetYear();
     int month = date.GetMonth();
     int day = date.GetDay();
     gtk_calendar_select_month(GTK_CALENDAR(m_widget), month, year);
     gtk_calendar_select_day(GTK_CALENDAR(m_widget), day);
-    
+
+    g_signal_handlers_unblock_by_func( m_widget,
+        (gpointer) gtk_month_changed_callback, this);
     g_signal_handlers_unblock_by_func( m_widget,
         (gpointer) gtk_day_selected_callback, this);
-    
+
     return true;
 }
 
 wxDateTime wxGtkCalendarCtrl::GetDate() const
 {
-    guint year, month, day;
-    gtk_calendar_get_date(GTK_CALENDAR(m_widget), &year, &month, &day);
-    return wxDateTime(day, (wxDateTime::Month) month, year);
+    guint year, monthGTK, day;
+    gtk_calendar_get_date(GTK_CALENDAR(m_widget), &year, &monthGTK, &day);
+
+    // GTK may return an invalid date, this happens at least when switching the
+    // month (or the year in case of February in a leap year) and the new month
+    // has fewer days than the currently selected one making the currently
+    // selected day invalid, e.g. just choosing May 31 and going back a month
+    // results in the date being (non existent) April 31 when we're called from
+    // gtk_prev_month_callback(). We need to manually work around this to avoid
+    // asserts from wxDateTime ctor.
+    const wxDateTime::Month month = static_cast<wxDateTime::Month>(monthGTK);
+    const guint dayMax = wxDateTime::GetNumberOfDays(month, year);
+    if ( day > dayMax )
+        day = dayMax;
+
+    return wxDateTime(day, month, year);
 }
 
 void wxGtkCalendarCtrl::Mark(size_t day, bool mark)
@@ -171,7 +250,4 @@ void wxGtkCalendarCtrl::Mark(size_t day, bool mark)
         gtk_calendar_unmark_day(GTK_CALENDAR(m_widget), day);
 }
 
-IMPLEMENT_DYNAMIC_CLASS(wxGtkCalendarCtrl, wxControl)
-
-
 #endif // wxUSE_CALENDARCTRL