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"
19 #if wxUSE_CALENDARCTRL
21 #include "wx/gtk/private.h"
22 #include "wx/calctrl.h"
23 #include "wx/gtk/calctrl.h"
28 static void gtk_day_selected_callback(GtkWidget
*WXUNUSED(widget
),
29 wxGtkCalendarCtrl
*cal
)
31 cal
->GTKGenerateEvent(wxEVT_CALENDAR_SEL_CHANGED
);
34 static void gtk_day_selected_double_click_callback(GtkWidget
*WXUNUSED(widget
),
35 wxGtkCalendarCtrl
*cal
)
37 cal
->GTKGenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
40 static void gtk_month_changed_callback(GtkWidget
*WXUNUSED(widget
),
41 wxGtkCalendarCtrl
*cal
)
43 cal
->GTKGenerateEvent(wxEVT_CALENDAR_PAGE_CHANGED
);
46 // callbacks that send deprecated events
48 static void gtk_prev_month_callback(GtkWidget
*WXUNUSED(widget
),
49 wxGtkCalendarCtrl
*cal
)
51 cal
->GTKGenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED
);
54 static void gtk_prev_year_callback(GtkWidget
*WXUNUSED(widget
),
55 wxGtkCalendarCtrl
*cal
)
57 cal
->GTKGenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED
);
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
67 bool wxGtkCalendarCtrl::Create(wxWindow
*parent
,
69 const wxDateTime
& date
,
75 if (!PreCreation(parent
, pos
, size
) ||
76 !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
78 wxFAIL_MSG(wxT("wxGtkCalendarCtrl creation failed"));
82 m_widget
= gtk_calendar_new();
83 g_object_ref(m_widget
);
84 SetDate(date
.IsValid() ? date
: wxDateTime::Today());
86 if (style
& wxCAL_NO_MONTH_CHANGE
)
87 g_object_set (G_OBJECT (m_widget
), "no-month-change", true, NULL
);
88 if (style
& wxCAL_SHOW_WEEK_NUMBERS
)
89 g_object_set (G_OBJECT (m_widget
), "show-week-numbers", true, NULL
);
91 g_signal_connect_after(m_widget
, "day-selected",
92 G_CALLBACK (gtk_day_selected_callback
),
94 g_signal_connect_after(m_widget
, "day-selected-double-click",
95 G_CALLBACK (gtk_day_selected_double_click_callback
),
97 g_signal_connect_after(m_widget
, "month-changed",
98 G_CALLBACK (gtk_month_changed_callback
),
101 // connect callbacks that send deprecated events
102 g_signal_connect_after(m_widget
, "prev-month",
103 G_CALLBACK (gtk_prev_month_callback
),
105 g_signal_connect_after(m_widget
, "next-month",
106 G_CALLBACK (gtk_prev_month_callback
),
108 g_signal_connect_after(m_widget
, "prev-year",
109 G_CALLBACK (gtk_prev_year_callback
),
111 g_signal_connect_after(m_widget
, "next-year",
112 G_CALLBACK (gtk_prev_year_callback
),
115 m_parent
->DoAddChild(this);
122 void wxGtkCalendarCtrl::GTKGenerateEvent(wxEventType type
)
124 // First check if the new date is in the specified range.
125 wxDateTime dt
= GetDate();
126 if ( !IsInValidRange(dt
) )
128 if ( m_validStart
.IsValid() && dt
< m_validStart
)
138 if ( type
== wxEVT_CALENDAR_SEL_CHANGED
)
140 // Don't generate this event if the new date is the same as the old
142 if ( m_selectedDate
== dt
)
149 // Also send the deprecated event together with the new one.
150 GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED
);
158 bool wxGtkCalendarCtrl::IsInValidRange(const wxDateTime
& dt
) const
160 return (!m_validStart
.IsValid() || m_validStart
<= dt
) &&
161 (!m_validEnd
.IsValid() || dt
<= m_validEnd
);
165 wxGtkCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
,
166 const wxDateTime
& upperdate
)
168 if ( lowerdate
.IsValid() && upperdate
.IsValid() && lowerdate
>= upperdate
)
171 m_validStart
= lowerdate
;
172 m_validEnd
= upperdate
;
178 wxGtkCalendarCtrl::GetDateRange(wxDateTime
*lowerdate
,
179 wxDateTime
*upperdate
) const
182 *lowerdate
= m_validStart
;
184 *upperdate
= m_validEnd
;
186 return m_validStart
.IsValid() || m_validEnd
.IsValid();
190 bool wxGtkCalendarCtrl::EnableMonthChange(bool enable
)
192 if ( !wxCalendarCtrlBase::EnableMonthChange(enable
) )
195 g_object_set (G_OBJECT (m_widget
), "no-month-change", !enable
, NULL
);
201 bool wxGtkCalendarCtrl::SetDate(const wxDateTime
& date
)
203 if ( date
.IsValid() && !IsInValidRange(date
) )
206 g_signal_handlers_block_by_func(m_widget
,
207 (gpointer
) gtk_day_selected_callback
, this);
208 g_signal_handlers_block_by_func(m_widget
,
209 (gpointer
) gtk_month_changed_callback
, this);
211 m_selectedDate
= date
;
212 int year
= date
.GetYear();
213 int month
= date
.GetMonth();
214 int day
= date
.GetDay();
215 gtk_calendar_select_month(GTK_CALENDAR(m_widget
), month
, year
);
216 gtk_calendar_select_day(GTK_CALENDAR(m_widget
), day
);
218 g_signal_handlers_unblock_by_func( m_widget
,
219 (gpointer
) gtk_month_changed_callback
, this);
220 g_signal_handlers_unblock_by_func( m_widget
,
221 (gpointer
) gtk_day_selected_callback
, this);
226 wxDateTime
wxGtkCalendarCtrl::GetDate() const
228 guint year
, monthGTK
, day
;
229 gtk_calendar_get_date(GTK_CALENDAR(m_widget
), &year
, &monthGTK
, &day
);
231 // GTK may return an invalid date, this happens at least when switching the
232 // month (or the year in case of February in a leap year) and the new month
233 // has fewer days than the currently selected one making the currently
234 // selected day invalid, e.g. just choosing May 31 and going back a month
235 // results in the date being (non existent) April 31 when we're called from
236 // gtk_prev_month_callback(). We need to manually work around this to avoid
237 // asserts from wxDateTime ctor.
238 const wxDateTime::Month month
= static_cast<wxDateTime::Month
>(monthGTK
);
239 const guint dayMax
= wxDateTime::GetNumberOfDays(month
, year
);
243 return wxDateTime(day
, month
, year
);
246 void wxGtkCalendarCtrl::Mark(size_t day
, bool mark
)
249 gtk_calendar_mark_day(GTK_CALENDAR(m_widget
), day
);
251 gtk_calendar_unmark_day(GTK_CALENDAR(m_widget
), day
);
254 #endif // wxUSE_CALENDARCTRL