summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJedidiah Barber <contact@jedbarber.id.au>2022-11-07 03:31:07 +1300
committerJedidiah Barber <contact@jedbarber.id.au>2022-11-07 03:31:07 +1300
commit525863904e8cb1ce62bbbf407262e5305d6bbc6f (patch)
tree68c9cfa61a8d807a08be92a328f27412bfdb3abb
parent95ebd2d6acfa744c5e93287cc6385f4f1359376e (diff)
visualwall now fully working
-rw-r--r--makefile4
-rw-r--r--src/dialog.ml297
-rw-r--r--src/dialog.mli26
-rw-r--r--src/visualwall.ml382
-rw-r--r--src/wall.ml6
-rw-r--r--src/wall.mli2
6 files changed, 613 insertions, 104 deletions
diff --git a/makefile b/makefile
index d502225..dc4cc96 100644
--- a/makefile
+++ b/makefile
@@ -30,8 +30,10 @@ visualwall:
ocamlfind opt -g -linkpkg -I ${SOURCEDIR} \
-o ${OUTPUTDIR}/visualwall \
-package lablgtk2,zarith \
- ${SOURCEDIR}/sequence.mli ${SOURCEDIR}/sequence.ml \
+ ${SOURCEDIR}/util.mli ${SOURCEDIR}/util.ml \
${SOURCEDIR}/wall.mli ${SOURCEDIR}/wall.ml \
+ ${SOURCEDIR}/sequence.mli ${SOURCEDIR}/sequence.ml \
+ ${SOURCEDIR}/dialog.mli ${SOURCEDIR}/dialog.ml \
${SOURCEDIR}/visualwall.ml
wallgen:
diff --git a/src/dialog.ml b/src/dialog.ml
new file mode 100644
index 0000000..826d280
--- /dev/null
+++ b/src/dialog.ml
@@ -0,0 +1,297 @@
+
+
+(* Programmed by Jedidiah Barber *)
+(* Licensed under the Sunset License v1.0 *)
+
+
+let license_text =
+ "SUNSET LICENSE\n" ^
+ "Version 1.0, June 2017\n" ^
+ "\n" ^
+ "1. You may copy, modify, use, sell, or distribute this work, verbatim or\n" ^
+ "modified, for any purpose.\n" ^
+ "\n" ^
+ "2. If you sell or distribute this work, whether verbatim or modified, you must\n" ^
+ "include a copy of this license, and you must make the source code available for\n" ^
+ "no extra charge.\n" ^
+ "\n" ^
+ "3. A modified version of this work must be clearly labeled as such.\n" ^
+ "\n" ^
+ "4. Derivative works must also be licensed under this license or a license of\n" ^
+ "equivalent terms. As an exception, linking this work with another, whether\n" ^
+ "statically or dynamically, does not impose any license requirements on the\n" ^
+ "other work.\n" ^
+ "\n" ^
+ "5. If a minimum of 15 years have passed since the date of first publishing for\n" ^
+ "a part of this work, then that part is placed into the public domain and you\n" ^
+ "may do whatever you want with it, regardless of all other clauses.\n"
+
+
+
+let new_wall () =
+ let newer =
+ GWindow.dialog
+ ~title:"Create New Wall - Number Wall Viewer" () in
+ let dialog_box =
+ GPack.vbox
+ ~border_width:10
+ ~packing:newer#vbox#add () in
+ let frame =
+ GBin.frame
+ ~label:"New Wall"
+ ~packing:dialog_box#add () in
+ let frame_box =
+ GPack.vbox
+ ~border_width:5
+ ~packing:frame#add () in
+ let seq_box =
+ GPack.hbox
+ ~border_width:5
+ ~packing:frame_box#add () in
+ let _ =
+ GMisc.label
+ ~text:"Sequence : "
+ ~packing:seq_box#add () in
+ let seq_combo =
+ GEdit.combo
+ ~popdown_strings:["Pagoda";"Random"]
+ ~allow_empty:false
+ ~case_sensitive:false
+ ~enable_arrow_keys:true
+ ~packing:seq_box#add () in
+ let adj_box =
+ GPack.hbox
+ ~border_width:5
+ ~packing:frame_box#add () in
+ let x_adj =
+ GData.adjustment
+ ~value:200.0
+ ~lower:10.0
+ ~upper:10000.0
+ ~step_incr:1.0
+ ~page_incr:100.0
+ ~page_size:0.0 () in
+ let y_adj =
+ GData.adjustment
+ ~value:200.0
+ ~lower:10.0
+ ~upper:10000.0
+ ~step_incr:1.0
+ ~page_incr:100.0
+ ~page_size:0.0 () in
+ let _ =
+ GMisc.label
+ ~text:"X : "
+ ~packing:adj_box#add () in
+ let _ =
+ GEdit.spin_button
+ ~adjustment:x_adj
+ ~rate:0.0
+ ~digits:0
+ ~wrap:false
+ ~packing:adj_box#add () in
+ let _ =
+ GMisc.label
+ ~text:" Y : "
+ ~packing:adj_box#add () in
+ let _ =
+ GEdit.spin_button
+ ~adjustment:y_adj
+ ~rate:0.0
+ ~digits:0
+ ~wrap:false
+ ~packing:adj_box#add () in
+ newer#add_button_stock `CANCEL `CANCEL;
+ newer#add_button_stock `NEW `NEW;
+ let code = newer#run () in
+ let result = (int_of_float x_adj#value, int_of_float y_adj#value, seq_combo#entry#text) in
+ newer#destroy ();
+ if code = `NEW then Some result else None
+
+
+
+let open_file ?(folder = "") () =
+ let chooser =
+ GWindow.file_chooser_dialog
+ ~action:`OPEN
+ ~title:"Open Sequence - Number Wall Viewer" () in
+ chooser#add_button_stock `CANCEL `dialog;
+ chooser#add_select_button_stock `OPEN `filechooser;
+ ignore (chooser#set_current_folder folder);
+ let code = chooser#run () in
+ let maybe_result = chooser#filename in
+ chooser#destroy ();
+ if code <> `filechooser then None else maybe_result
+
+
+
+let overwrite_check ~filename =
+ if not (Sys.file_exists filename) then
+ true
+ else
+ (let asker =
+ GWindow.dialog
+ ~title:"Confirm Overwrite"
+ ~resizable:false
+ ~width:380 ~height:130 () in
+ let box =
+ GPack.hbox
+ ~packing:asker#vbox#add () in
+ ignore (GMisc.image
+ ~stock:`DIALOG_ERROR
+ ~packing:box#add ());
+ let message =
+ GMisc.label
+ ~text:("Error: " ^ filename ^ " already exists.")
+ ~packing:box#add () in
+ message#set_line_wrap true;
+ asker#add_button "Cancel" `dialog;
+ asker#add_button "Overwrite" `filechooser;
+ let code = asker#run () in
+ asker#destroy ();
+ code = `filechooser)
+
+let save_export_file ~title ?(folder = "") ?(name = "") () =
+ let chooser =
+ GWindow.file_chooser_dialog
+ ~action:`SAVE
+ ~title:title () in
+ chooser#add_button_stock `CANCEL `dialog;
+ chooser#add_select_button_stock `SAVE `filechooser;
+ chooser#set_current_name name;
+ ignore (chooser#set_current_folder folder);
+ let rec get_result chooser =
+ let code = chooser#run () in
+ let choice = chooser#filename in
+ if code <> `filechooser then
+ None
+ else
+ if Option.is_none choice ||
+ overwrite_check ~filename:(Option.get choice)
+ then
+ choice
+ else
+ get_result chooser in
+ let result = get_result chooser in
+ chooser#destroy ();
+ result
+
+let save_file ?(folder = "") ?(name = "") () =
+ save_export_file ~title:"Save Sequence - Number Wall Viewer" ~folder ~name ()
+
+let export_file ?(folder = "") ?(name = "") () =
+ save_export_file ~title:"Export Image - Number Wall Viewer" ~folder ~name ()
+
+
+
+let colors ~fore ~back =
+ let colormap = Gdk.Color.get_system_colormap () in
+ let fore_color = Gdk.Color.alloc ~colormap (`RGB fore) in
+ let back_color = Gdk.Color.alloc ~colormap (`RGB back) in
+ let kaleidoscope =
+ GWindow.dialog
+ ~title:"Change Colors - Number Wall Viewer" () in
+ let dialog_box =
+ GPack.vbox
+ ~border_width:10
+ ~packing:kaleidoscope#vbox#add () in
+ let frame =
+ GBin.frame
+ ~label:"Colors"
+ ~packing:dialog_box#add () in
+ let frame_box =
+ GPack.vbox
+ ~border_width:5
+ ~packing:frame#add () in
+ let fg_box =
+ GPack.hbox
+ ~packing:frame_box#add () in
+ let _ =
+ GMisc.label
+ ~text:"Foreground : "
+ ~packing:fg_box#add () in
+ let fg_button =
+ GButton.color_button
+ ~color:fore_color
+ ~title:"Change Foreground Color"
+ ~packing:fg_box#add () in
+ let bg_box =
+ GPack.hbox
+ ~packing:frame_box#add () in
+ let _ =
+ GMisc.label
+ ~text:"Background : "
+ ~packing:bg_box#add () in
+ let bg_button =
+ GButton.color_button
+ ~color:back_color
+ ~title:"Change Background Color"
+ ~packing:bg_box#add () in
+ kaleidoscope#add_button_stock `CANCEL `CANCEL;
+ kaleidoscope#add_button_stock `APPLY `APPLY;
+ let code = kaleidoscope#run () in
+ let (new_fg, new_bg) = (fg_button#color, bg_button#color) in
+ kaleidoscope#destroy ();
+ let fg_r = Gdk.Color.red new_fg in
+ let fg_g = Gdk.Color.green new_fg in
+ let fg_b = Gdk.Color.blue new_fg in
+ let bg_r = Gdk.Color.red new_bg in
+ let bg_g = Gdk.Color.green new_bg in
+ let bg_b = Gdk.Color.blue new_bg in
+ if code = `APPLY then Some ((fg_r, fg_g, fg_b), (bg_r, bg_g, bg_b)) else None
+
+
+
+let modulus ~current =
+ let changer =
+ GWindow.dialog
+ ~title:"Set Modulus - Number Wall Viewer" () in
+ let dialog_box =
+ GPack.vbox
+ ~border_width:10
+ ~packing:changer#vbox#add () in
+ let frame =
+ GBin.frame
+ ~label:"Modulus"
+ ~packing:dialog_box#add () in
+ let frame_box =
+ GPack.vbox
+ ~border_width:5
+ ~packing:frame#add () in
+ let adj =
+ GData.adjustment
+ ~value:(float_of_int current)
+ ~lower:2.0
+ ~upper:10001.0
+ ~step_incr:1.0
+ ~page_incr:100.0
+ ~page_size:0.0 () in
+ let _ =
+ GEdit.spin_button
+ ~adjustment:adj
+ ~rate:0.0
+ ~digits:0
+ ~wrap:false
+ ~packing:frame_box#add () in
+ changer#add_button_stock `CANCEL `CANCEL;
+ changer#add_button_stock `APPLY `APPLY;
+ let code = changer#run () in
+ let maybe_result = adj#value in
+ changer#destroy ();
+ if code = `APPLY then Some (int_of_float maybe_result) else None
+
+
+
+let about () =
+ let about_window =
+ GWindow.about_dialog
+ ~authors:["Jedidiah Barber"]
+ ~comments:"A simple program to generate and visualise number walls."
+ ~license:license_text
+ ~title:"About - Number Wall Viewer"
+ ~modal:true () in
+ let destroy_me button = about_window#destroy () in
+ ignore (about_window#connect#response ~callback:destroy_me);
+ about_window#show ()
+
+
diff --git a/src/dialog.mli b/src/dialog.mli
new file mode 100644
index 0000000..29bcf12
--- /dev/null
+++ b/src/dialog.mli
@@ -0,0 +1,26 @@
+
+
+(* Programmed by Jedidiah Barber *)
+(* Licensed under the Sunset License v1.0 *)
+
+
+val license_text : string
+
+
+
+val new_wall : unit -> (int * int * string) option
+
+val open_file : ?folder:string -> unit -> string option
+
+val save_file : ?folder:string -> ?name:string -> unit -> string option
+
+val export_file : ?folder:string -> ?name:string -> unit -> string option
+
+val colors : fore:(int * int * int) -> back:(int * int * int) ->
+ ((int * int * int) * (int * int * int)) option
+
+val modulus : current:int -> int option
+
+val about : unit -> unit
+
+
diff --git a/src/visualwall.ml b/src/visualwall.ml
index 3c07363..773f226 100644
--- a/src/visualwall.ml
+++ b/src/visualwall.ml
@@ -4,29 +4,56 @@
(* Licensed under the Sunset License v1.0 *)
+module My_Algebra =
+ struct
+ type t = Z.t
+ let zero = Z.zero
+ let one = Z.one
+ let add = Z.add
+ let sub = Z.sub
+ let mul = Z.mul
+ let div = Z.div
+ let to_string = Z.to_string
+ end
+
+module My_Wall = Wall.Make (My_Algebra)
+
+
+
let main () =
ignore (GtkMain.Main.init ());
- let window = GWindow.window
- ~title:"Number Wall Viewer"
- ~width:250 () in
+ let window =
+ GWindow.window
+ ~title:"Number Wall Viewer"
+ ~width:250 () in
ignore (window#connect#destroy ~callback:GMain.quit);
- let main_vbox = GPack.vbox
- ~packing:window#add () in
+ let main_vbox =
+ GPack.vbox
+ ~packing:window#add () in
+
+ let menubar =
+ GMenu.menu_bar
+ ~packing:(main_vbox#pack ~expand:false) () in
- let menubar = GMenu.menu_bar
- ~packing:(main_vbox#pack ~expand:false) () in
- let wall_view = GBin.scrolled_window
- ~hpolicy:`AUTOMATIC
- ~vpolicy:`AUTOMATIC
- ~packing:(main_vbox#pack ~expand:true) () in
- let statusbar = GMisc.statusbar
- ~packing:(main_vbox#pack ~expand:false) () in
+ let wall_view =
+ GBin.scrolled_window
+ ~hpolicy:`AUTOMATIC
+ ~vpolicy:`AUTOMATIC
+ ~packing:(main_vbox#pack ~expand:true) () in
+ let statusbar =
+ GMisc.statusbar
+ ~packing:(main_vbox#pack ~expand:false) () in
+
+ let context =
+ statusbar#new_context ~name:"Program status" in
+
+ let system_colormap =
+ Gdk.Color.get_system_colormap () in
- let context = statusbar#new_context ~name:"Program status" in
let set_status ~msg =
context#pop ();
@@ -34,130 +61,261 @@ let main () =
- let choose_open_file ~title ?(folder = "") () =
- let chooser = GWindow.file_chooser_dialog
- ~action:`OPEN
- ~title:title () in
- chooser#add_button_stock `CANCEL `dialog;
- chooser#add_select_button_stock `OPEN `filechooser;
- ignore (chooser#set_current_folder folder);
- let code = chooser#run () in
- let maybe_result = chooser#filename in
- chooser#destroy ();
- match maybe_result with
- | None -> ""
- | Some result -> if code = `filechooser then result else "" in
-
- let choose_save_file ~title ?(folder = "") ?(name = "") () =
- let chooser = GWindow.file_chooser_dialog
- ~action:`SAVE
- ~title:title () in
- chooser#add_button_stock `CANCEL `dialog;
- chooser#add_select_button_stock `SAVE `filechooser;
- chooser#set_current_name name;
- ignore (chooser#set_current_folder folder);
- let code = chooser#run () in
- let maybe_result = chooser#filename in
- chooser#destroy ();
- match maybe_result with
- | None -> ""
- | Some result -> if code = `filechooser then result else "" in
+ let number_wall = ref My_Wall.empty in
+ let modulus = ref 2 in
+
+ let magnify = ref 2 in
+
+ (* Default to orange foreground, blue background. *)
+ let foreground_color = ref (65535, 40447, 0) in
+ let background_color = ref (11519, 21247, 65535) in
+
+ let x_dim = ref 1 in
+ let y_dim = ref 1 in
+ let x_offset = ref 0 in
+
+ let wall_loaded = ref false in
+
+
+
+ let expose (drawitem:GMisc.drawing_area) (backing:GDraw.pixmap ref) event =
+ let area = GdkEvent.Expose.area event in
+ let x = Gdk.Rectangle.x area in
+ let y = Gdk.Rectangle.y area in
+ let width = Gdk.Rectangle.width area in
+ let height = Gdk.Rectangle.height area in
+ let drawing =
+ drawitem#misc#realize ();
+ new GDraw.drawable (drawitem#misc#window) in
+ drawing#put_pixmap ~x ~y ~xsrc:x ~ysrc:y ~width ~height !backing#pixmap;
+ false in
+
+ let draw_area =
+ GMisc.drawing_area
+ ~packing:wall_view#add_with_viewport () in
+
+ let pixmap_area = ref
+ (GDraw.pixmap
+ ~width:!x_dim
+ ~height:!y_dim
+ ~window:wall_view
+ ~colormap:system_colormap ()) in
+
+ ignore (draw_area#event#connect#expose ~callback:(expose draw_area pixmap_area));
+ draw_area#event#add [`EXPOSURE];
+
+ let redraw_pixmap () =
+ for j = 0 to !y_dim - 1 do
+ for i = !x_offset to !x_dim + !x_offset - 1 do
+ if My_Wall.has_value !number_wall ~x:i ~y:j &&
+ Z.rem (My_Wall.get !number_wall ~x:i ~y:j) (Z.of_int !modulus) <> My_Algebra.zero
+ then
+ !pixmap_area#set_foreground (`RGB !background_color)
+ else
+ !pixmap_area#set_foreground (`RGB !foreground_color);
+ !pixmap_area#rectangle
+ ~x:((i - !x_offset) * !magnify)
+ ~y:(j * !magnify)
+ ~width:!magnify
+ ~height:!magnify
+ ~filled:true ()
+ done
+ done;
+ let update_rectangle =
+ Gdk.Rectangle.create
+ ~x:0 ~y:0
+ ~width:(!x_dim * !magnify)
+ ~height:(!y_dim * !magnify) in
+ draw_area#misc#draw (Some update_rectangle) in
+
+ let new_pixmap () =
+ pixmap_area :=
+ GDraw.pixmap
+ ~width:(!x_dim * !magnify)
+ ~height:(!y_dim * !magnify)
+ ~window:wall_view
+ ~colormap:system_colormap ();
+ draw_area#misc#set_size_request
+ ~width:(!x_dim * !magnify)
+ ~height:(!y_dim * !magnify) () in
let generate_unused ~basename ~extension =
let rec checker num =
let testname = basename ^ "-" ^ (string_of_int num) ^ "." ^ extension in
- if not (Sys.file_exists testname) then testname else checker (num + 1) in
+ if not (Sys.file_exists testname) then
+ testname
+ else
+ checker (num + 1) in
checker 1 in
- let overwrite_check ~filename =
- if not (Sys.file_exists filename) then true else
- (let asker = GWindow.dialog
- ~title:"Confirm Overwrite"
- ~resizable:false
- ~width:380 ~height:130 () in
- let box = GPack.hbox
- ~packing:asker#vbox#add () in
- let _ = GMisc.image
- ~stock:`DIALOG_ERROR
- ~packing:box#add () in
- let message = GMisc.label
- ~text:("Error: " ^ filename ^ " already exists.")
- ~packing:box#add () in
- message#set_line_wrap true;
- asker#add_button "Cancel" `dialog;
- asker#add_button "Overwrite" `filechooser;
- let code = asker#run () in
- asker#destroy ();
- code = `filechooser) in
+ let menus = ref ([] : (string * GMenu.menu) list) in
+
+ let disable_menu_items menu placelist =
+ let disable nth = (List.nth menu#children nth)#misc#set_sensitive false in
+ List.iter disable placelist in
+
+ let enable_menu_items menu placelist =
+ let enable nth = (List.nth menu#children nth)#misc#set_sensitive true in
+ List.iter enable placelist in
let new_cb () =
- print_endline "New..." in
+ let maybe_new = Dialog.new_wall () in
+ if Option.is_some maybe_new then
+ (let (x,y,s) = Option.get maybe_new in
+ x_dim := x;
+ y_dim := y;
+ x_offset := y;
+ let real_x_dim = x + 2 * y in
+ let real_y_dim = y + x / 2 + 1 in
+ if s = "Pagoda" then
+ number_wall :=
+ My_Wall.create
+ ~dimx:real_x_dim
+ ~dimy:real_y_dim
+ ~init:(Sequence.pagoda ~len:real_x_dim)
+ else
+ number_wall :=
+ My_Wall.create
+ ~dimx:real_x_dim
+ ~dimy:real_y_dim
+ ~init:(Sequence.random ~len:real_x_dim);
+ new_pixmap ();
+ redraw_pixmap ();
+ wall_loaded := true;
+ enable_menu_items (List.assoc "file" !menus) [3;4;6];
+ set_status ~msg:"New wall created")
+ else
+ (set_status ~msg:"Canceled new wall")in
let open_cb () =
- let filename = choose_open_file
- ~title:"Open Sequence - Number Wall Viewer"
- ~folder:(Sys.getcwd ()) () in
- if filename != "" then
- (set_status ~msg:("Opened " ^ filename);
- print_endline filename)
+ let maybe_filename =
+ Dialog.open_file
+ ~folder:(Sys.getcwd ()) () in
+ if Option.is_some maybe_filename then
+ (let filename = Option.get maybe_filename in
+ try
+ let input_seq = Util.read_sequence_file filename in
+ let real_x_dim = Array.length input_seq in
+ x_dim := real_x_dim / 3;
+ y_dim := !x_dim;
+ let real_y_dim = !y_dim + !x_dim / 2 + 1 in
+ x_offset := !y_dim;
+ number_wall :=
+ My_Wall.create
+ ~dimx:real_x_dim
+ ~dimy:real_y_dim
+ ~init:input_seq;
+ new_pixmap ();
+ redraw_pixmap ();
+ wall_loaded := true;
+ enable_menu_items (List.assoc "file" !menus) [3;4;6];
+ set_status ~msg:("Opened " ^ filename)
+ with
+ Util.Not_an_integer s ->
+ set_status ~msg:("Error: " ^ s ^ " is not an integer"))
else
(set_status ~msg:"Canceled open") in
let save_as_cb () =
- let filename = choose_save_file
- ~title:"Save Sequence - Number Wall Viewer"
- ~folder:(Sys.getcwd ())
- ~name:(generate_unused ~basename:"sequence" ~extension:"txt") () in
- if filename != "" && overwrite_check ~filename then
- (set_status ~msg:("Saved sequence to " ^ filename);
- print_endline filename)
+ let maybe_filename =
+ Dialog.save_file
+ ~folder:(Sys.getcwd ())
+ ~name:(generate_unused ~basename:"sequence" ~extension:"txt") () in
+ if Option.is_some maybe_filename then
+ (let filename = Option.get maybe_filename in
+ let write channel =
+ for i = 0 to My_Wall.x_length !number_wall - 2 do
+ output_string channel (Z.to_string (My_Wall.get !number_wall ~x:i ~y:1) ^ ",");
+ done;
+ output_string channel (Z.to_string
+ (My_Wall.get !number_wall ~x:(My_Wall.x_length !number_wall - 1) ~y:1) ^ "\n") in
+ Util.call_with_open_output_file ~filename ~func:write;
+ set_status ~msg:("Saved sequence to " ^ filename))
else
(set_status ~msg:"Canceled save") in
let export_cb () =
- let filename = choose_save_file
- ~title:"Export Image - Number Wall Viewer"
- ~folder:(Sys.getcwd ())
- ~name:(generate_unused ~basename:"image" ~extension:"png") () in
- if filename != "" && overwrite_check ~filename then
- (set_status ~msg:("Exported image to " ^ filename);
- print_endline filename)
+ let maybe_filename =
+ Dialog.export_file
+ ~folder:(Sys.getcwd ())
+ ~name:(generate_unused ~basename:"image" ~extension:"png") () in
+ if Option.is_some maybe_filename then
+ (let filename = Option.get maybe_filename in
+ let buffer = GdkPixbuf.create
+ ~width:(!x_dim * !magnify)
+ ~height:(!y_dim * !magnify)
+ ~has_alpha:false () in
+ !pixmap_area#get_pixbuf
+ ~dest_x:0 ~dest_y:0
+ ~width:(!x_dim * !magnify)
+ ~height:(!y_dim * !magnify)
+ ~src_x:0 ~src_y:0
+ buffer;
+ GdkPixbuf.save
+ ~filename
+ ~typ:"png"
+ buffer;
+ set_status ~msg:("Exported image to " ^ filename))
else
(set_status ~msg:"Canceled export") in
let discard_cb () =
- print_endline "Discard" in
+ number_wall := My_Wall.empty;
+ x_dim := 1;
+ y_dim := 1;
+ new_pixmap ();
+ redraw_pixmap ();
+ wall_loaded := false;
+ disable_menu_items (List.assoc "file" !menus) [3;4;6];
+ set_status ~msg:"Discarded sequence" in
let color_cb () =
- print_endline "Color..." in
+ let maybe_colors =
+ Dialog.colors ~fore:!foreground_color ~back:!background_color in
+ if Option.is_some maybe_colors then
+ (foreground_color := fst (Option.get maybe_colors);
+ background_color := snd (Option.get maybe_colors);
+ if !wall_loaded then redraw_pixmap ();
+ set_status ~msg:"Color change applied")
+ else
+ (set_status ~msg:"Canceled color change") in
let modulus_cb () =
- print_endline "Modulus..." in
+ let maybe_modulus =
+ Dialog.modulus ~current:!modulus in
+ if Option.is_some maybe_modulus then
+ (modulus := Option.get maybe_modulus;
+ if !wall_loaded then redraw_pixmap ();
+ set_status ~msg:("Changed modulus to " ^ string_of_int !modulus))
+ else
+ (set_status ~msg:"Canceled modulus change") in
+
+
+
+ let zoom_cb n active =
+ if active then
+ (magnify := n;
+ if !wall_loaded then
+ (new_pixmap ();
+ redraw_pixmap ());
+ set_status ~msg:("Zoom set to " ^ string_of_int n ^ "x")) in
let about_cb () =
- let about_window = GWindow.about_dialog
- ~authors:["Jedidiah Barber"]
- ~comments:"A simple program to generate and visualise number walls."
- ~license:"Sunset License v1.0"
- ~title:"About - Number Wall Viewer"
- ~modal:true () in
- let destroy_me button = about_window#destroy () in
- ignore (about_window#connect#response ~callback:destroy_me);
- about_window#show () in
+ Dialog.about () in
@@ -177,6 +335,13 @@ let main () =
`I ("Modulus...", modulus_cb)
] in
+ let zoom_menu_entries = [
+ `R [ ("1x", false, (zoom_cb 1))
+ ; ("2x", true, (zoom_cb 2))
+ ; ("3x", false, (zoom_cb 3))
+ ; ("4x", false, (zoom_cb 4))]
+ ] in
+
let help_menu_entries = [
`I ("About", about_cb)
] in
@@ -184,13 +349,24 @@ let main () =
let create_menu ~label ~bar ~entries =
- let item = GMenu.menu_item ~label ~packing:bar#append () in
- let menu = GMenu.menu ~packing:item#set_submenu () in
- GToolbox.build_menu menu ~entries in
-
- ignore (create_menu ~label:"File" ~bar:menubar ~entries:file_menu_entries);
- ignore (create_menu ~label:"Options" ~bar:menubar ~entries:option_menu_entries);
- ignore (create_menu ~label:"Help" ~bar:menubar ~entries:help_menu_entries);
+ let item =
+ GMenu.menu_item
+ ~label
+ ~packing:bar#append () in
+ let menu =
+ GMenu.menu
+ ~packing:item#set_submenu () in
+ GToolbox.build_menu menu ~entries;
+ menu in
+
+ let file_menu = create_menu ~label:"File" ~bar:menubar ~entries:file_menu_entries in
+ let option_menu = create_menu ~label:"Options" ~bar:menubar ~entries:option_menu_entries in
+ let zoom_menu = create_menu ~label:"Zoom" ~bar:menubar ~entries:zoom_menu_entries in
+ let help_menu = create_menu ~label:"Help" ~bar:menubar ~entries:help_menu_entries in
+
+ menus := [("file",file_menu); ("option",option_menu); ("zoom",zoom_menu); ("help",help_menu)];
+
+ disable_menu_items (List.assoc "file" !menus) [3;4;6];
set_status ~msg:"No wall loaded";
window#show ();
diff --git a/src/wall.ml b/src/wall.ml
index 94043dc..6c11939 100644
--- a/src/wall.ml
+++ b/src/wall.ml
@@ -22,6 +22,7 @@ module type S =
sig
type element
type wall
+ val empty : wall
val create : dimx:int -> dimy:int -> init:element array -> wall
val x_length : wall -> int
val y_length : wall -> int
@@ -281,6 +282,11 @@ module Make (A : Algebra) =
with Exit ->
result
+ (* The empty wall isn't truly empty because every wall has *)
+ (* a row of ones at the very top, regardless of the input sequence. *)
+ let empty =
+ Array.make_matrix 1 1 (Some A.one)
+
let get wall ~x ~y =
diff --git a/src/wall.mli b/src/wall.mli
index 59d8edb..dc96218 100644
--- a/src/wall.mli
+++ b/src/wall.mli
@@ -26,6 +26,8 @@ module type S =
type element
type wall
+ val empty : wall
+
val create : dimx:int -> dimy:int -> init:element array -> wall
val x_length : wall -> int