1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
|
(***********************************************************************)
(* Clock *)
(* *)
(* Maxence Guesdon, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 2001 Institut National de Recherche en Informatique et *)
(* en Automatique. All rights reserved. This file is distributed *)
(* under the terms of the Q Public License version 1.0. *)
(* *)
(***********************************************************************)
open Camltk;;
(** Diameter of the clock. *)
let diametre = ref 200;;
(** Background color. *)
let background_color = ref "White";;
(** Total major time for 360 degrees (in miliseconds) *)
let base_major = ref 3600000.0;;
(** Total minor time for 360 degrees (in miliseconds) *)
let base_minor = ref 60000.0;;
(** Color of the major hand. *)
let color_major = ref "FireBrick";;
(** Color of the minor hand. *)
let color_minor = ref "Blue";;
(** Width of the major hand. *)
let width_major = ref 2;;
(** Width of the major hand. *)
let width_minor = ref 1;;
(** Width of the circle. *)
let width_circle = ref 0;;
(** Refresh frequency (in milliseconds). *)
let frequency = ref 1000.0;;
(** Reverse or not. *)
let reverse = ref false;;
(** Total time, in theory :-), in milliseconds. *)
let total_time = ref 1800000.0;;
(** Color for the authorized time interval. *)
let color_ok = ref "PaleGreen2";;
(** Color for the done time interval. *)
let color_done = ref "Turquoise3";;
(** Color for the 'you're late' time interval. *)
let color_overtime = ref "Red";;
(** Predefined times (in milliseconds). *)
let times = ref ([] : float list);;
(** The filename of the interface file. *)
let filename = ref (None : string option);;
let pi = 4.0 *. atan 1.0;;
let base_x = 2;;
let base_y = 2;;
module Args = struct
let options = [
"-d", Arg.Int (fun d -> diametre := d),
"<d> Use <d> as the diameter of the clock";
"-bg", Arg.String (fun c -> background_color := c),
"<color> Set the background color";
"-wc", Arg.Int (fun n -> width_circle := n),
"<n> Use <n> as the width of the circle line";
"-W", Arg.Int (fun n -> width_major := n),
"<n> Use <n> as the width of the major hand";
"-w", Arg.Int (fun n -> width_minor := n),
"<n> Use <n> as the width of the minor hand";
"-C", Arg.String (fun s -> color_major := s),
"<color> Set the color name used for the major hand";
"-c", Arg.String (fun s -> color_minor := s),
"<color> Set the color name used for the minor hand";
"-B", Arg.Float (fun f -> base_major := f),
"<base> Set the value for 360 of the major hand \
(float, in milliseconds)";
"-b", Arg.Float (fun f -> base_minor := f),
"<base> Set the value for 360 of the minor hand \
(float, in milliseconds)";
"-rev", Arg.Set reverse, " Countdown style";
"-time", Arg.Float (fun m -> total_time := (m *. 60000.)),
"<time> Theoretical total time in minutes";
"-f", Arg.Float (fun f -> frequency := f),
"<f> Set the refresh frequency (in milliseconds, default is 1000.0)";
"-file", Arg.String (fun f -> filename := Some f),
"<file> Use <file> to read the current slide number \
when receiving SIGUSR1";
"-done", Arg.String (fun s -> color_done := s),
"<color> Set the color name used for the done sectors";
"-ok", Arg.String (fun s -> color_ok := s),
"<color> Set the color name used for the sectors not done yet";
"-over", Arg.String (fun s -> color_overtime := s),
"<color> Set the color name used for the overtime";
]
let parse () = Arg.parse
(keywords @ options)
(fun s ->
try times := !times @ [ float_of_string s *. 1000.0] with
| Invalid_argument err ->
prerr_endline
(Printf.sprintf "Invalid_argument %s : %s" err s)
)
(Printf.sprintf
"usage : %s [options] t1 t2 ... (in seconds)\nOptions are:"
Sys.argv.(0))
end;;
let opencamltk () =
Args.parse ();
opentk ();;
type clock = {
widget : Widget.widget;
mutable major : tagOrId;
mutable minor : tagOrId;
mutable major_elapsed : float;
mutable minor_elapsed : float;
};;
let compute_coord rayon base_time time =
let angle = (time /. base_time) *. (2. *. pi) in
let x = cos angle *. float_of_int rayon in
let y = sin angle *. float_of_int rayon in
(int_of_float y, - (int_of_float x));;
let options_circle () =
[Width (Pixels !width_circle)];;
let options_major () =
[Width (Pixels !width_major); FillColor (NamedColor !color_major)];;
let options_minor () =
[Width (Pixels !width_minor); FillColor (NamedColor !color_minor)];;
let draw_major c =
Canvas.delete c.widget [c.major];
let d = !diametre in
let r = d / 2 in
let (x,y) = compute_coord r !base_major c.major_elapsed in
c.major <-
Canvas.create_line c.widget
[ Pixels (base_x + r); Pixels (base_y + r);
Pixels (base_x + r + x); Pixels(base_y + r + y)]
(options_major ());;
let draw_minor c =
Canvas.delete c.widget [c.minor];
let d = !diametre in
let r = d / 2 in
let (x,y) = compute_coord r !base_minor c.minor_elapsed in
c.minor <-
Canvas.create_line c.widget
[ Pixels (base_x + r); Pixels (base_y + r);
Pixels (r + x); Pixels(r + y)]
(options_minor ());;
let create_clock () =
let top = opencamltk () in
Toplevel.configure top [Background (NamedColor !background_color) ] ;
let d = !diametre in
let r = d / 2 in
let w = Canvas.create top [Background (NamedColor !background_color)] in
pack [w] [Expand true; Fill Fill_Both ];
if !width_circle > 0 then ignore (
Canvas.create_oval w
(Pixels base_x) (Pixels base_y)
(Pixels (base_x + d)) (Pixels (base_y + d))
(options_circle ()));
let clock =
{
widget = w;
major =
Canvas.create_line w
[ Pixels (base_x + r); Pixels (base_y + r);
Pixels (base_x + r); Pixels base_y] (options_major ());
minor =
Canvas.create_line w
[ Pixels (base_x + r); Pixels (base_y + r);
Pixels (base_x + r); Pixels base_y] (options_minor ());
major_elapsed = (if !reverse then !total_time else 0.0);
minor_elapsed = 0.0;
}
in
draw_major clock;
draw_minor clock;
clock;;
let draw_overtime_arc c old_major =
let d = !diametre in
let inf = if !reverse then 0.0 else -. !total_time in
let angle_base = 360.0 in
let angle_inf = (inf /. !base_major) *. angle_base +. 90.0 in
let angle_sup =
if !reverse then
-. ((c.major_elapsed /. !base_major) *. angle_base)
else
-. (((c.major_elapsed -. !total_time) /. !base_major) *. angle_base)
(* -. ((c.major_elapsed /. !base_major) *. angle_base +. inf) *)
in
(* prerr_endline
(Printf.sprintf "overtime inf=%f sup=%f" angle_inf angle_sup); *)
let arc =
Canvas.create_arc c.widget
(Pixels base_x) (Pixels base_y)
(Pixels (base_x + d)) (Pixels (base_y + d))
[ Start angle_inf; Extent angle_sup;
FillColor (NamedColor !color_overtime);
ArcStyle PieSlice; Outline (NamedColor !color_overtime)]
in
();;
let create_secteurs clock times =
let rec iter acc = function
| [] -> []
| t :: q ->
let d = !diametre in
let angle_base = 360.0 in
let inf = if !reverse then -. !total_time +. acc else -. acc in
let angle_inf = (inf /. !base_major) *. angle_base +. 90.0 in
let new_acc = acc +. t in
if !total_time < (-. new_acc) then
(prerr_endline
"The sum of the given times is greater than the total time.";
[])
else
(
let angle_sup_pre = (-. t /. !base_major) *. angle_base in
let angle_sup =
if !reverse then -. angle_sup_pre else angle_sup_pre in
(*Printf.printf "overtime inf=%f sup%f new_acc=%f"
angle_inf angle_sup new_acc; print_newline ();*)
let arc =
Canvas.create_arc clock.widget (Pixels base_x) (Pixels base_y)
(Pixels (base_x + d)) (Pixels (base_y + d))
[Start angle_inf; Extent angle_sup;
FillColor (NamedColor !color_ok);
ArcStyle PieSlice; Outline (NamedColor "Black")]
in
arc :: iter new_acc q
)
in
iter 0.0 times;;
let clock = create_clock ();;
let secteurs = create_secteurs clock !times;;
let current_secteur = ref 0;;
let secteurs_done = ref ([] : int list);;
let last_time = ref (Unix.time ());;
let rec set_time freq c () =
let new_time = Unix.time () in
let gain = (new_time -. !last_time) *. 1000.0 in
c.minor_elapsed <-
(if !reverse then c.minor_elapsed -. gain else c.minor_elapsed +. gain);
let old_major = c.major_elapsed in
c.major_elapsed <-
(if !reverse then c.major_elapsed -. gain else c.major_elapsed +. gain);
if c.major_elapsed > !total_time || c.major_elapsed < 0.0
then draw_overtime_arc c old_major;
draw_minor c;
draw_major c;
last_time := new_time;
ignore (Timer.add (int_of_float freq) (set_time freq c));;
let handle_signal clock =
let must_colorize =
match !filename with
| None -> true
| Some f ->
try
let ic = open_in f in
let n = int_of_string (input_line ic) in
close_in ic;
let b = List.mem n !secteurs_done in
if not b then secteurs_done := n :: !secteurs_done;
not b
with
| Sys_error s -> prerr_endline s; false
| _ -> false
in
if must_colorize then
try
let sec = List.nth secteurs !current_secteur in
incr current_secteur;
Canvas.configure_arc clock.widget sec
[FillColor (NamedColor !color_done)]
with _ -> ();;
Sys.set_signal Sys.sigusr1 (Sys.Signal_handle (fun _ -> handle_signal clock));;
ignore (Timer.add (int_of_float !frequency) (set_time !frequency clock));;
mainLoop ();;
|