eb7a1a20d19b5f5358439a74ff7e491d24653863
[sdk] / ecere / src / gui / controls / CalendarControl.ec
1 namespace gui::controls;
2
3 import "Window"
4
5 #define ISLEAP(y) (!((y)%4) && (((y) % 100) || (!((y)% 400))))
6
7 /*static */Array<String> veryShortDaysNames
8 { [
9    $"Sunday"."S", $"Monday"."M", $"Tuesday"."T", $"Wednesday"."W",
10    $"Thursday"."T", $"Friday"."F", $"Saturday"."S"
11 ] };
12
13 public class CalendarControl : CommonControl
14 {
15    class_property(icon) = "<:ecere>controls/calendar.png";
16
17 public:
18    virtual void Window::NotifyChanged(CalendarControl calendarControl, bool close);
19    Date dateValue;
20    Month shownMonth;
21    int shownYear;
22
23 private:
24    background = { 195, 217, 255 };
25    clientSize = { 168, 198 };
26    tabCycle = true;
27
28    bool OnCreate()
29    {
30       if(!dateValue.year && !dateValue.day && !dateValue.month)
31       {
32          DateTime now;
33          now.GetLocalTime();
34          dateValue.day = now.day;
35          dateValue.month = now.month;
36          shownYear = dateValue.year = now.year;
37          shownMonth = dateValue.month;
38       }
39       return true;
40    }
41
42    RepButton leftArrow
43    {
44       this,
45       position = { 3, 8 };
46       size = { 16, 16 };
47       bevel = false;
48       inactive = true;
49       background = background;
50       font = { $"Verdana", 8.25f, true };
51       foreground = navy;
52       offset = false;
53       text = "«";
54       hotKey = pageUp;
55
56       bool NotifyClicked(Button button, int x, int y, ecere::gui::Modifiers mods)
57       {
58          shownMonth--;
59          if(shownMonth < january) { shownMonth = december; shownYear--; yearBox.Refresh(); }
60          monthBox.Refresh();
61          Update(null);
62          dateBox.Activate();
63          return true;
64       }
65    };
66    RepButton rightArrow
67    {
68       this,
69       anchor = { right = 8, top = 8 };
70       size = { 16, 16 };
71       bevel = false;
72       inactive = true;
73       offset = false;
74       background = background;
75       font = { $"Verdana", 8.25f, true };
76       foreground = navy;
77       text = "»";
78       hotKey = pageDown;
79
80       bool NotifyClicked(Button button, int x, int y, ecere::gui::Modifiers mods)
81       {
82          shownMonth++;
83          if(shownMonth > december) { shownMonth = january; shownYear++; yearBox.Refresh(); }
84          monthBox.Refresh();
85          Update(null);
86          dateBox.Activate();
87          return true;
88       }
89    };
90
91    DataBox monthBox
92    {
93       this, type = class(Month), data = &shownMonth, position = { 25, 5 }, size = { 75, 20 };
94       background = background;
95       foreground = navy;
96       font = { $"Verdana", 8.25f, true };
97
98       bool OnPostCreate()
99       {
100          DataBox::OnPostCreate();
101          ((DropBox)editor).showButton = false;
102          ((DropBox)editor).alignment = right;
103          return true;
104       }
105
106       bool NotifyChanged(DataBox dataBox, bool closingDropDown)
107       {
108          Update(null);
109          if(closingDropDown)
110             dateBox.Activate();
111          return true;
112       }
113    };
114    DataBox yearBox
115    {
116       this, type = class(int), data = &shownYear, position = { 100, 5 }, size = { 38, 20 };
117       font = { $"Verdana", 8.25f, true };
118       background = background;
119       foreground = navy;
120
121       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
122       {
123          if(!active)
124          {
125             SaveData();
126          }
127          return true;
128       }
129
130       bool OnPostCreate()
131       {
132          DataBox::OnPostCreate();
133          ((EditBox)editor).textHorzScroll = false;
134          return true;
135       }
136
137       bool NotifyChanged(DataBox dataBox, bool closingDropDown)
138       {
139          if(shownYear < 100)
140          {
141             DateTime time;
142             time.GetLocalTime();
143             shownYear += (time.year / 100) * 100;
144             if(Abs(shownYear - time.year) >= 50)
145                shownYear -= 100;
146             yearBox.Refresh();
147          }
148          Update(null);
149          dateBox.Activate();
150          return true;
151       }
152    };
153 #define  Height   20
154 #define  Width    24
155    void FindDate(int mx, int my, bool changeMonth, bool close)
156    {
157       DayOfTheWeek d;
158       int x, y;
159       int w;
160       Date day = { shownYear, shownMonth, 1 };
161       d = day.dayOfTheWeek;
162       day.day -= 7 + (d % 7);
163       if(day.day < 1)
164       {
165          if(--day.month < january)
166          {
167             day.month = december;
168             day.year--;
169          }
170          day.day += monthLengths[ISLEAP(day.year)][day.month];
171       }
172
173       y = 5 + Height;
174       for(w = 0; w<7; w++, y += Height)
175       {
176          for(x = Width / 2, d = sunday; d <= saturday; d++, x += Width)
177          {
178             if(mx >= x-10 && my >= y && mx <= x+10 && my <= y+15 && (day.month == shownMonth || changeMonth))
179             {
180                bool closeCalendar = close && dateValue.day == day.day && dateValue.month == day.month && dateValue.year == day.year;
181                dateValue = day;
182                shownMonth = day.month;
183                shownYear = day.year;
184                Update(null);
185                monthBox.Refresh();
186                yearBox.Refresh();
187
188                NotifyChanged(master, this, closeCalendar);
189                return;
190             }
191             if(++day.day > monthLengths[ISLEAP(day.year)][day.month])
192             {
193                day.day = 1;
194                if(++day.month > december)
195                {
196                   day.year++;
197                   day.month = january;
198                }
199             }
200          }
201       }
202    }
203    Window dateBox
204    {
205       this, anchor = { top = 30, left = 0, right = 0, bottom = 0 };
206
207       bool OnMouseMove(int x, int y, Modifiers mods)
208       {
209          if(mods.left && !mods.isSideEffect)
210             ((CalendarControl)master).FindDate(x, y, false, false);
211          return true;
212       }
213       bool OnLeftButtonDown(int x, int y, Modifiers mods)
214       {
215          ((CalendarControl)master).FindDate(x, y, false, true);
216          return true;
217       }
218       bool OnLeftButtonUp(int x, int y, Modifiers mods)
219       {
220          ((CalendarControl)master).FindDate(x, y, true, false);
221          return true;
222       }
223
224       void OnRedraw(Surface surface)
225       {
226          CalendarControl dateEditor = (CalendarControl)master;
227          DayOfTheWeek d;
228          int x, y;
229          int w;
230          Date day = { dateEditor.shownYear, dateEditor.shownMonth, 1 };
231          d = day.dayOfTheWeek;
232          day.day -= 7 + (d % 7);
233          if(day.day < 1)
234          {
235             if(--day.month < january)
236             {
237                day.month = december;
238                day.year--;
239             }
240             day.day += monthLengths[ISLEAP(day.year)][day.month];
241          }
242
243          surface.SetBackground(dateEditor.background);
244          surface.Area(0, 0, clientSize.w, Height-1);
245
246          surface.SetForeground(black);
247          for(d = sunday; d <= saturday; d++)
248          {
249             surface.CenterTextf(Width / 2 + d * Width, 0, "%s", veryShortDaysNames[d]);
250          }
251
252          surface.SetBackground(Color { 238, 238, 238 } /*whiteSmoke*/);
253          surface.Area(0, Height, Width, clientSize.h);
254          surface.Area(6 * Width, Height, 7*Width, clientSize.h);
255
256          surface.SetForeground(lightGray);
257          surface.DrawLine(0, Height, clientSize.w, Height);
258          surface.DrawLine(0, Height, 0, clientSize.h);
259          surface.SetForeground(dateEditor.background);
260          surface.DrawLine(clientSize.w-1, Height, clientSize.w-1, clientSize.h);
261          surface.DrawLine(0, clientSize.h-1, clientSize.w, clientSize.h-1);
262
263          y = 5 + Height;
264          for(w = 0; w<7; w++, y += Height)
265          {
266             for(x = Width / 2, d = sunday; d <= saturday; d++, x += Width)
267             {
268                if(day.year == dateEditor.dateValue.year && day.month == dateEditor.dateValue.month && day.day == dateEditor.dateValue.day)
269                {
270                   surface.SetBackground(navy);
271                   surface.Area(x - 10, y, x + 10, y + 15);
272                   if(day.month == dateEditor.shownMonth)
273                      surface.SetForeground(white);
274                   else
275                      surface.SetForeground(gray);
276                }
277                else if(day.month == dateEditor.shownMonth)
278                   surface.SetForeground(black);
279                else
280                   surface.SetForeground(gray);
281
282                surface.CenterTextf(x, y, "%d", day.day);
283                if(++day.day > monthLengths[ISLEAP(day.year)][day.month])
284                {
285                   day.day = 1;
286                   if(++day.month > december)
287                   {
288                      day.year++;
289                      day.month = january;
290                   }
291                }
292             }
293          }
294       }
295    };
296
297    bool OnKeyHit(Key key, unichar ch)
298    {
299       switch((Key)(SmartKey) key)         // Because it's inside ecere.dll and no property interpretation yet
300       {
301          case left:
302          case up:
303          case right:
304          case down:
305             if(dateBox.active)
306             {
307                if(shownMonth != dateValue.month || shownYear != dateValue.year)
308                {
309                   dateValue.month = shownMonth;
310                   dateValue.year = shownYear;
311                   dateValue.day = 1;
312                }
313                else if(key == left) dateValue.day--;
314                else if(key == right) dateValue.day++;
315                else if(key == up) dateValue.day-=7;
316                else if(key == down) dateValue.day+=7;
317                if(dateValue.day < 1)
318                {
319                   if(--dateValue.month < january)
320                   {
321                      dateValue.month = december;
322                      dateValue.year--;
323                   }
324                   dateValue.day += monthLengths[ISLEAP(dateValue.year)][dateValue.month];
325                }
326                else if(dateValue.day > monthLengths[ISLEAP(dateValue.year)][dateValue.month])
327                {
328                   dateValue.day -= monthLengths[ISLEAP(dateValue.year)][dateValue.month];
329                   if(++dateValue.month > december)
330                   {
331                      dateValue.year++;
332                      dateValue.month = january;
333                   }
334                }
335                shownMonth = dateValue.month;
336                shownYear = dateValue.year;
337                NotifyChanged(master, this, false);
338
339                monthBox.Refresh();
340                yearBox.Refresh();
341                Update(null);
342             }
343             return false;
344       }
345       return true;
346    }
347
348    bool OnPostCreate()
349    {
350       if(active)
351          dateBox.Activate();
352       return true;
353    }
354 }