1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/calctrl.cpp
3 // Purpose: implementation of the wxGtkCalendarCtrl
4 // Author: Marcin Wojdyr
5 // Copyright: (c) 2008 Marcin Wojdyr
6 // Licence: wxWindows licence
7 ///////////////////////////////////////////////////////////////////////////////
15 #if wxUSE_CALENDARCTRL
20 #include "wx/calctrl.h"
26 static void gtk_day_selected_callback(GtkWidget
*WXUNUSED(widget
),
27 wxGtkCalendarCtrl
*cal
)
29 cal
->GTKGenerateEvent(wxEVT_CALENDAR_SEL_CHANGED
);
32 static void gtk_day_selected_double_click_callback(GtkWidget
*WXUNUSED(widget
),
33 wxGtkCalendarCtrl
*cal
)
35 cal
->GTKGenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
38 static void gtk_month_changed_callback(GtkWidget
*WXUNUSED(widget
),
39 wxGtkCalendarCtrl
*cal
)
41 cal
->GTKGenerateEvent(wxEVT_CALENDAR_PAGE_CHANGED
);
44 // callbacks that send deprecated events
46 static void gtk_prev_month_callback(GtkWidget
*WXUNUSED(widget
),
47 wxGtkCalendarCtrl
*cal
)
49 cal
->GTKGenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED
);
52 static void gtk_prev_year_callback(GtkWidget
*WXUNUSED(widget
),
53 wxGtkCalendarCtrl
*cal
)
55 cal
->GTKGenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED
);
60 // ----------------------------------------------------------------------------
62 // ----------------------------------------------------------------------------
65 bool wxGtkCalendarCtrl::Create(wxWindow
*parent
,
67 const wxDateTime
& date
,
73 if (!PreCreation(parent
, pos
, size
) ||
74 !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
76 wxFAIL_MSG(wxT("wxGtkCalendarCtrl creation failed"));
80 m_widget
= gtk_calendar_new();
81 g_object_ref(m_widget
);
82 SetDate(date
.IsValid() ? date
: wxDateTime::Today());
84 if (style
& wxCAL_NO_MONTH_CHANGE
)
85 g_object_set (G_OBJECT (m_widget
), "no-month-change", true, NULL
);
86 if (style
& wxCAL_SHOW_WEEK_NUMBERS
)
87 g_object_set (G_OBJECT (m_widget
), "show-week-numbers", true, NULL
);
89 g_signal_connect_after(m_widget
, "day-selected",
90 G_CALLBACK (gtk_day_selected_callback
),
92 g_signal_connect_after(m_widget
, "day-selected-double-click",
93 G_CALLBACK (gtk_day_selected_double_click_callback
),
95 g_signal_connect_after(m_widget
, "month-changed",
96 G_CALLBACK (gtk_month_changed_callback
),
99 // connect callbacks that send deprecated events
100 g_signal_connect_after(m_widget
, "prev-month",
101 G_CALLBACK (gtk_prev_month_callback
),
103 g_signal_connect_after(m_widget
, "next-month",
104 G_CALLBACK (gtk_prev_month_callback
),
106 g_signal_connect_after(m_widget
, "prev-year",
107 G_CALLBACK (gtk_prev_year_callback
),
109 g_signal_connect_after(m_widget
, "next-year",
110 G_CALLBACK (gtk_prev_year_callback
),
113 m_parent
->DoAddChild(this);
120 void wxGtkCalendarCtrl::GTKGenerateEvent(wxEventType type
)
122 // First check if the new date is in the specified range.
123 wxDateTime dt
= GetDate();
124 if ( !IsInValidRange(dt
) )
126 if ( m_validStart
.IsValid() && dt
< m_validStart
)
136 if ( type
== wxEVT_CALENDAR_SEL_CHANGED
)
138 // Don't generate this event if the new date is the same as the old
140 if ( m_selectedDate
== dt
)
147 // Also send the deprecated event together with the new one.
148 GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED
);
156 bool wxGtkCalendarCtrl::IsInValidRange(const wxDateTime
& dt
) const
158 return (!m_validStart
.IsValid() || m_validStart
<= dt
) &&
159 (!m_validEnd
.IsValid() || dt
<= m_validEnd
);
163 wxGtkCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
,
164 const wxDateTime
& upperdate
)
166 if ( lowerdate
.IsValid() && upperdate
.IsValid() && lowerdate
>= upperdate
)
169 m_validStart
= lowerdate
;
170 m_validEnd
= upperdate
;
176 wxGtkCalendarCtrl::GetDateRange(wxDateTime
*lowerdate
,
177 wxDateTime
*upperdate
) const
180 *lowerdate
= m_validStart
;
182 *upperdate
= m_validEnd
;
184 return m_validStart
.IsValid() || m_validEnd
.IsValid();
188 bool wxGtkCalendarCtrl::EnableMonthChange(bool enable
)
190 if ( !wxCalendarCtrlBase::EnableMonthChange(enable
) )
193 g_object_set (G_OBJECT (m_widget
), "no-month-change", !enable
, NULL
);
199 bool wxGtkCalendarCtrl::SetDate(const wxDateTime
& date
)
201 if ( date
.IsValid() && !IsInValidRange(date
) )
204 g_signal_handlers_block_by_func(m_widget
,
205 (gpointer
) gtk_day_selected_callback
, this);
206 g_signal_handlers_block_by_func(m_widget
,
207 (gpointer
) gtk_month_changed_callback
, this);
209 m_selectedDate
= date
;
210 int year
= date
.GetYear();
211 int month
= date
.GetMonth();
212 int day
= date
.GetDay();
213 gtk_calendar_select_month(GTK_CALENDAR(m_widget
), month
, year
);
214 gtk_calendar_select_day(GTK_CALENDAR(m_widget
), day
);
216 g_signal_handlers_unblock_by_func( m_widget
,
217 (gpointer
) gtk_month_changed_callback
, this);
218 g_signal_handlers_unblock_by_func( m_widget
,
219 (gpointer
) gtk_day_selected_callback
, this);
224 wxDateTime
wxGtkCalendarCtrl::GetDate() const
226 guint year
, monthGTK
, day
;
227 gtk_calendar_get_date(GTK_CALENDAR(m_widget
), &year
, &monthGTK
, &day
);
229 // GTK may return an invalid date, this happens at least when switching the
230 // month (or the year in case of February in a leap year) and the new month
231 // has fewer days than the currently selected one making the currently
232 // selected day invalid, e.g. just choosing May 31 and going back a month
233 // results in the date being (non existent) April 31 when we're called from
234 // gtk_prev_month_callback(). We need to manually work around this to avoid
235 // asserts from wxDateTime ctor.
236 const wxDateTime::Month month
= static_cast<wxDateTime::Month
>(monthGTK
);
237 const guint dayMax
= wxDateTime::GetNumberOfDays(month
, year
);
241 return wxDateTime(day
, month
, year
);
244 void wxGtkCalendarCtrl::Mark(size_t day
, bool mark
)
247 gtk_calendar_mark_day(GTK_CALENDAR(m_widget
), day
);
249 gtk_calendar_unmark_day(GTK_CALENDAR(m_widget
), day
);
252 #endif // wxUSE_CALENDARCTRL