4 (* Needs Unix module, so use with lablgtk_t *)
8 type date = { mutable year: int; mutable mon: int; mutable mday: int }
10 (* Load the schedule data *)
11 let calendar_file = Filename.concat (Sys.getenv "HOME") ".camlendar"
15 let ichan = open_in calendar_file in
16 let (s : (int * int * int, string) Hashtbl.t) =
17 Marshal.from_channel ichan in
21 prerr_endline msg; flush stderr;
24 (* Saves the schedule data when the application terminates *)
26 let ochan = open_out calendar_file in
27 Marshal.to_channel ochan schedule ~mode: [];
30 (* date: Current date initialized to "today" *)
32 let tm = Unix.localtime (Unix.time ()) in
33 { year = 1900 + tm.Unix.tm_year; mon = tm.Unix.tm_mon; mday = 1 }
36 (* previous_month, next_month: change application status *)
37 let previous_month () =
40 (date.year <- date.year - 1; date.mon <- 11)
41 else date.mon <- date.mon - 1
45 if date.mon = 11 then (date.year <- date.year + 1; date.mon <- 0)
46 else date.mon <- date.mon + 1
48 (* leap, mon_name, wday_name: Calendar related function and data *)
51 (year mod 4 = 0) & (year mod 100 <> 0)
53 let mdays_in_month = [|31; 28; 31; 30; 31; 30; 31; 31; 30; 31; 30; 31|]
56 [|"Jan"; "Feb"; "Mar"; "Apr"; "May"; "Jun";
57 "Jul"; "Aug"; "Sep"; "Oct"; "Nov"; "Dec"|]
60 [|"Sun"; "Mon"; "Tue"; "Wed"; "Thu"; "Fri"; "Sat"|]
62 let s_normal = 0 and s_focused = 1 and s_planned = 2
64 let default = (Obj.magic () : GObj.style) in
65 [| default; default; default |]
67 (* class date_button: one button for each day in the month *)
68 class date_button i (calendar : GPack.table) =
72 val widget = GButton.button ~label: (string_of_int mday) ~show: false ()
74 val mutable show = false
75 val mutable have_plan = false
77 method widget = widget
80 widget#misc#set_style styles.(s_focused)
82 widget#misc#set_style styles.(if have_plan then s_planned else s_normal)
85 widget#misc#set_style styles.(s_planned)
88 widget#misc#set_style styles.(s_normal)
92 let top = (mday + wday0) / 7 + 1
93 and left = (mday + wday0) mod 7 in
94 calendar#attach ~left ~top ~expand:`BOTH widget#coerce;
100 (widget#misc#hide ();
101 calendar#remove widget#coerce;
105 let update_calendar (calendar : GPack.table) (buttons : date_button array) =
106 let now = Unix.localtime (Unix.gettimeofday ()) in
107 let _, first = Unix.mktime { now with
109 Unix.tm_mon = date.mon;
110 Unix.tm_year = date.year - 1900 } in
112 (* wday0: day of the week of the zero'th day in the month *)
113 let wday0 = (first.Unix.tm_wday - 1 + 7) mod 7 in
116 if date.mon = 1 & leap date.year then mdays_in_month.(date.mon) + 1
117 else mdays_in_month.(date.mon) in
119 Array.iter ~f: (fun button -> button#hide)
122 for i = 0 to ndays - 1 do buttons.(i)#show wday0 done
129 GWindow.window ~title: "Camlendar" ~show: true
130 ~allow_shrink: false ~allow_grow: false () in
131 win#event#connect#delete
132 ~callback: (fun _ -> GMain.Main.quit (); exit 0; false);
134 let style = win#misc#style#copy in
135 styles.(s_normal) <- style;
137 let style = style#copy in
138 style#set_bg [`NORMAL, `NAME "light green";
139 `PRELIGHT, `NAME "light green"];
140 styles.(s_focused) <- style;
142 styles.(s_focused) <- style;
143 let style = style#copy in
144 style#set_bg [`NORMAL, `NAME "sky blue";
145 `PRELIGHT, `NAME "sky blue"];
146 styles.(s_planned) <- style;
148 let vbox = GPack.vbox ~packing: win#add () in
149 let packing = vbox#add in
150 let toolbar = GButton.toolbar ~style: `TEXT ~packing () in
153 toolbar#insert_button ~text: "Prev" ~tooltip: "Show previous month" () in
155 toolbar#insert_button ~text: "Next" ~tooltip: "Show next month" () in
158 GPack.table ~homogeneous: true ~rows: 7 ~columns: 7
159 ~border_width: 10 ~row_spacings: 2 ~col_spacings: 2 ~packing () in
163 ignore (GButton.button ~label: wday
164 ~packing:(calendar#attach ~top: 0 ~left: i ~expand:`BOTH) ()))
168 Array.init 31 ~f: (fun i -> new date_button i calendar) in
170 let date_view = GMisc.label ~justify: `CENTER ~packing () in
172 let text = GEdit.text ~editable: true ~width: 70 ~height: 50 ~packing () in
177 let data = text#get_chars ~start: 0 ~stop: text#length in
178 let key = (date.year, date.mon, date.mday) in
179 Hashtbl.remove schedule key;
181 (Hashtbl.add schedule ~key ~data;
182 buttons.(date.mday - 1)#set_plan)
183 else buttons.(date.mday - 1)#unset_plan in
185 let restore_text () =
186 text#delete_text ~start: 0 ~stop: text#length;
188 text#insert_text ~pos: 0
189 (Hashtbl.find schedule (date.year, date.mon, date.mday));
191 with Not_found -> () in
193 let update_date_view () =
194 date_view#set_text (sprintf "%d %s, %d\n"
195 date.mday mon_name.(date.mon) date.year) in
198 update_calendar calendar buttons;
200 Array.iteri ~f: (fun i button ->
202 Hashtbl.find schedule (date.year, date.mon, i + 1);
204 with Not_found -> button#unset_plan);
205 button#focus_off) buttons;
206 win#set_title (sprintf "Camlendar: %s, %d"
207 mon_name.(date.mon) date.year) in
210 ~callback: (fun () ->
216 buttons.(0)#focus_on);
219 ~callback: (fun () ->
225 buttons.(0)#focus_on);
229 button#widget#connect#clicked
230 ~callback: (fun () ->
232 buttons.(date.mday - 1)#focus_off;
236 update_date_view ());
241 buttons.(0)#focus_on;;
244 print_endline (GtkMain.Main.set_locale ());