calctrl.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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. ///////////////////////////////////////////////////////////////////////////////
  8. #include "wx/wxprec.h"
  9. #ifdef __BORLANDC__
  10. #pragma hdrstop
  11. #endif
  12. #if wxUSE_CALENDARCTRL
  13. #ifndef WX_PRECOMP
  14. #endif //WX_PRECOMP
  15. #include "wx/calctrl.h"
  16. #include <gtk/gtk.h>
  17. extern "C" {
  18. static void gtk_day_selected_callback(GtkWidget *WXUNUSED(widget),
  19. wxGtkCalendarCtrl *cal)
  20. {
  21. cal->GTKGenerateEvent(wxEVT_CALENDAR_SEL_CHANGED);
  22. }
  23. static void gtk_day_selected_double_click_callback(GtkWidget *WXUNUSED(widget),
  24. wxGtkCalendarCtrl *cal)
  25. {
  26. cal->GTKGenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
  27. }
  28. static void gtk_month_changed_callback(GtkWidget *WXUNUSED(widget),
  29. wxGtkCalendarCtrl *cal)
  30. {
  31. cal->GTKGenerateEvent(wxEVT_CALENDAR_PAGE_CHANGED);
  32. }
  33. // callbacks that send deprecated events
  34. static void gtk_prev_month_callback(GtkWidget *WXUNUSED(widget),
  35. wxGtkCalendarCtrl *cal)
  36. {
  37. cal->GTKGenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED);
  38. }
  39. static void gtk_prev_year_callback(GtkWidget *WXUNUSED(widget),
  40. wxGtkCalendarCtrl *cal)
  41. {
  42. cal->GTKGenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED);
  43. }
  44. }
  45. // ----------------------------------------------------------------------------
  46. // wxGtkCalendarCtrl
  47. // ----------------------------------------------------------------------------
  48. bool wxGtkCalendarCtrl::Create(wxWindow *parent,
  49. wxWindowID id,
  50. const wxDateTime& date,
  51. const wxPoint& pos,
  52. const wxSize& size,
  53. long style,
  54. const wxString& name)
  55. {
  56. if (!PreCreation(parent, pos, size) ||
  57. !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name))
  58. {
  59. wxFAIL_MSG(wxT("wxGtkCalendarCtrl creation failed"));
  60. return false;
  61. }
  62. m_widget = gtk_calendar_new();
  63. g_object_ref(m_widget);
  64. SetDate(date.IsValid() ? date : wxDateTime::Today());
  65. if (style & wxCAL_NO_MONTH_CHANGE)
  66. g_object_set (G_OBJECT (m_widget), "no-month-change", true, NULL);
  67. if (style & wxCAL_SHOW_WEEK_NUMBERS)
  68. g_object_set (G_OBJECT (m_widget), "show-week-numbers", true, NULL);
  69. g_signal_connect_after(m_widget, "day-selected",
  70. G_CALLBACK (gtk_day_selected_callback),
  71. this);
  72. g_signal_connect_after(m_widget, "day-selected-double-click",
  73. G_CALLBACK (gtk_day_selected_double_click_callback),
  74. this);
  75. g_signal_connect_after(m_widget, "month-changed",
  76. G_CALLBACK (gtk_month_changed_callback),
  77. this);
  78. // connect callbacks that send deprecated events
  79. g_signal_connect_after(m_widget, "prev-month",
  80. G_CALLBACK (gtk_prev_month_callback),
  81. this);
  82. g_signal_connect_after(m_widget, "next-month",
  83. G_CALLBACK (gtk_prev_month_callback),
  84. this);
  85. g_signal_connect_after(m_widget, "prev-year",
  86. G_CALLBACK (gtk_prev_year_callback),
  87. this);
  88. g_signal_connect_after(m_widget, "next-year",
  89. G_CALLBACK (gtk_prev_year_callback),
  90. this);
  91. m_parent->DoAddChild(this);
  92. PostCreation(size);
  93. return true;
  94. }
  95. void wxGtkCalendarCtrl::GTKGenerateEvent(wxEventType type)
  96. {
  97. // First check if the new date is in the specified range.
  98. wxDateTime dt = GetDate();
  99. if ( !IsInValidRange(dt) )
  100. {
  101. if ( m_validStart.IsValid() && dt < m_validStart )
  102. dt = m_validStart;
  103. else
  104. dt = m_validEnd;
  105. SetDate(dt);
  106. return;
  107. }
  108. if ( type == wxEVT_CALENDAR_SEL_CHANGED )
  109. {
  110. // Don't generate this event if the new date is the same as the old
  111. // one.
  112. if ( m_selectedDate == dt )
  113. return;
  114. m_selectedDate = dt;
  115. GenerateEvent(type);
  116. // Also send the deprecated event together with the new one.
  117. GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED);
  118. }
  119. else
  120. {
  121. GenerateEvent(type);
  122. }
  123. }
  124. bool wxGtkCalendarCtrl::IsInValidRange(const wxDateTime& dt) const
  125. {
  126. return (!m_validStart.IsValid() || m_validStart <= dt) &&
  127. (!m_validEnd.IsValid() || dt <= m_validEnd);
  128. }
  129. bool
  130. wxGtkCalendarCtrl::SetDateRange(const wxDateTime& lowerdate,
  131. const wxDateTime& upperdate)
  132. {
  133. if ( lowerdate.IsValid() && upperdate.IsValid() && lowerdate >= upperdate )
  134. return false;
  135. m_validStart = lowerdate;
  136. m_validEnd = upperdate;
  137. return true;
  138. }
  139. bool
  140. wxGtkCalendarCtrl::GetDateRange(wxDateTime *lowerdate,
  141. wxDateTime *upperdate) const
  142. {
  143. if ( lowerdate )
  144. *lowerdate = m_validStart;
  145. if ( upperdate )
  146. *upperdate = m_validEnd;
  147. return m_validStart.IsValid() || m_validEnd.IsValid();
  148. }
  149. bool wxGtkCalendarCtrl::EnableMonthChange(bool enable)
  150. {
  151. if ( !wxCalendarCtrlBase::EnableMonthChange(enable) )
  152. return false;
  153. g_object_set (G_OBJECT (m_widget), "no-month-change", !enable, NULL);
  154. return true;
  155. }
  156. bool wxGtkCalendarCtrl::SetDate(const wxDateTime& date)
  157. {
  158. if ( date.IsValid() && !IsInValidRange(date) )
  159. return false;
  160. g_signal_handlers_block_by_func(m_widget,
  161. (gpointer) gtk_day_selected_callback, this);
  162. g_signal_handlers_block_by_func(m_widget,
  163. (gpointer) gtk_month_changed_callback, this);
  164. m_selectedDate = date;
  165. int year = date.GetYear();
  166. int month = date.GetMonth();
  167. int day = date.GetDay();
  168. gtk_calendar_select_month(GTK_CALENDAR(m_widget), month, year);
  169. gtk_calendar_select_day(GTK_CALENDAR(m_widget), day);
  170. g_signal_handlers_unblock_by_func( m_widget,
  171. (gpointer) gtk_month_changed_callback, this);
  172. g_signal_handlers_unblock_by_func( m_widget,
  173. (gpointer) gtk_day_selected_callback, this);
  174. return true;
  175. }
  176. wxDateTime wxGtkCalendarCtrl::GetDate() const
  177. {
  178. guint year, monthGTK, day;
  179. gtk_calendar_get_date(GTK_CALENDAR(m_widget), &year, &monthGTK, &day);
  180. // GTK may return an invalid date, this happens at least when switching the
  181. // month (or the year in case of February in a leap year) and the new month
  182. // has fewer days than the currently selected one making the currently
  183. // selected day invalid, e.g. just choosing May 31 and going back a month
  184. // results in the date being (non existent) April 31 when we're called from
  185. // gtk_prev_month_callback(). We need to manually work around this to avoid
  186. // asserts from wxDateTime ctor.
  187. const wxDateTime::Month month = static_cast<wxDateTime::Month>(monthGTK);
  188. const guint dayMax = wxDateTime::GetNumberOfDays(month, year);
  189. if ( day > dayMax )
  190. day = dayMax;
  191. return wxDateTime(day, month, year);
  192. }
  193. void wxGtkCalendarCtrl::Mark(size_t day, bool mark)
  194. {
  195. if (mark)
  196. gtk_calendar_mark_day(GTK_CALENDAR(m_widget), day);
  197. else
  198. gtk_calendar_unmark_day(GTK_CALENDAR(m_widget), day);
  199. }
  200. #endif // wxUSE_CALENDARCTRL