1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/calctrl.cpp
3 // Purpose: implementation of the wxGtkCalendarCtrl
4 // Author: Marcin Wojdyr
6 // Copyright: (c) 2008 Marcin Wojdyr
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 #include "wx/wxprec.h"
16 #if wxUSE_CALENDARCTRL
21 #include "wx/calctrl.h"
27 static void gtk_day_selected_callback(GtkWidget
*WXUNUSED(widget
),
28 wxGtkCalendarCtrl
*cal
)
30 cal
->GTKGenerateEvent(wxEVT_CALENDAR_SEL_CHANGED
);
33 static void gtk_day_selected_double_click_callback(GtkWidget
*WXUNUSED(widget
),
34 wxGtkCalendarCtrl
*cal
)
36 cal
->GTKGenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
39 static void gtk_month_changed_callback(GtkWidget
*WXUNUSED(widget
),
40 wxGtkCalendarCtrl
*cal
)
42 cal
->GTKGenerateEvent(wxEVT_CALENDAR_PAGE_CHANGED
);
45 // callbacks that send deprecated events
47 static void gtk_prev_month_callback(GtkWidget
*WXUNUSED(widget
),
48 wxGtkCalendarCtrl
*cal
)
50 cal
->GTKGenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED
);
53 static void gtk_prev_year_callback(GtkWidget
*WXUNUSED(widget
),
54 wxGtkCalendarCtrl
*cal
)
56 cal
->GTKGenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED
);
61 // ----------------------------------------------------------------------------
63 // ----------------------------------------------------------------------------
66 bool wxGtkCalendarCtrl::Create(wxWindow
*parent
,
68 const wxDateTime
& date
,
74 if (!PreCreation(parent
, pos
, size
) ||
75 !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
77 wxFAIL_MSG(wxT("wxGtkCalendarCtrl creation failed"));
81 m_widget
= gtk_calendar_new();
82 g_object_ref(m_widget
);
83 SetDate(date
.IsValid() ? date
: wxDateTime::Today());
85 if (style
& wxCAL_NO_MONTH_CHANGE
)
86 g_object_set (G_OBJECT (m_widget
), "no-month-change", true, NULL
);
87 if (style
& wxCAL_SHOW_WEEK_NUMBERS
)
88 g_object_set (G_OBJECT (m_widget
), "show-week-numbers", true, NULL
);
90 g_signal_connect_after(m_widget
, "day-selected",
91 G_CALLBACK (gtk_day_selected_callback
),
93 g_signal_connect_after(m_widget
, "day-selected-double-click",
94 G_CALLBACK (gtk_day_selected_double_click_callback
),
96 g_signal_connect_after(m_widget
, "month-changed",
97 G_CALLBACK (gtk_month_changed_callback
),
100 // connect callbacks that send deprecated events
101 g_signal_connect_after(m_widget
, "prev-month",
102 G_CALLBACK (gtk_prev_month_callback
),
104 g_signal_connect_after(m_widget
, "next-month",
105 G_CALLBACK (gtk_prev_month_callback
),
107 g_signal_connect_after(m_widget
, "prev-year",
108 G_CALLBACK (gtk_prev_year_callback
),
110 g_signal_connect_after(m_widget
, "next-year",
111 G_CALLBACK (gtk_prev_year_callback
),
114 m_parent
->DoAddChild(this);
121 void wxGtkCalendarCtrl::GTKGenerateEvent(wxEventType type
)
123 // First check if the new date is in the specified range.
124 wxDateTime dt
= GetDate();
125 if ( !IsInValidRange(dt
) )
127 if ( m_validStart
.IsValid() && dt
< m_validStart
)
137 if ( type
== wxEVT_CALENDAR_SEL_CHANGED
)
139 // Don't generate this event if the new date is the same as the old
141 if ( m_selectedDate
== dt
)
148 // Also send the deprecated event together with the new one.
149 GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED
);
157 bool wxGtkCalendarCtrl::IsInValidRange(const wxDateTime
& dt
) const
159 return (!m_validStart
.IsValid() || m_validStart
<= dt
) &&
160 (!m_validEnd
.IsValid() || dt
<= m_validEnd
);
164 wxGtkCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
,
165 const wxDateTime
& upperdate
)
167 if ( lowerdate
.IsValid() && upperdate
.IsValid() && lowerdate
>= upperdate
)
170 m_validStart
= lowerdate
;
171 m_validEnd
= upperdate
;
177 wxGtkCalendarCtrl::GetDateRange(wxDateTime
*lowerdate
,
178 wxDateTime
*upperdate
) const
181 *lowerdate
= m_validStart
;
183 *upperdate
= m_validEnd
;
185 return m_validStart
.IsValid() || m_validEnd
.IsValid();
189 bool wxGtkCalendarCtrl::EnableMonthChange(bool enable
)
191 if ( !wxCalendarCtrlBase::EnableMonthChange(enable
) )
194 g_object_set (G_OBJECT (m_widget
), "no-month-change", !enable
, NULL
);
200 bool wxGtkCalendarCtrl::SetDate(const wxDateTime
& date
)
202 if ( date
.IsValid() && !IsInValidRange(date
) )
205 g_signal_handlers_block_by_func(m_widget
,
206 (gpointer
) gtk_day_selected_callback
, this);
207 g_signal_handlers_block_by_func(m_widget
,
208 (gpointer
) gtk_month_changed_callback
, this);
210 m_selectedDate
= date
;
211 int year
= date
.GetYear();
212 int month
= date
.GetMonth();
213 int day
= date
.GetDay();
214 gtk_calendar_select_month(GTK_CALENDAR(m_widget
), month
, year
);
215 gtk_calendar_select_day(GTK_CALENDAR(m_widget
), day
);
217 g_signal_handlers_unblock_by_func( m_widget
,
218 (gpointer
) gtk_month_changed_callback
, this);
219 g_signal_handlers_unblock_by_func( m_widget
,
220 (gpointer
) gtk_day_selected_callback
, this);
225 wxDateTime
wxGtkCalendarCtrl::GetDate() const
227 guint year
, monthGTK
, day
;
228 gtk_calendar_get_date(GTK_CALENDAR(m_widget
), &year
, &monthGTK
, &day
);
230 // GTK may return an invalid date, this happens at least when switching the
231 // month (or the year in case of February in a leap year) and the new month
232 // has fewer days than the currently selected one making the currently
233 // selected day invalid, e.g. just choosing May 31 and going back a month
234 // results in the date being (non existent) April 31 when we're called from
235 // gtk_prev_month_callback(). We need to manually work around this to avoid
236 // asserts from wxDateTime ctor.
237 const wxDateTime::Month month
= static_cast<wxDateTime::Month
>(monthGTK
);
238 const guint dayMax
= wxDateTime::GetNumberOfDays(month
, year
);
242 return wxDateTime(day
, month
, year
);
245 void wxGtkCalendarCtrl::Mark(size_t day
, bool mark
)
248 gtk_calendar_mark_day(GTK_CALENDAR(m_widget
), day
);
250 gtk_calendar_unmark_day(GTK_CALENDAR(m_widget
), day
);
253 #endif // wxUSE_CALENDARCTRL