/*
* Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace ElmSharp
{
///
/// 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.
///
public enum CalendarMarkRepeatType
{
///
/// Default value. Marks will be displayed only on event day.
///
Unique,
///
/// Marks will be displayed every day after event day.
///
Daily,
///
/// Marks will be displayed every week after event day.
///
Weekly,
///
/// Marks will be displayed every month day that coincides to event day.
///
Monthly,
///
/// Marks will be displayed every year that coincides to event day.
///
Annually,
///
/// Marks will be displayed every last day of month after event day.
///
LastDayOfMonth
}
///
/// Enumeration for the mode, which determine how user could select a day.
///
public enum CalendarSelectMode
{
///
/// Default value. a day is always selected.
///
Default,
///
/// A day is always selected.
///
Always,
///
/// None of the days can be selected.
///
None,
///
/// User may have selected a day or not.
///
OnDemand
}
///
/// Enumeration used to define which fields of a tm struct will be taken into account
///
[Flags]
public enum CalendarSelectable
{
///
/// None will be taken into account
///
None = 0,
///
/// Year will be taken into account
///
Year = 1 << 0,
///
/// Month will be taken into account
///
Month = 1 << 1,
///
/// Day will be taken into account
///
Day = 1 << 2
}
///
/// The CalendarMark is a Item for marking a Calendar's type,date and repeat type.
///
public class CalendarMark
{
internal IntPtr Handle;
///
/// A string used to define the type of mark.
///
public string Type;
///
/// A time struct to represent the date of inclusion of the mark.
///
public DateTime Date;
///
/// Repeat the event following this periodicity.
///
public CalendarMarkRepeatType Repeat;
///
/// Creates and initializes a new instance of the CalendarMark class.
///
/// Type of mark
/// Date of inclusion of the mark
/// Repeat type
public CalendarMark(string type, DateTime date, CalendarMarkRepeatType repeat)
{
Handle = IntPtr.Zero;
Type = type;
Date = date;
Repeat = repeat;
}
}
///
/// The Calendar is a widget that helps applications to flexibly display a calender with day of the week, date, year and month.
///
public class Calendar : Layout
{
SmartEvent _changed;
DateTime _cacheSelectedDate;
SmartEvent _displayedMonthChanged;
int _cacheDisplayedMonth;
Interop.Elementary.Elm_Calendar_Format_Cb _calendarFormat;
DateFormatDelegate _dateFormatDelegate = null;
///
/// Creates and initializes a new instance of the Calendar class.
///
///
/// The EvasObject to which the new Calendar will be attached as a child.
///
public Calendar(EvasObject parent) : base(parent)
{
_changed = new SmartEvent(this, this.RealHandle, "changed");
_changed.On += (sender, e) =>
{
DateTime selectedDate = SelectedDate;
DateChanged?.Invoke(this, new DateChangedEventArgs(_cacheSelectedDate, selectedDate));
_cacheSelectedDate = selectedDate;
};
_displayedMonthChanged = new SmartEvent(this, this.RealHandle, "display,changed");
_displayedMonthChanged.On += (sender, e) =>
{
int currentDisplayedMonth = DisplayedTime.Month;
DisplayedMonthChanged?.Invoke(this, new DisplayedMonthChangedEventArgs(_cacheDisplayedMonth, currentDisplayedMonth));
_cacheDisplayedMonth = currentDisplayedMonth;
};
_calendarFormat = (t) => { return _dateFormatDelegate(t); };
}
///
/// DateChanged will be triggered when the date in the calendar is changed.
///
public event EventHandler DateChanged;
///
/// DisplayedMonthChanged will be triggered when the current month displayed in the calendar is changed.
///
public event EventHandler DisplayedMonthChanged;
///
/// This delegate type is used to format the string that will be used to display month and year.
///
/// DateTime
///
public delegate string DateFormatDelegate(DateTime time);
///
/// Sets or gets the minimum for year.
///
public int MinimumYear
{
get
{
int minimumYear;
int unused;
Interop.Elementary.elm_calendar_min_max_year_get(RealHandle, out minimumYear, out unused);
return minimumYear;
}
set
{
int maximumYear;
int unused;
Interop.Elementary.elm_calendar_min_max_year_get(RealHandle, out unused, out maximumYear);
if (maximumYear < 1902)
{
maximumYear = DateTime.MaxValue.Year;
}
Interop.Elementary.elm_calendar_min_max_year_set(RealHandle, value, maximumYear);
}
}
///
/// Sets or gets the maximum for the year.
///
public int MaximumYear
{
get
{
int maximumYear;
int unused;
Interop.Elementary.elm_calendar_min_max_year_get(RealHandle, out unused, out maximumYear);
return maximumYear;
}
set
{
int minimumYear;
int unused;
Interop.Elementary.elm_calendar_min_max_year_get(RealHandle, out minimumYear, out unused);
Interop.Elementary.elm_calendar_min_max_year_set(RealHandle, minimumYear, value);
}
}
///
/// Sets or gets the first day of week, who are used on Calendar.
///
public DateTime DisplayedTime
{
get
{
var tm = new Interop.Libc.SystemTime();
Interop.Elementary.elm_calendar_displayed_time_get(RealHandle, out tm);
///TODO
///If the defect is fixed, it will be removed.
var daysInMonth = DateTime.DaysInMonth(tm.tm_year + 1900, tm.tm_mon + 1);
var day = tm.tm_mday;
if (day > daysInMonth)
{
day = daysInMonth;
}
DateTime date = new DateTime(tm.tm_year + 1900, tm.tm_mon + 1, day, tm.tm_hour, tm.tm_min, tm.tm_sec);
return date;
}
}
///
/// Sets or gets the first day of week, who are used on Calendar.
///
public DayOfWeek FirstDayOfWeek
{
get
{
return (DayOfWeek)Interop.Elementary.elm_calendar_first_day_of_week_get(RealHandle);
}
set
{
Interop.Elementary.elm_calendar_first_day_of_week_set(RealHandle, (int)value);
}
}
///
/// Sets or gets the weekdays names to be displayed by the Calendar.
///
///
/// The usage should be like this;
/// List weekDayNames = new List() { "S", "M", "T", "W", "T", "F", "S" };
/// Calendar.WeekDayNames = weekDayNames;
///
public IReadOnlyList WeekDayNames
{
get
{
IntPtr stringArrayPtr = Interop.Elementary.elm_calendar_weekdays_names_get(RealHandle);
string[] stringArray;
IntPtrToStringArray(stringArrayPtr, 7, out stringArray);
return stringArray;
}
set
{
if (value != null && value.Count == 7)
{
Interop.Elementary.elm_calendar_weekdays_names_set(RealHandle, value.ToArray());
}
}
}
///
/// Sets or gets the selected date.
///
///
/// Selected date changes when the user goes to next/previous month or select a day pressing over it on calendar.
///
public DateTime SelectedDate
{
get
{
var tm = new Interop.Libc.SystemTime();
Interop.Elementary.elm_calendar_selected_time_get(RealHandle, ref tm);
if (tm.tm_year == 0 && tm.tm_mon == 0 && tm.tm_mday == 0)
{
return DateTime.Now;
}
return tm;
}
set
{
Interop.Libc.SystemTime tm = value;
Interop.Elementary.elm_calendar_selected_time_set(RealHandle, ref tm);
_cacheSelectedDate = value;
}
}
///
/// Sets or gets the interval on time updates for an user mouse button
/// hold on calendar widgets' month/year selection.
///
public double Interval
{
get
{
return Interop.Elementary.elm_calendar_interval_get(RealHandle);
}
set
{
Interop.Elementary.elm_calendar_interval_set(RealHandle, value);
}
}
///
/// Gets or sets the select day mode used.
///
public CalendarSelectMode SelectMode
{
get
{
return (CalendarSelectMode)Interop.Elementary.elm_calendar_select_mode_get(RealHandle);
}
set
{
Interop.Elementary.elm_calendar_select_mode_set(RealHandle, (Interop.Elementary.Elm_Calendar_Select_Mode)value);
}
}
///
/// Gets or sets fields of a datetime will be taken into account, when SelectedDate set is invoked.
///
public CalendarSelectable Selectable
{
get
{
return (CalendarSelectable)Interop.Elementary.elm_calendar_selectable_get(RealHandle);
}
set
{
Interop.Elementary.elm_calendar_selectable_set(RealHandle, (int)value);
}
}
///
/// Gets or sets date format the string that will be used to display month and year.
///
public DateFormatDelegate DateFormat
{
get
{
return _dateFormatDelegate;
}
set
{
_dateFormatDelegate = value;
if (value != null)
{
Interop.Elementary.elm_calendar_format_function_set(RealHandle, _calendarFormat);
}
else
{
Interop.Elementary.elm_calendar_format_function_set(RealHandle, null);
}
}
}
///
/// Add a new mark to the calendar.
///
/// 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.
/// 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.
/// Repeat the event following this periodicity. Can be a unique mark (that don't repeat), daily, weekly, monthly or annually.
/// Item for a calendar mark.
public CalendarMark AddMark(string type, DateTime date, CalendarMarkRepeatType repeat)
{
CalendarMark mark = new CalendarMark(type, date, repeat);
Interop.Libc.SystemTime tm = date;
IntPtr nativeHandle = Interop.Elementary.elm_calendar_mark_add(RealHandle, type, ref tm, (Interop.Elementary.Elm_Calendar_Mark_Repeat_Type)repeat);
mark.Handle = nativeHandle;
return mark;
}
///
/// Delete mark from the calendar.
///
/// Item for a calendar mark
public void DeleteMark(CalendarMark mark)
{
Interop.Elementary.elm_calendar_mark_del(mark.Handle);
}
///
/// Draw calendar marks.
///
public void DrawMarks()
{
Interop.Elementary.elm_calendar_marks_draw(RealHandle);
}
///
/// Remove all calendar's marks.
///
public void ClearMarks()
{
Interop.Elementary.elm_calendar_marks_clear(RealHandle);
}
protected override IntPtr CreateHandle(EvasObject parent)
{
IntPtr handle = Interop.Elementary.elm_layout_add(parent.Handle);
Interop.Elementary.elm_layout_theme_set(handle, "layout", "elm_widget", "default");
RealHandle = Interop.Elementary.elm_calendar_add(handle);
Interop.Elementary.elm_object_part_content_set(handle, "elm.swallow.content", RealHandle);
return handle;
}
static void IntPtrToStringArray(IntPtr unmanagedArray, int size, out string[] managedArray)
{
managedArray = new string[size];
IntPtr[] IntPtrArray = new IntPtr[size];
Marshal.Copy(unmanagedArray, IntPtrArray, 0, size);
for (int iterator = 0; iterator < size; iterator++)
{
managedArray[iterator] = Marshal.PtrToStringAnsi(IntPtrArray[iterator]);
}
}
}
}