Release 4.0.0-preview1-00051
[platform/core/csapi/tizenfx.git] / src / ElmSharp / ElmSharp / Calendar.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Linq;
20 using System.Runtime.InteropServices;
21
22 namespace ElmSharp
23 {
24     /// <summary>
25     /// Enumeration for event periodicity, used to define if a mark should be repeated beyond event's day. It's set when a mark is added.
26     /// </summary>
27     public enum CalendarMarkRepeatType
28     {
29         /// <summary>
30         /// Default value. Marks will be displayed only on event day.
31         /// </summary>
32         Unique,
33
34         /// <summary>
35         /// Marks will be displayed every day after event day.
36         /// </summary>
37         Daily,
38
39         /// <summary>
40         /// Marks will be displayed every week after event day.
41         /// </summary>
42         Weekly,
43
44         /// <summary>
45         /// Marks will be displayed every month day that coincides to event day.
46         /// </summary>
47         Monthly,
48
49         /// <summary>
50         /// Marks will be displayed every year that coincides to event day.
51         /// </summary>
52         Annually,
53
54         /// <summary>
55         /// Marks will be displayed every last day of month after event day.
56         /// </summary>
57         LastDayOfMonth
58     }
59
60     /// <summary>
61     /// Enumeration for the mode, which determine how user could select a day.
62     /// </summary>
63     public enum CalendarSelectMode
64     {
65         /// <summary>
66         /// Default value. a day is always selected.
67         /// </summary>
68         Default,
69
70         /// <summary>
71         /// A day is always selected.
72         /// </summary>
73         Always,
74
75         /// <summary>
76         /// None of the days can be selected.
77         /// </summary>
78         None,
79
80         /// <summary>
81         /// User may have selected a day or not.
82         /// </summary>
83         OnDemand
84     }
85
86     /// <summary>
87     /// Enumeration used to define which fields of a tm struct will be taken into account
88     /// </summary>
89     [Flags]
90     public enum CalendarSelectable
91     {
92         /// <summary>
93         /// None will be taken into account
94         /// </summary>
95         None = 0,
96         /// <summary>
97         /// Year will be taken into account
98         /// </summary>
99         Year = 1 << 0,
100         /// <summary>
101         /// Month will be taken into account
102         /// </summary>
103         Month = 1 << 1,
104         /// <summary>
105         /// Day will be taken into account
106         /// </summary>
107         Day = 1 << 2
108     }
109
110     /// <summary>
111     /// The CalendarMark is a Item for marking a Calendar's type,date and repeat type.
112     /// </summary>
113     public class CalendarMark
114     {
115         internal IntPtr Handle;
116
117         /// <summary>
118         /// A string used to define the type of mark.
119         /// </summary>
120         public string Type;
121
122         /// <summary>
123         /// A time struct to represent the date of inclusion of the mark.
124         /// </summary>
125         public DateTime Date;
126
127         /// <summary>
128         /// Repeat the event following this periodicity.
129         /// </summary>
130         public CalendarMarkRepeatType Repeat;
131
132         /// <summary>
133         /// Creates and initializes a new instance of the CalendarMark class.
134         /// </summary>
135         /// <param name="type">Type of mark</param>
136         /// <param name="date">Date of inclusion of the mark</param>
137         /// <param name="repeat">Repeat type</param>
138         public CalendarMark(string type, DateTime date, CalendarMarkRepeatType repeat)
139         {
140             Handle = IntPtr.Zero;
141             Type = type;
142             Date = date;
143             Repeat = repeat;
144         }
145     }
146
147     /// <summary>
148     /// The Calendar is a widget that helps applications to flexibly display a calender with day of the week, date, year and month.
149     /// </summary>
150     public class Calendar : Layout
151     {
152         SmartEvent _changed;
153         DateTime _cacheSelectedDate;
154         SmartEvent _displayedMonthChanged;
155         int _cacheDisplayedMonth;
156
157         Interop.Elementary.Elm_Calendar_Format_Cb _calendarFormat;
158         DateFormatDelegate _dateFormatDelegate = null;
159
160         /// <summary>
161         /// Creates and initializes a new instance of the Calendar class.
162         /// </summary>
163         /// <param name="parent">
164         /// The EvasObject to which the new Calendar will be attached as a child.
165         /// </param>
166         public Calendar(EvasObject parent) : base(parent)
167         {
168             _changed = new SmartEvent(this, this.RealHandle, "changed");
169             _changed.On += (sender, e) =>
170             {
171                 DateTime selectedDate = SelectedDate;
172                 DateChanged?.Invoke(this, new DateChangedEventArgs(_cacheSelectedDate, selectedDate));
173                 _cacheSelectedDate = selectedDate;
174             };
175
176             _displayedMonthChanged = new SmartEvent(this, this.RealHandle, "display,changed");
177             _displayedMonthChanged.On += (sender, e) =>
178             {
179                 int currentDisplayedMonth = DisplayedTime.Month;
180                 DisplayedMonthChanged?.Invoke(this, new DisplayedMonthChangedEventArgs(_cacheDisplayedMonth, currentDisplayedMonth));
181                 _cacheDisplayedMonth = currentDisplayedMonth;
182             };
183
184             _calendarFormat = (t) => { return _dateFormatDelegate(t); };
185         }
186
187         /// <summary>
188         /// DateChanged will be triggered when the date in the calendar is changed.
189         /// </summary>
190         public event EventHandler<DateChangedEventArgs> DateChanged;
191
192         /// <summary>
193         /// DisplayedMonthChanged will be triggered when the current month displayed in the calendar is changed.
194         /// </summary>
195         public event EventHandler<DisplayedMonthChangedEventArgs> DisplayedMonthChanged;
196
197         /// <summary>
198         /// This delegate type is used to format the string that will be used to display month and year.
199         /// </summary>
200         /// <param name="time">DateTime</param>
201         /// <returns></returns>
202         public delegate string DateFormatDelegate(DateTime time);
203
204         /// <summary>
205         /// Sets or gets the minimum for year.
206         /// </summary>
207         public int MinimumYear
208         {
209             get
210             {
211                 int minimumYear;
212                 int unused;
213                 Interop.Elementary.elm_calendar_min_max_year_get(RealHandle, out minimumYear, out unused);
214                 return minimumYear;
215             }
216             set
217             {
218                 int maximumYear;
219                 int unused;
220                 Interop.Elementary.elm_calendar_min_max_year_get(RealHandle, out unused, out maximumYear);
221                 if (maximumYear < 1902)
222                 {
223                     maximumYear = DateTime.MaxValue.Year;
224                 }
225                 Interop.Elementary.elm_calendar_min_max_year_set(RealHandle, value, maximumYear);
226             }
227         }
228
229         /// <summary>
230         /// Sets or gets the maximum for the year.
231         /// </summary>
232         public int MaximumYear
233         {
234             get
235             {
236                 int maximumYear;
237                 int unused;
238                 Interop.Elementary.elm_calendar_min_max_year_get(RealHandle, out unused, out maximumYear);
239                 return maximumYear;
240             }
241             set
242             {
243                 int minimumYear;
244                 int unused;
245                 Interop.Elementary.elm_calendar_min_max_year_get(RealHandle, out minimumYear, out unused);
246                 Interop.Elementary.elm_calendar_min_max_year_set(RealHandle, minimumYear, value);
247             }
248         }
249
250         /// <summary>
251         /// Sets or gets the first day of week, who are used on Calendar.
252         /// </summary>
253         public DateTime DisplayedTime
254         {
255             get
256             {
257                 var tm = new Interop.Libc.SystemTime();
258                 Interop.Elementary.elm_calendar_displayed_time_get(RealHandle, out tm);
259                 ///TODO
260                 ///If the defect is fixed, it will be removed.
261                 var daysInMonth = DateTime.DaysInMonth(tm.tm_year + 1900, tm.tm_mon + 1);
262                 var day = tm.tm_mday;
263
264                 if (day > daysInMonth)
265                 {
266                     day = daysInMonth;
267                 }
268
269                 DateTime date = new DateTime(tm.tm_year + 1900, tm.tm_mon + 1, day, tm.tm_hour, tm.tm_min, tm.tm_sec);
270
271                 return date;
272             }
273         }
274
275         /// <summary>
276         /// Sets or gets the first day of week, who are used on Calendar.
277         /// </summary>
278         public DayOfWeek FirstDayOfWeek
279         {
280             get
281             {
282                 return (DayOfWeek)Interop.Elementary.elm_calendar_first_day_of_week_get(RealHandle);
283             }
284             set
285             {
286                 Interop.Elementary.elm_calendar_first_day_of_week_set(RealHandle, (int)value);
287             }
288         }
289
290         /// <summary>
291         /// Sets or gets the weekdays names to be displayed by the Calendar.
292         /// </summary>
293         /// <remarks>
294         /// The usage should be like this;
295         /// List<string> weekDayNames = new List<string>() { "S", "M", "T", "W", "T", "F", "S" };
296         /// Calendar.WeekDayNames = weekDayNames;
297         /// </remarks>
298         public IReadOnlyList<string> WeekDayNames
299         {
300             get
301             {
302                 IntPtr stringArrayPtr = Interop.Elementary.elm_calendar_weekdays_names_get(RealHandle);
303                 string[] stringArray;
304                 IntPtrToStringArray(stringArrayPtr, 7, out stringArray);
305                 return stringArray;
306             }
307             set
308             {
309                 if (value != null && value.Count == 7)
310                 {
311                     Interop.Elementary.elm_calendar_weekdays_names_set(RealHandle, value.ToArray());
312                 }
313             }
314         }
315
316         /// <summary>
317         /// Sets or gets the selected date.
318         /// </summary>
319         /// <remarks>
320         /// Selected date changes when the user goes to next/previous month or select a day pressing over it on calendar.
321         /// </remarks>
322         public DateTime SelectedDate
323         {
324             get
325             {
326                 var tm = new Interop.Libc.SystemTime();
327                 Interop.Elementary.elm_calendar_selected_time_get(RealHandle, ref tm);
328                 if (tm.tm_year == 0 && tm.tm_mon == 0 && tm.tm_mday == 0)
329                 {
330                     return DateTime.Now;
331                 }
332                 return tm;
333             }
334             set
335             {
336                 Interop.Libc.SystemTime tm = value;
337                 Interop.Elementary.elm_calendar_selected_time_set(RealHandle, ref tm);
338                 _cacheSelectedDate = value;
339             }
340         }
341
342         /// <summary>
343         /// Sets or gets the interval on time updates for an user mouse button
344         /// hold on calendar widgets' month/year selection.
345         /// </summary>
346         public double Interval
347         {
348             get
349             {
350                 return Interop.Elementary.elm_calendar_interval_get(RealHandle);
351             }
352             set
353             {
354                 Interop.Elementary.elm_calendar_interval_set(RealHandle, value);
355             }
356         }
357
358         /// <summary>
359         /// Gets or sets the select day mode used.
360         /// </summary>
361         public CalendarSelectMode SelectMode
362         {
363             get
364             {
365                 return (CalendarSelectMode)Interop.Elementary.elm_calendar_select_mode_get(RealHandle);
366             }
367             set
368             {
369                 Interop.Elementary.elm_calendar_select_mode_set(RealHandle, (Interop.Elementary.Elm_Calendar_Select_Mode)value);
370             }
371         }
372
373         /// <summary>
374         /// Gets or sets fields of a datetime will be taken into account, when SelectedDate set is invoked.
375         /// </summary>
376         public CalendarSelectable Selectable
377         {
378             get
379             {
380                 return (CalendarSelectable)Interop.Elementary.elm_calendar_selectable_get(RealHandle);
381             }
382             set
383             {
384                 Interop.Elementary.elm_calendar_selectable_set(RealHandle, (int)value);
385             }
386         }
387
388         /// <summary>
389         /// Gets or sets date format the string that will be used to display month and year.
390         /// By default it uses strftime with "%B %Y" format string.
391         /// It should allocate the memory that will be used by the string, that will be freed by the widget after usage.A pointer to the string and a pointer to the time struct will be provided.
392         /// </summary>
393         public DateFormatDelegate DateFormat
394         {
395             get
396             {
397                 return _dateFormatDelegate;
398             }
399             set
400             {
401                 _dateFormatDelegate = value;
402                 if (value != null)
403                 {
404                     Interop.Elementary.elm_calendar_format_function_set(RealHandle, _calendarFormat);
405                 }
406                 else
407                 {
408                     Interop.Elementary.elm_calendar_format_function_set(RealHandle, null);
409                 }
410             }
411         }
412
413         /// <summary>
414         /// Add a new mark to the calendar.
415         /// </summary>
416         /// <param name="type">A string used to define the type of mark. It will be emitted to the theme, that should display a related modification on these days representation.</param>
417         /// <param name="date">A time struct to represent the date of inclusion of the mark. For marks that repeats it will just be displayed after the inclusion date in the calendar.</param>
418         /// <param name="repeat">Repeat the event following this periodicity. Can be a unique mark (that don't repeat), daily, weekly, monthly or annually.</param>
419         /// <returns>Item for a calendar mark.</returns>
420         public CalendarMark AddMark(string type, DateTime date, CalendarMarkRepeatType repeat)
421         {
422             CalendarMark mark = new CalendarMark(type, date, repeat);
423             Interop.Libc.SystemTime tm = date;
424             IntPtr nativeHandle = Interop.Elementary.elm_calendar_mark_add(RealHandle, type, ref tm, (Interop.Elementary.Elm_Calendar_Mark_Repeat_Type)repeat);
425             mark.Handle = nativeHandle;
426
427             return mark;
428         }
429
430         /// <summary>
431         /// Delete mark from the calendar.
432         /// </summary>
433         /// <param name="mark">Item for a calendar mark</param>
434         public void DeleteMark(CalendarMark mark)
435         {
436             Interop.Elementary.elm_calendar_mark_del(mark.Handle);
437         }
438
439         /// <summary>
440         /// Draw calendar marks.
441         /// </summary>
442         public void DrawMarks()
443         {
444             Interop.Elementary.elm_calendar_marks_draw(RealHandle);
445         }
446
447         /// <summary>
448         /// Remove all calendar's marks.
449         /// </summary>
450         public void ClearMarks()
451         {
452             Interop.Elementary.elm_calendar_marks_clear(RealHandle);
453         }
454
455         protected override IntPtr CreateHandle(EvasObject parent)
456         {
457             IntPtr handle = Interop.Elementary.elm_layout_add(parent.Handle);
458             Interop.Elementary.elm_layout_theme_set(handle, "layout", "elm_widget", "default");
459
460             RealHandle = Interop.Elementary.elm_calendar_add(handle);
461             Interop.Elementary.elm_object_part_content_set(handle, "elm.swallow.content", RealHandle);
462
463             return handle;
464         }
465
466         static void IntPtrToStringArray(IntPtr unmanagedArray, int size, out string[] managedArray)
467         {
468             managedArray = new string[size];
469             IntPtr[] IntPtrArray = new IntPtr[size];
470
471             Marshal.Copy(unmanagedArray, IntPtrArray, 0, size);
472
473             for (int iterator = 0; iterator < size; iterator++)
474             {
475                 managedArray[iterator] = Marshal.PtrToStringAnsi(IntPtrArray[iterator]);
476             }
477         }
478     }
479 }