let wp_panel (main_ui:Design.main_window_extension_points) =
  let vbox = GPack.vbox () in
  let demon = Gtk_form.demon () in
  let packing = vbox#pack in
  let form = new Gtk_form.form ~packing in

  form#label "Model" ;
  Gtk_form.menu wp_model_menu
    ~tooltip:"Memory model selection" ~packing:form#item
    Wp_parameters.Model.get Wp_parameters.Model.set demon ;

  form#label "Prover" ;
  Gtk_form.menu wp_prover_menu
    ~tooltip:"Prover selection"
    ~packing:form#item
    wp_prover_get wp_prover_set demon ;

  let options = GPack.hbox ~spacing:8 ~packing () in

  Gtk_form.check ~label:"RTE"
    ~tooltip:"Generates RTE guards for WP"
    ~packing:options#pack
    Wp_parameters.RTE.get Wp_parameters.RTE.set demon ;

  Gtk_form.check ~label:"Split"
    ~tooltip:"Split cunjunctions into sub-goals"
    ~packing:options#pack
    Wp_parameters.Split.get Wp_parameters.Split.set
    demon ;

  Gtk_form.check ~label:"Invariants"
    ~tooltip:"Alternative WP for loop with arbitrary invariants"
    ~packing:options#pack
    Wp_parameters.Invariants.get Wp_parameters.Invariants.set demon ;

  Gtk_form.check ~label:"Trace"
    ~tooltip:"Report proof information from the provers"
    ~packing:options#pack
    Wp_parameters.ProofTrace.get Wp_parameters.ProofTrace.set demon ;

  let control = GPack.hbox ~packing () in

  Gtk_form.button ~label:"Scripts"
    ~tooltip:"Script file for saving Coq proofs"
    ~callback:wp_script ~packing:control#pack () ;

  Gtk_form.label ~text:"Timeout" ~packing:control#pack () ;
  Gtk_form.spinner ~lower:0 ~upper:100000
    ~tooltip:"Timeout for proving one proof obligation"
    ~packing:control#pack
    Wp_parameters.Timeout.get Wp_parameters.Timeout.set demon ;

  Gtk_form.label ~text:"Process" ~packing:control#pack () ;
  Gtk_form.spinner ~lower:1 ~upper:32
    ~tooltip:"Maximum number of parallel running provers"
    ~packing:control#pack
    Wp_parameters.Procs.get
    (fun n ->
       Wp_parameters.Procs.set n ;
       ignore (Prover.server ()) (* to make server procs updated is server exists *)
    ) demon ;

  let pbox = GPack.hbox ~packing ~show:false () in
  let progress = GRange.progress_bar ~packing:(pbox#pack ~expand:true ~fill:true) () in
  let cancel = GButton.button ~packing:(pbox#pack ~expand:false) ~stock:`STOP () in
  cancel#misc#set_sensitive false ;
  let server = Prover.server () in
  ignore (cancel#connect#released (fun () -> Task.cancel_all server)) ;
  let inactive = (0,0) in
  let state = ref inactive in
  Task.on_server_activity server
    (fun () ->
       let scheduled = Task.scheduled server in
       let terminated = Task.terminated server in
       let remaining = scheduled - terminated in

       if remaining <= 0 then
         ( pbox#misc#hide () ; state := inactive ; cancel#misc#set_sensitive false )
       else
         begin
           if !state = inactive then
             ( pbox#misc#show () ; cancel#misc#set_sensitive true ) ;

           let s_term , s_sched = !state in

           if s_term <> terminated
           then ( Po_navigator.refresh_status () ; main_ui#rehighlight () ) ;
           if s_sched <> scheduled || s_term <> terminated then
             begin
               progress#set_text (Printf.sprintf "%d / %d" terminated scheduled) ;
               progress#set_fraction
                 (if scheduled = 0 then 1.0 else (float terminated /. float scheduled)) ;
             end ;

           state := (terminated,remaining) ;
         end) ;
  "WP" , vbox#coerce , Some (Gtk_form.refresh demon)