]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/calctrl.cpp
Cache HDC used for painting for the entire duration of WM_PAINT processing.
[wxWidgets.git] / src / gtk / calctrl.cpp
CommitLineData
628e155d
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/calctrl.cpp
3// Purpose: implementation of the wxGtkCalendarCtrl
4// Author: Marcin Wojdyr
5// RCS-ID: $Id$
6// Copyright: (c) 2008 Marcin Wojdyr
7// Licence: wxWindows licence
8///////////////////////////////////////////////////////////////////////////////
9
10#include "wx/wxprec.h"
11
12#ifdef __BORLANDC__
13 #pragma hdrstop
14#endif
15
85f62269
PC
16#if wxUSE_CALENDARCTRL
17
628e155d
VZ
18#ifndef WX_PRECOMP
19#endif //WX_PRECOMP
20
628e155d 21#include "wx/calctrl.h"
628e155d 22
85f62269 23#include <gtk/gtk.h>
628e155d
VZ
24
25extern "C" {
26
27static void gtk_day_selected_callback(GtkWidget *WXUNUSED(widget),
28 wxGtkCalendarCtrl *cal)
29{
106f0d98 30 cal->GTKGenerateEvent(wxEVT_CALENDAR_SEL_CHANGED);
628e155d
VZ
31}
32
33static void gtk_day_selected_double_click_callback(GtkWidget *WXUNUSED(widget),
34 wxGtkCalendarCtrl *cal)
35{
106f0d98 36 cal->GTKGenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
628e155d
VZ
37}
38
39static void gtk_month_changed_callback(GtkWidget *WXUNUSED(widget),
40 wxGtkCalendarCtrl *cal)
41{
106f0d98 42 cal->GTKGenerateEvent(wxEVT_CALENDAR_PAGE_CHANGED);
628e155d
VZ
43}
44
45// callbacks that send deprecated events
46
47static void gtk_prev_month_callback(GtkWidget *WXUNUSED(widget),
48 wxGtkCalendarCtrl *cal)
49{
106f0d98 50 cal->GTKGenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED);
628e155d
VZ
51}
52
53static void gtk_prev_year_callback(GtkWidget *WXUNUSED(widget),
54 wxGtkCalendarCtrl *cal)
55{
106f0d98 56 cal->GTKGenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED);
628e155d
VZ
57}
58
59}
60
61// ----------------------------------------------------------------------------
62// wxGtkCalendarCtrl
63// ----------------------------------------------------------------------------
64
65
66bool wxGtkCalendarCtrl::Create(wxWindow *parent,
67 wxWindowID id,
68 const wxDateTime& date,
69 const wxPoint& pos,
70 const wxSize& size,
71 long style,
72 const wxString& name)
73{
74 if (!PreCreation(parent, pos, size) ||
75 !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name))
76 {
77 wxFAIL_MSG(wxT("wxGtkCalendarCtrl creation failed"));
78 return false;
79 }
80
81 m_widget = gtk_calendar_new();
9ff9d30c 82 g_object_ref(m_widget);
628e155d
VZ
83 SetDate(date.IsValid() ? date : wxDateTime::Today());
84
85 if (style & wxCAL_NO_MONTH_CHANGE)
86 g_object_set (G_OBJECT (m_widget), "no-month-change", true, NULL);
7b0ccb8a
RR
87 if (style & wxCAL_SHOW_WEEK_NUMBERS)
88 g_object_set (G_OBJECT (m_widget), "show-week-numbers", true, NULL);
628e155d
VZ
89
90 g_signal_connect_after(m_widget, "day-selected",
91 G_CALLBACK (gtk_day_selected_callback),
92 this);
93 g_signal_connect_after(m_widget, "day-selected-double-click",
94 G_CALLBACK (gtk_day_selected_double_click_callback),
95 this);
96 g_signal_connect_after(m_widget, "month-changed",
97 G_CALLBACK (gtk_month_changed_callback),
98 this);
99
100 // connect callbacks that send deprecated events
101 g_signal_connect_after(m_widget, "prev-month",
102 G_CALLBACK (gtk_prev_month_callback),
103 this);
104 g_signal_connect_after(m_widget, "next-month",
105 G_CALLBACK (gtk_prev_month_callback),
106 this);
107 g_signal_connect_after(m_widget, "prev-year",
108 G_CALLBACK (gtk_prev_year_callback),
109 this);
110 g_signal_connect_after(m_widget, "next-year",
111 G_CALLBACK (gtk_prev_year_callback),
112 this);
113
114 m_parent->DoAddChild(this);
115
116 PostCreation(size);
117
118 return true;
119}
120
106f0d98
VZ
121void wxGtkCalendarCtrl::GTKGenerateEvent(wxEventType type)
122{
123 // First check if the new date is in the specified range.
124 wxDateTime dt = GetDate();
125 if ( !IsInValidRange(dt) )
126 {
127 if ( m_validStart.IsValid() && dt < m_validStart )
128 dt = m_validStart;
129 else
130 dt = m_validEnd;
131
132 SetDate(dt);
133
134 return;
135 }
136
137 if ( type == wxEVT_CALENDAR_SEL_CHANGED )
138 {
139 // Don't generate this event if the new date is the same as the old
140 // one.
141 if ( m_selectedDate == dt )
142 return;
143
144 m_selectedDate = dt;
145
146 GenerateEvent(type);
147
148 // Also send the deprecated event together with the new one.
149 GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED);
150 }
151 else
152 {
153 GenerateEvent(type);
154 }
155}
156
157bool wxGtkCalendarCtrl::IsInValidRange(const wxDateTime& dt) const
158{
159 return (!m_validStart.IsValid() || m_validStart <= dt) &&
160 (!m_validEnd.IsValid() || dt <= m_validEnd);
161}
162
163bool
164wxGtkCalendarCtrl::SetDateRange(const wxDateTime& lowerdate,
165 const wxDateTime& upperdate)
166{
167 if ( lowerdate.IsValid() && upperdate.IsValid() && lowerdate >= upperdate )
168 return false;
169
170 m_validStart = lowerdate;
171 m_validEnd = upperdate;
172
173 return true;
174}
175
176bool
177wxGtkCalendarCtrl::GetDateRange(wxDateTime *lowerdate,
178 wxDateTime *upperdate) const
179{
180 if ( lowerdate )
181 *lowerdate = m_validStart;
182 if ( upperdate )
183 *upperdate = m_validEnd;
184
185 return m_validStart.IsValid() || m_validEnd.IsValid();
186}
187
188
628e155d
VZ
189bool wxGtkCalendarCtrl::EnableMonthChange(bool enable)
190{
191 if ( !wxCalendarCtrlBase::EnableMonthChange(enable) )
192 return false;
193
194 g_object_set (G_OBJECT (m_widget), "no-month-change", !enable, NULL);
195
196 return true;
197}
198
7b0ccb8a 199
628e155d
VZ
200bool wxGtkCalendarCtrl::SetDate(const wxDateTime& date)
201{
106f0d98
VZ
202 if ( date.IsValid() && !IsInValidRange(date) )
203 return false;
204
7b0ccb8a
RR
205 g_signal_handlers_block_by_func(m_widget,
206 (gpointer) gtk_day_selected_callback, this);
6c1de056
VZ
207 g_signal_handlers_block_by_func(m_widget,
208 (gpointer) gtk_month_changed_callback, this);
03647350 209
7b0ccb8a 210 m_selectedDate = date;
628e155d
VZ
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);
03647350 216
6c1de056
VZ
217 g_signal_handlers_unblock_by_func( m_widget,
218 (gpointer) gtk_month_changed_callback, this);
7b0ccb8a
RR
219 g_signal_handlers_unblock_by_func( m_widget,
220 (gpointer) gtk_day_selected_callback, this);
03647350 221
628e155d
VZ
222 return true;
223}
224
225wxDateTime wxGtkCalendarCtrl::GetDate() const
226{
8ea26eed
VZ
227 guint year, monthGTK, day;
228 gtk_calendar_get_date(GTK_CALENDAR(m_widget), &year, &monthGTK, &day);
229
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);
239 if ( day > dayMax )
240 day = dayMax;
241
242 return wxDateTime(day, month, year);
628e155d
VZ
243}
244
245void wxGtkCalendarCtrl::Mark(size_t day, bool mark)
246{
247 if (mark)
248 gtk_calendar_mark_day(GTK_CALENDAR(m_widget), day);
249 else
250 gtk_calendar_unmark_day(GTK_CALENDAR(m_widget), day);
251}
252
628e155d 253#endif // wxUSE_CALENDARCTRL