From 5bd9f59fb930fe5e585ee297cd2d9c23d7536ea3 Mon Sep 17 00:00:00 2001 From: Erwan Jahier <erwan.jahier@univ-grenoble-alpes.fr> Date: Mon, 6 Apr 2020 10:58:39 +0200 Subject: [PATCH] New: add a gtk3 UI over rdbg named rdbgui4sasa --- sasa.opam | 1 + test/Makefile.inc | 9 +- test/{my-rdbg-tuning.ml => sasa-rdbg-cmds.ml} | 0 tools/rdbgui/dune | 12 + tools/rdbgui/rdbgui.ml | 309 ++++++++++++++++++ 5 files changed, 328 insertions(+), 3 deletions(-) rename test/{my-rdbg-tuning.ml => sasa-rdbg-cmds.ml} (100%) create mode 100644 tools/rdbgui/dune create mode 100644 tools/rdbgui/rdbgui.ml diff --git a/sasa.opam b/sasa.opam index 03f1d945..935c4507 100644 --- a/sasa.opam +++ b/sasa.opam @@ -23,6 +23,7 @@ depends: [ "dune" { >= "1.11" } "ocamlgraph" "lutils" + "lablgtk3" "lustre-v6" "lutin" "rdbg" { >= "1.184" } diff --git a/test/Makefile.inc b/test/Makefile.inc index 111a45b4..b8c625da 100644 --- a/test/Makefile.inc +++ b/test/Makefile.inc @@ -1,4 +1,4 @@ -# Time-stamp: <modified the 11/03/2020 (at 13:59) by Erwan Jahier> +# Time-stamp: <modified the 06/04/2020 (at 10:35) by Erwan Jahier> DIR=../../_build/install/default @@ -37,7 +37,10 @@ LIB=-package algo sasa $< %.rdbg: %.dot %.ml - rdbg -sut "sasa $< -dd" + ledit -h rdbg-history -x rdbg -sut "sasa $< -dd" + +%.rdbgui: %.dot %.ml + ledit -h rdbg-history -x rdbgui4sasa -sut "sasa $< -dd" @@ -47,7 +50,7 @@ s:sim2chrogtk genclean: rm -f *.cmxs sasa *.cm* *.o *.pdf *.rif *.gp *.log *.dro *.seed *.c *.h sasa-*.dot rm -f rdbg-session*.ml luretteSession* *.lut a.out *.cov read_dot.ml - rm -f *.exec *.sh grid*.ml read_dot.ml + rm -f *.exec *.sh grid*.ml read_dot.ml rdbg-history ################################################################################## -include Makefile.untracked diff --git a/test/my-rdbg-tuning.ml b/test/sasa-rdbg-cmds.ml similarity index 100% rename from test/my-rdbg-tuning.ml rename to test/sasa-rdbg-cmds.ml diff --git a/tools/rdbgui/dune b/tools/rdbgui/dune new file mode 100644 index 00000000..77345078 --- /dev/null +++ b/tools/rdbgui/dune @@ -0,0 +1,12 @@ + + +(executables + (names rdbgui ) + (flags :standard -w -3-6-7-10-24-26-27-33-35 -no-strict-sequence) + (libraries lablgtk3 str)) + +(install + (section bin) + (package sasa) +(files (rdbgui.exe as rdbgui4sasa)) +) diff --git a/tools/rdbgui/rdbgui.ml b/tools/rdbgui/rdbgui.ml new file mode 100644 index 00000000..8709ca66 --- /dev/null +++ b/tools/rdbgui/rdbgui.ml @@ -0,0 +1,309 @@ + + +let quote str = if String.contains str ' ' then ("\""^str^"\"") else str +let rdbg_cmd = + String.concat " " ("rdbg"::(List.tl (List.map quote (Array.to_list Sys.argv)))) + +(* let oc_stdin = Unix.open_process_out rdbg_cmd *) +let ic_stdout, oc_stdin = Unix.open_process rdbg_cmd +(* let ic_stdout, oc_stdin, ic_stderr = + Unix.open_process_full rdbg_cmd (Unix.environment()) *) + +let _ = + Unix.set_nonblock (Unix.descr_of_in_channel ic_stdout); +(* Unix.set_nonblock (Unix.descr_of_in_channel ic_stderr) *) + () +(* let p str = Printf.printf "%s\n%!" str *) + + +let read_stdout ic = + let buff = Bytes.create 256 in + let res = ref "" in + let cond = ref true in + Unix.sleepf 0.5; + while !cond do + try + let n = Stdlib.input ic buff 0 256 in + res := !res ^ (Bytes.sub_string buff 0 n); + if n < 256 then cond := false; + with Sys_blocked_io -> cond := false + done; + if !res <> "" then Printf.printf "%s%!" !res; + !res + +let gui str = + Printf.fprintf oc_stdin "%s\n" str; (* sent the session choice *) + Printf.fprintf oc_stdin + "del_hook \"print_event\"; add_hook \"print_event\" (print_sasa_event false);;\n%!"; + (* Printf.fprintf oc_stdin "print_sasa_event false !e;;\n"; (* print the first event *) *) + + let _locale = GMain.init () in + let _thread = GtkThread.start() in + let w = GWindow.window ~show:true ~title: "A rdbg GUI for sasa" () in + let box = GPack.vbox ~packing: w#add () in + let gbox = GPack.hbox ~packing: box#add () in + let gbox2 = GPack.hbox ~packing: box#add () in + let sw1 = GBin.scrolled_window ~border_width:10 ~shadow_type:`IN ~height:30 ~width:50 + ~packing:box#add () + in + let sw2 = GBin.scrolled_window ~border_width:10 ~shadow_type:`OUT ~height:250 + ~packing:box#add () + in + sw1#misc#set_tooltip_text "This window displays the commands sent to the rdbg cli"; + sw2#misc#set_tooltip_text "This window displays commands outputs"; + let text1 = GText.view ~wrap_mode:`CHAR ~height:50 ~editable:false ~width:50 + ~packing: sw1#add () ~cursor_visible:true + in + let text2 = GText.view ~wrap_mode:`CHAR ~height:250 ~editable:false + ~packing: sw2#add () ~cursor_visible:true + in + (* text2#place_cursor_onscreen (); *) + (* let text3 = GText.view ~editable:false ~packing: box#add () in *) + + (* let input_buff = Buffer.create 100 in *) + let p str = + (* Buffer.add_string input_buff (str^"\n"); *) + (* text1#set_buffer (GText.buffer ~text:(Buffer.contents input_buff) ()); *) + text1#set_buffer (GText.buffer ~text:str ()); + Printf.fprintf oc_stdin "%s\n%!" str; + Printf.printf "%s\n%!" str; + in + (* p str; *) + Printf.fprintf oc_stdin "print_sasa_event false !e;;\n%!"; (* print the first event *) + + let readloop () = + while true do + let str = read_line () in + p str; + if str="q" then exit 0; + done; + in + (* let str = input_line ic_stdout in *) + (* let n_buff = GText.buffer ~text:str () in *) + (* text#set_buffer n_buff; *) + + + + let bbox = GPack.hbox ~packing: box#add () in + + let change_label button str = + let icon = button#image in + button#set_label str; + button#set_image icon + in + + let back_step_button = + GButton.button ~use_mnemonic:true ~stock:`GO_BACK ~packing:bbox#add + ~label:"back step" () + in + back_step_button#misc#set_tooltip_text "Move BACKWARD to the previous STEP"; + change_label back_step_button "Ste_p"; + ignore (back_step_button#connect#clicked ~callback:(fun () -> p "bd")); + + let step_button = + GButton.button ~use_mnemonic:true ~packing:bbox#add ~stock:`GO_FORWARD + ~label:"step" () + in + step_button#misc#set_tooltip_text "Move FORWARD to the next STEP"; + change_label step_button "_Step"; + ignore (step_button#connect#clicked ~callback:(fun () -> p "sd")); + + let back_round_button = + GButton.button ~packing:bbox#add ~stock:`MEDIA_PREVIOUS ~use_mnemonic:true + ~label:"back round" () + in + back_round_button#misc#set_tooltip_text "Move BACKWARD to the previous ROUND"; + change_label back_round_button "Roun_d"; + ignore (back_round_button#connect#clicked ~callback:(fun () -> p "pr" )); + + let round_button = + GButton.button ~use_mnemonic:true ~stock:`MEDIA_FORWARD + ~packing:bbox#add ~label:"round" () + in + round_button#misc#set_tooltip_text "Move FORWARD to the next ROUND"; + change_label round_button "_Round"; + ignore (round_button#connect#clicked ~callback:(fun () -> p "nr")); + + let silence () = + let silence_button = GButton.button ~use_mnemonic:true + ~packing:bbox#add () in + silence_button#misc#set_tooltip_text + "Move FORWARD until the algorithm is SILENT (i.e., when no action is enabled)"; + let image = GMisc.image ~file:"../rdbg-utils/chut_small.svg" () in + silence_button#set_image image#coerce; + (* change_label silence_button "Silen_t"; *) + ignore (silence_button#connect#clicked ~callback:(fun () -> p "silence")) + + in + silence (); + + let graph () = + let graph_button = GButton.button ~use_mnemonic:true ~packing:bbox#add () in + graph_button#misc#set_tooltip_text + "Visualize the Topology states: Green=Enabled ; Gold=Active"; + let image = GMisc.image ~file:"../rdbg-utils/graph_small.png" () in + graph_button#set_image image#coerce; + ignore (graph_button#connect#clicked ~callback: (fun () -> p "graph_view" )); + + in + graph (); + + let viol_oracle () = + let viol_button = GButton.button ~use_mnemonic:true ~stock:`OK + ~packing:bbox#add () in + viol_button#misc#set_tooltip_text + "Move FORWARD until an oracle states something wrong happened"; + (* let image = GMisc.image ~file:"../rdbg-utils/oracle_small.jpg" () in *) + (* viol_button#set_image image#coerce; *) + change_label viol_button "_Oracle"; + ignore (viol_button#connect#clicked ~callback:(fun () -> p "viol")) + in + (* if args.oracles <> [] then *) + viol_oracle (); + + let undo_button = GButton.button ~use_mnemonic:true ~stock:`UNDO + ~packing:bbox#add ~label:"undo" () + in + undo_button#misc#set_tooltip_text "Undo the last move"; + ignore (undo_button#connect#clicked ~callback:(fun () -> p "u\nd")); + + let restart_button = GButton.button ~use_mnemonic:true ~stock:`REFRESH + ~packing:bbox#add ~label:"restart" () + in + restart_button#misc#set_tooltip_text "Restart from the beginning"; + change_label restart_button "Restar_t"; + ignore (restart_button#connect#clicked ~callback:(fun ()-> p "r\nd")); + + let info_button = + GButton.button ~use_mnemonic:true ~stock:`INFO ~packing:bbox#add ~label:"_Info" () + in + change_label info_button "_Info"; + info_button#misc#set_tooltip_text "Get information about the current session"; + ignore (info_button#connect#clicked ~callback: (fun() -> p "i")); + + let quit_button = + GButton.button ~use_mnemonic:true ~stock:`QUIT ~packing:bbox#add ~label:"bye" () + in + quit_button#misc#set_tooltip_text "Quit RDBGUI"; + ignore (quit_button#connect#clicked ~callback: (fun() -> p "q"; exit 0)); + + + let dot_button = GButton.radio_button ~packing:gbox#add ~label:"dot" () in + let fd_button = GButton.radio_button ~packing:gbox#add + ~group:dot_button#group ~label:"fdp" () + in + let sf_button = GButton.radio_button ~packing:gbox#add + ~group:dot_button#group ~label:"sfdp" () + in + let ne_button = GButton.radio_button ~packing:gbox#add + ~active:true ~group:dot_button#group ~label:"neato" () + in + let tw_button = GButton.radio_button ~packing:gbox#add + ~group:dot_button#group ~label:"twopi" () + in + let ci_button = GButton.radio_button ~packing:gbox#add + ~group:dot_button#group ~label:"circo" () + in + let pa_button = GButton.radio_button ~packing:gbox#add + ~group:dot_button#group ~label:"patchwork" () + in + let os_button = GButton.radio_button ~packing:gbox#add + ~group:dot_button#group ~label:"osage" () + in + + let par_dot () = + let par_dot_button = GButton.radio_button ~packing:gbox2#add + ~group:dot_button#group ~label:"dot*" () in + let par_fd_button = GButton.radio_button ~packing:gbox2#add + ~group:dot_button#group ~label:"fdp*" () in + let par_sf_button = GButton.radio_button ~packing:gbox2#add + ~group:dot_button#group ~label:"sfdp*" () in + let par_ne_button = GButton.radio_button ~packing:gbox2#add + ~group:dot_button#group ~label:"neato*" () in + let par_tw_button = GButton.radio_button ~packing:gbox2#add + ~group:dot_button#group ~label:"twopi*" () in + let par_ci_button = GButton.radio_button ~packing:gbox2#add + ~group:dot_button#group ~label:"circo*" () in + let par_pa_button = GButton.radio_button ~packing:gbox2#add + ~group:dot_button#group ~label:"patchwork*" () in + let par_os_button = GButton.radio_button ~packing:gbox2#add + ~group:dot_button#group ~label:"osage*" () + in + par_dot_button#misc#set_tooltip_text "Use dot, but show only links to parents"; + par_fd_button#misc#set_tooltip_text "Use fdp, but show only links to parents"; + par_sf_button#misc#set_tooltip_text "Use sfdp, but show only links to parents"; + par_ne_button#misc#set_tooltip_text "Use neato, but show only links to parents"; + par_tw_button#misc#set_tooltip_text "Use twopi, but show only links to parents"; + par_ci_button#misc#set_tooltip_text "Use circo, but show only links to parents"; + par_pa_button#misc#set_tooltip_text "Use patchwork, but show only links to parents"; + par_os_button#misc#set_tooltip_text "Use osage, but show only links to parents"; + ignore (par_dot_button#connect#clicked + ~callback:(fun () -> p "dot_view := d_par; !dot_view();;")); + ignore (par_fd_button#connect#clicked + ~callback:(fun () -> p "dot_view := fd_par; !dot_view();;")); + ignore (par_sf_button#connect#clicked + ~callback:(fun () -> p "dot_view := sf_par; !dot_view();;")); + ignore (par_ne_button#connect#clicked + ~callback:(fun () -> p "dot_view := ne_par; !dot_view();;")); + ignore (par_tw_button#connect#clicked + ~callback:(fun () -> p "dot_view := tw_par; !dot_view();;")); + ignore (par_ci_button#connect#clicked + ~callback:(fun () -> p "dot_view := ci_par; !dot_view();;")); + ignore (par_pa_button#connect#clicked + ~callback:(fun () -> p "dot_view := pa_par; !dot_view();;")); + ignore (par_os_button#connect#clicked + ~callback:(fun () -> p "dot_view := os_par; !dot_view();;")) + in + + let have_parent () = (* is there a parent field in the state ? *) + (* List.exists (fun (v,_) -> Str.string_match (Str.regexp ".*_par.*") v 0) !e.data *) + true + in + if have_parent () then par_dot (); + dot_button#misc#set_tooltip_text "Use the dot engine to display the graph"; + fd_button#misc#set_tooltip_text "Use the fdp engine to display the graph"; + sf_button#misc#set_tooltip_text "Use the sfdp engine to display the graph"; + ne_button#misc#set_tooltip_text "Use the neato engine to display the graph"; + tw_button#misc#set_tooltip_text "Use the twopi engine to display the graph"; + ci_button#misc#set_tooltip_text "Use the circo engine to display the graph"; + pa_button#misc#set_tooltip_text "Use the patchwork engine to display the graph"; + os_button#misc#set_tooltip_text "Use the osage engine to display the graph"; + + ignore (dot_button#connect#clicked + ~callback:(fun () -> p "dot_view:=dot; !dot_view();;")); + ignore (fd_button#connect#clicked + ~callback:(fun () -> p "dot_view:=fd; !dot_view();;")); + ignore (sf_button#connect#clicked + ~callback:(fun () -> p "dot_view:=sf; !dot_view();;")); + ignore (ne_button#connect#clicked + ~callback:(fun () -> p "dot_view:=ne; !dot_view();;")); + ignore (tw_button#connect#clicked + ~callback:(fun () -> p "dot_view:=tw; !dot_view();;")); + ignore (ci_button#connect#clicked + ~callback:(fun () -> p "dot_view:=ci; !dot_view();;")); + ignore (pa_button#connect#clicked + ~callback:(fun () -> p "dot_view:=pa; !dot_view();;")); + ignore (os_button#connect#clicked + ~callback:(fun () -> p "dot_view:=os; !dot_view();;")); + + ignore (read_stdout ic_stdout); + let rec read_stdout_loop () = + let res = read_stdout ic_stdout in + let res = Str.global_replace (Str.regexp_string "(rdbg) ") "" res in + if res <> "" then text2#set_buffer (GText.buffer ~text:res ()); + (* let res = read_stdout ic_stderr in *) + (* if res <> "" then text3#set_buffer (GText.buffer ~text:res ()); *) + read_stdout_loop () + in + + let _ = Thread.create read_stdout_loop () in + + (* ignore (Sys.command "rdbg"); *) + readloop () + (* GMain.main () *) +;; + + +let _ = + ignore (read_stdout ic_stdout); + gui (read_line ()) (* read the session choice *) -- GitLab