diff options
author | gareuselesinge <gareuselesinge@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2013-09-30 16:09:58 +0000 |
---|---|---|
committer | gareuselesinge <gareuselesinge@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2013-09-30 16:09:58 +0000 |
commit | 5d628ba4a253f86c9796a10a344b8ce9c176cf9b (patch) | |
tree | 9743c3e8b19b5fce5bf28663d65fda8785637004 /ide | |
parent | c262d5f43d3dcaef9bd078437cd022d9d272f753 (diff) |
wg_Command: detachable, less "from the 80s", query pane
- Tabs have labels derived from the query (e.g. "About eq_ind" will have
"eq_ind" as its label, that is better than "Page 1" ;-)
- Tabs have a [x] close icon
- Icon to create a new tab in in the notebook
- Dispotically grab the F1 key to open/close the query pane
(alt-esc is grabbed by windows managers these days)
- Esc hides the query pane (like the search pane)
- F1 puts a detached query pane in front
- Tab switches from the combo-box to the entry on its right
- Detaching is taken-over, and the query pane is reparented in a regular
window that can be resized
- A detached query pane can be put back by closing the window
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@16817 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'ide')
-rw-r--r-- | ide/coqide.ml | 12 | ||||
-rw-r--r-- | ide/coqide_ui.ml | 2 | ||||
-rw-r--r-- | ide/session.ml | 4 | ||||
-rw-r--r-- | ide/wg_Command.ml | 267 | ||||
-rw-r--r-- | ide/wg_Command.mli | 42 |
5 files changed, 217 insertions, 110 deletions
diff --git a/ide/coqide.ml b/ide/coqide.ml index 5ff849268..cdd1a9e48 100644 --- a/ide/coqide.ml +++ b/ide/coqide.ml @@ -768,11 +768,9 @@ let coqtop_arguments sn = let coqtop_arguments = cb_on_current_term coqtop_arguments -let show_query_pane sn = +let show_hide_query_pane sn = let ccw = sn.command in - if ccw#frame#misc#visible - then ccw#frame#misc#hide () - else ccw#frame#misc#show () + if ccw#visible then ccw#hide else ccw#show let zoom_fit sn = let script = sn.script in @@ -1058,9 +1056,9 @@ let build_ui () = ~callback:(fun _ -> prefs.show_toolbar <- not prefs.show_toolbar; !refresh_toolbar_hook ()); - toggle_item "Show Query Pane" ~label:"Show _Query Pane" - ~accel:"<Alt>Escape" - ~callback:(cb_on_current_term MiscMenu.show_query_pane) + item "Query Pane" ~label:"_Query Pane" + ~accel:"F1" + ~callback:(cb_on_current_term MiscMenu.show_hide_query_pane) ]; toggle_items view_menu Coq.PrintOpt.bool_items; diff --git a/ide/coqide_ui.ml b/ide/coqide_ui.ml index ed8027959..d763c33cb 100644 --- a/ide/coqide_ui.ml +++ b/ide/coqide_ui.ml @@ -67,7 +67,7 @@ let init () = <menuitem action='Zoom fit' /> <separator/> <menuitem action='Show Toolbar' /> - <menuitem action='Show Query Pane' /> + <menuitem action='Query Pane' /> <separator/> <menuitem action='Display implicit arguments' /> <menuitem action='Display coercions' /> diff --git a/ide/session.ml b/ide/session.ml index e094ac996..31e76935f 100644 --- a/ide/session.ml +++ b/ide/session.ml @@ -233,7 +233,7 @@ let create file coqtop_args = let script = create_script coqtop buffer in let proof = create_proof () in let messages = create_messages () in - let command = new Wg_Command.command_window coqtop ~mark_as_broken:(fun _ -> ()) ~mark_as_processed:(fun _ -> ()) ~cur_state:(fun () -> Obj.magic 0) in + let command = new Wg_Command.command_window basename coqtop in let finder = new Wg_Find.finder (script :> GText.view) in let fops = new FileOps.fileops (buffer :> GText.buffer) file reset in let _ = fops#update_stats in @@ -308,7 +308,7 @@ let build_layout (sn:session) = end) in session_box#pack sn.finder#coerce; - session_paned#pack2 ~shrink:false ~resize:false (sn.command#frame#coerce); + sn.command#pack_in (session_paned#pack2 ~shrink:false ~resize:false); script_scroll#add sn.script#coerce; proof_scroll#add sn.proof#coerce; message_frame#add sn.messages#coerce; diff --git a/ide/wg_Command.ml b/ide/wg_Command.ml index 3422b1682..591374412 100644 --- a/ide/wg_Command.ml +++ b/ide/wg_Command.ml @@ -6,102 +6,157 @@ (* * GNU Lesser General Public License Version 2.1 *) (************************************************************************) +class type detachable_signals = + object + inherit GContainer.container_signals + method attached : callback:(GObj.widget -> unit) -> unit + method detached : callback:(GObj.widget -> unit) -> unit + end + +class detachable (obj : ([> Gtk.box] as 'a) Gobject.obj) = + + object(self) + inherit GPack.box_skel (obj :> Gtk.box Gobject.obj) as super + + val but = GButton.button () + val win = GWindow.window () + val frame = GBin.frame ~shadow_type:`NONE () + val mutable detached = false + val mutable detached_cb = (fun _ -> ()) + val mutable attached_cb = (fun _ -> ()) + + method child = frame#child + method add = frame#add + method pack ?from ?expand ?fill ?padding w = + if frame#all_children = [] then self#add w + else raise (Invalid_argument "detachable#pack") + + method title = win#title + method set_title = win#set_title + + method connect : detachable_signals = object + inherit GContainer.container_signals_impl obj + method attached ~callback = attached_cb <- callback + method detached ~callback = detached_cb <- callback + end + + method show = + if detached then win#present () + else self#misc#show (); + + method hide = + if detached then win#misc#hide () + else self#misc#hide () + + method visible = win#misc#visible || self#misc#visible + + initializer + self#set_homogeneous false; + super#pack ~expand:false but#coerce; + super#pack ~expand:true ~fill:true frame#coerce; + win#misc#hide (); + but#add (GMisc.label + ~markup:"<span size='x-small'>D\nE\nT\nA\nC\nH</span>" ())#coerce; + ignore(win#event#connect#delete ~callback:(fun _ -> + win#misc#hide (); + frame#misc#reparent self#coerce; + detached <- false; + attached_cb self#child; + true)); + ignore(but#connect#clicked ~callback:(fun _ -> + frame#misc#reparent win#coerce; + self#misc#hide (); + win#present (); + detached <- true; + detached_cb self#child; + )) + + end + +let detachable ?title = + GtkPack.Box.make_params [] ~cont:( + GContainer.pack_container + ~create:(fun p -> + let d = new detachable (GtkPack.Box.create `HORIZONTAL p) in + Option.iter d#set_title title; + d)) + open Preferences -class command_window coqtop - ~mark_as_broken ~mark_as_processed ~cur_state -= -(* let window = GWindow.window - ~allow_grow:true ~allow_shrink:true - ~width:500 ~height:250 - ~position:`CENTER - ~title:"CoqIde queries" ~show:false () - in *) - let views = ref [] in - let frame = GBin.frame ~label:"Command Pane" ~shadow_type:`IN () in - let _ = frame#misc#hide () in +class command_window name coqtop = + let frame = detachable ~title:"Query pane" () in + let _ = frame#hide in let _ = GtkData.AccelGroup.create () in - let hbox = GPack.hbox ~homogeneous:false ~packing:frame#add () in - let toolbar = GButton.toolbar - ~orientation:`VERTICAL - ~style:`ICONS - ~tooltips:true - ~packing:(hbox#pack - ~expand:false - ~fill:false) - () - in - let notebook = GPack.notebook ~scrollable:true - ~packing:(hbox#pack - ~expand:true - ~fill:true - ) - () - in - let _ = - toolbar#insert_button - ~tooltip:"Hide Commands Pane" - ~text:"Hide Pane" - ~icon:(Ideutils.stock_to_widget `CLOSE) - ~callback:frame#misc#hide - () - in - let new_page_menu = - toolbar#insert_button - ~tooltip:"New Page" - ~text:"New Page" - ~icon:(Ideutils.stock_to_widget `NEW) - () - in - - let remove_cb () = - let index = notebook#current_page in - let () = notebook#remove_page index in - views := Util.List.filteri (fun i x -> i <> index) !views - in - let _ = - toolbar#insert_button - ~tooltip:"Delete Page" - ~text:"Delete Page" - ~icon:(Ideutils.stock_to_widget `DELETE) - ~callback:remove_cb - () - in + let notebook = + GPack.notebook ~height:200 ~scrollable:true ~packing:frame#add () in + let _ = frame#connect#attached ~callback:(fun _ -> + notebook#misc#set_size_request ~height:200 ()) in + let _ = frame#connect#detached ~callback:(fun _ -> + notebook#misc#set_size_request ~width:600 ~height:500 (); + notebook#misc#grab_focus ()) in + object(self) val frame = frame - - val new_page_menu = new_page_menu val notebook = notebook - method frame = frame - method new_command ?command ?term () = - let frame = GBin.frame - ~shadow_type:`ETCHED_OUT - () - in - let _ = notebook#append_page frame#coerce in + method pack_in (f : GObj.widget -> unit) = f frame#coerce + + val mutable new_page : GObj.widget = (GMisc.label ())#coerce + + val mutable views = [] + + method private new_page_maker = + let page = notebook#append_page + (GMisc.label ~text:"No query" ())#coerce in + let page = notebook#get_nth_page page in + let b = GButton.button () in + b#add (Ideutils.stock_to_widget ~size:`MENU `NEW); + ignore(b#connect#clicked ~callback:self#new_query); + notebook#set_page ~tab_label:b#coerce page; + new_page <- page + + method new_query ?command ?term () = + let frame = GBin.frame ~shadow_type:`NONE () in + ignore(notebook#insert_page ~pos:(notebook#page_num new_page) frame#coerce); + let new_tab_lbl text = + let hbox = GPack.hbox ~homogeneous:false () in + ignore(GMisc.label ~width:100 ~ellipsize:`END ~text ~packing:hbox#pack()); + let b = GButton.button ~packing:hbox#pack () in + ignore(b#connect#clicked ~callback:(fun () -> + views <- + List.filter (fun (f,_,_) -> f#get_oid <> frame#coerce#get_oid) views; + notebook#remove_page (notebook#page_num frame#coerce))); + b#add (Ideutils.stock_to_widget ~size:`MENU `CLOSE); + hbox#coerce in + notebook#set_page ~tab_label:(new_tab_lbl "New query") frame#coerce; notebook#goto_page (notebook#page_num frame#coerce); let vbox = GPack.vbox ~homogeneous:false ~packing:frame#add () in - let hbox = GPack.hbox ~homogeneous:false ~packing:vbox#pack () in - let (combo,_) = GEdit.combo_box_entry_text ~strings:Coq_commands.state_preserving - ~packing:hbox#pack - () - in - let on_activate c () = - if List.mem combo#entry#text Coq_commands.state_preserving then c () - else Minilib.log "Not a state preserving command" - in - let entry = GEdit.entry ~packing:(hbox#pack ~expand:true) () in - entry#misc#set_can_default true; + let combo, entry, ok_b = + let bar = + GButton.toolbar ~style:`ICONS ~packing:(vbox#pack ~expand:false) () in + let bar_add ~expand w = + let item = GButton.tool_item ~expand () in + item#add w#coerce; + bar#insert item in + let combo, _ = + GEdit.combo_box_entry_text ~strings:Coq_commands.state_preserving () in + combo#entry#set_text "Search"; + let entry = GEdit.entry () in + entry#misc#set_can_default true; + let ok_b = GButton.button () in + ok_b#add (Ideutils.stock_to_widget `OK); + bar_add ~expand:false combo; + bar_add ~expand:true entry; + bar_add ~expand:false ok_b; + combo, entry, ok_b in let r_bin = GBin.scrolled_window ~vpolicy:`AUTOMATIC ~hpolicy:`AUTOMATIC ~packing:(vbox#pack ~fill:true ~expand:true) () in - let ok_b = GButton.button ~label:"Ok" ~packing:(hbox#pack ~expand:false) () in let result = GText.view ~packing:r_bin#add () in - let () = views := !views @ [result] in + views <- (frame#coerce, result, combo#entry) :: views; result#misc#modify_font current.text_font; let clr = Tags.color_of_string current.background_color in result#misc#modify_base [`NORMAL, `COLOR clr]; @@ -109,26 +164,29 @@ object(self) result#set_editable false; let callback () = let com = combo#entry#text in + let arg = entry#text in + if Str.string_match (Str.regexp "^ *$") (com^arg) 0 then () else let phrase = - if String.get com (String.length com - 1) = '.' - then com ^ " " else com ^ " " ^ entry#text ^" . " + if Str.string_match (Str.regexp "\\. *$") com 0 then com + else com ^ " " ^ arg ^" . " in let log level message = result#buffer#insert (message^"\n") in let process = Coq.bind (Coq.query ~logger:log (phrase,Stateid.dummy)) (function | Interface.Fail (_,l,str) -> result#buffer#insert str; + notebook#set_page ~tab_label:(new_tab_lbl "Error") frame#coerce; Coq.return () | Interface.Good res -> result#buffer#insert res; + notebook#set_page ~tab_label:(new_tab_lbl arg) frame#coerce; Coq.return ()) in result#buffer#set_text ("Result for command " ^ phrase ^ ":\n"); Coq.try_grab coqtop process ignore in - ignore (combo#entry#connect#activate ~callback:(on_activate callback)); - ignore (ok_b#connect#clicked ~callback:(on_activate callback)); - + ignore (combo#entry#connect#activate ~callback); + ignore (ok_b#connect#clicked ~callback); begin match command with | None -> () | Some c -> combo#entry#set_text c @@ -137,23 +195,44 @@ object(self) | None -> () | Some t -> entry#set_text t end; - on_activate callback (); - entry#misc#grab_focus (); + combo#entry#misc#grab_focus (); entry#misc#grab_default (); ignore (entry#connect#activate ~callback); ignore (combo#entry#connect#activate ~callback); - self#frame#misc#show () + ignore (combo#entry#event#connect#key_press ~callback:(fun ev -> + if GdkEvent.Key.keyval ev = GdkKeysyms._Tab then + (entry#misc#grab_focus ();true) + else false)) + method show = + frame#show; + let cur_page = notebook#get_nth_page notebook#current_page in + let _, _, e = + List.find (fun (p,_,_) -> p#get_oid == cur_page#get_oid) views in + e#misc#grab_focus () + + method hide = + frame#hide + + method visible = + frame#visible + method refresh_font () = - let iter view = view#misc#modify_font current.text_font in - List.iter iter !views + let iter (_,view,_) = view#misc#modify_font current.text_font in + List.iter iter views method refresh_color () = let clr = Tags.color_of_string current.background_color in - let iter view = view#misc#modify_base [`NORMAL, `COLOR clr] in - List.iter iter !views + let iter (_,view,_) = view#misc#modify_base [`NORMAL, `COLOR clr] in + List.iter iter views initializer - ignore (new_page_menu#connect#clicked ~callback:self#new_command); - (* ignore (window#event#connect#delete (fun _ -> window#misc#hide(); true));*) + self#new_page_maker; + self#new_query (); + frame#misc#hide (); + ignore(notebook#event#connect#key_press ~callback:(fun ev -> + if GdkEvent.Key.keyval ev = GdkKeysyms._Escape then (self#hide; true) + else false + )); + end diff --git a/ide/wg_Command.mli b/ide/wg_Command.mli index 2245befe7..92ad858f4 100644 --- a/ide/wg_Command.mli +++ b/ide/wg_Command.mli @@ -6,13 +6,43 @@ (* * GNU Lesser General Public License Version 2.1 *) (************************************************************************) -class command_window : Coq.coqtop -> - mark_as_broken:(Stateid.t list -> unit) -> - mark_as_processed:(Stateid.t list -> unit) -> - cur_state:(unit -> Stateid.t) -> +class type detachable_signals = object - method new_command : ?command:string -> ?term:string -> unit -> unit - method frame : GBin.frame + inherit GContainer.container_signals + method attached : callback:(GObj.widget -> unit) -> unit + method detached : callback:(GObj.widget -> unit) -> unit + end + +class detachable : ([> Gtk.box] as 'a) Gobject.obj -> + object + inherit GPack.box_skel + val obj : Gtk.box Gobject.obj + method connect : detachable_signals + method child : GObj.widget + method show : unit + method hide : unit + method visible : bool + method title : string + method set_title : string -> unit + + end + +val detachable : + ?title:string -> + ?homogeneous:bool -> + ?spacing:int -> + ?border_width:int -> + ?width:int -> + ?height:int -> + ?packing:(GObj.widget -> unit) -> ?show:bool -> unit -> detachable + +class command_window : string -> Coq.coqtop -> + object + method new_query : ?command:string -> ?term:string -> unit -> unit + method pack_in : (GObj.widget -> unit) -> unit method refresh_font : unit -> unit method refresh_color : unit -> unit + method show : unit + method hide : unit + method visible : bool end |