1 (* Copyright (C) 2000-2005,
2 * Luca Padovani <lpadovan@cs.unibo.it>
3 * Claudio Sacerdoti Coen <sacerdot@cs.unibo.it>
4 * Stefano Zacchiroli <zacchiro@cs.unibo.it>
6 * This file is part of lablgtkmathview, the Ocaml binding for the
9 * lablgtkmathview is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * lablgtkmathview is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with lablgtkmathview; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 * For details, send a mail to the authors.
27 (* finds the common node ancestor of two nodes *)
28 let common_ancestor (first : Gdome.node) (last : Gdome.node) =
30 match n#get_parentNode with
32 | Some p -> n::(path p)
36 _, hd1::tl1, hd2::tl2 when hd1#isSameNode hd2 -> (last_common ((Some hd1),tl1,tl2))
38 | _,_,_ -> assert false
40 (last_common (None,(List.rev (path first)),(List.rev (path last))))
42 let same_element (e1 : Gdome.element option) (e2 : Gdome.element option) =
45 | Some e1, Some e2 when (e1 :> Gdome.node)#isSameNode (e2 :> Gdome.node) -> true
48 (* true if n1 is n2 or one of n2's descendants *)
49 let rec descendant_of (n1 : Gdome.node) (n2 : Gdome.node) =
50 if n1#isSameNode n2 then true
52 match n1#get_parentNode with
54 | Some n1' -> descendant_of n1' n2
56 let remove_descendants_of (el : Gdome.element) =
60 | hd::tl when descendant_of (hd :> Gdome.node) (el :> Gdome.node) -> aux tl
61 | hd::tl -> hd::(aux tl)
65 (* mem el l = true if the node n is stored in the list l *)
66 let mem (el : Gdome.element) =
69 hd::_ when (hd :> Gdome.node)#isSameNode (el :> Gdome.node) -> true
75 (* remove el l = l' where l' has the same nodes as l except that all
76 * the occurrences of n have been removed *)
77 let remove (el : Gdome.element) =
80 hd::tl when (hd :> Gdome.node)#isSameNode (el :> Gdome.node) ->
82 | hd::tl -> hd::(remove_aux tl)
87 class single_selection_math_view_signals obj (set_selection_changed : (Gdome.element option -> unit) -> unit) =
89 inherit GMathView.math_view_signals obj
90 method selection_changed = set_selection_changed
94 class single_selection_math_view obj =
96 inherit GMathView.math_view_skel obj
97 val mutable first_selected = None
98 val mutable root_selected = None
99 val mutable selection_changed = (fun _ -> ())
101 method set_selection elem =
104 match root_selected with
106 | Some e -> self#unselect e
108 root_selected <- elem ;
112 | Some e -> self#select e
116 method get_selection = root_selected
120 single_selection_math_view_signals obj
121 (function f -> selection_changed <- f)
123 method action_toggle (elem : Gdome.element) =
124 match elem#get_namespaceURI, elem#get_localName with
127 (ns#to_string = "http://www.w3.org/1998/Math/MathML" && ln#to_string = "maction") ||
128 (ns#to_string = "http://helm.cs.unibo.it/2003/BoxML" && ln#to_string = "action")
131 let selection_attr = Gdome.domString "selection" in
133 if elem#hasAttribute ~name:selection_attr then
134 int_of_string (elem#getAttribute ~name:selection_attr)#to_string
139 (* the widget will cast the index back into a valid range *)
140 elem#setAttribute ~name:selection_attr
141 ~value:(Gdome.domString (string_of_int (selection + 1))) ;
147 match elem#get_parentNode with
151 self#action_toggle (new Gdome.element_of_node p)
153 GdomeInit.DOMCastException _ -> false
155 | None -> assert false (* every element has a parent *)
159 selection_changed <- self#set_selection ;
162 (self#connect#select_begin
163 (fun ((elem : Gdome.element option), _, _, _) ->
164 if not (same_element root_selected elem) then selection_changed elem ;
165 first_selected <- elem)) ;
168 (self#connect#select_over
169 (fun ((elem : Gdome.element option), _, _, _) ->
171 match first_selected, elem with
172 Some first', Some last' ->
174 (new Gdome.element_of_node
175 (common_ancestor (first' :> Gdome.node) (last' :> Gdome.node))))
178 if not (same_element root_selected new_selected) then
179 selection_changed new_selected)) ;
182 (self#connect#select_end
183 (fun ((elem : Gdome.element option), _, _, _) -> first_selected <- None)) ;
186 (self#connect#select_abort
188 first_selected <- None ;
189 selection_changed None)) ;
191 ignore (self#connect#click (fun _ -> self#set_selection None))
195 let single_selection_math_view ?hadjustment ?vadjustment ?font_size ?log_verbosity =
196 GtkBase.Widget.size_params ~cont:(
197 OgtkMathViewProps.pack_return
198 (fun p -> OgtkMathViewProps.set_params (new single_selection_math_view
199 (GtkMathViewProps.MathView_GMetaDOM.create p)) ~font_size ~log_verbosity)) []
202 class multi_selection_math_view_signals obj
203 (set_selection_changed : (Gdome.element option -> unit) -> unit)
206 inherit GMathView.math_view_signals obj
207 method selection_changed = set_selection_changed
211 class multi_selection_math_view obj =
213 inherit single_selection_math_view obj
214 val mutable selected : Gdome.element list = []
216 method remove_selection (elem : Gdome.element) =
217 if mem elem selected then
218 selected <- remove elem selected ;
221 method remove_selections =
223 List.iter (fun e -> self#unselect e) selected ;
226 match self#get_selection with
228 | Some e -> self#select e
232 method add_selection (elem : Gdome.element) =
233 List.iter self#unselect selected ;
234 selected <- elem::(remove_descendants_of elem selected) ;
235 List.iter self#select selected
237 method get_selections = selected
239 method set_selection elem =
242 match root_selected with
244 | Some e -> self#unselect e ; List.iter (fun e -> self#select e) selected
246 root_selected <- elem;
250 | Some e -> self#select e
256 (self#connect#select_begin
257 (fun (_,_,_,state) ->
258 if not (List.mem `CONTROL (Gdk.Convert.modifier state)) then
259 self#remove_selections)) ;
262 (self#connect#select_end
263 (fun (_,_,_,state) ->
264 if not (List.mem `CONTROL (Gdk.Convert.modifier state)) then
265 self#remove_selections ;
266 match root_selected with
268 | Some e -> self#set_selection None ; self#add_selection e)) ;
272 (fun _ -> self#remove_selections))
276 let multi_selection_math_view ?hadjustment ?vadjustment ?font_size ?log_verbosity =
277 GtkBase.Widget.size_params ~cont:(
278 OgtkMathViewProps.pack_return
279 (fun p -> OgtkMathViewProps.set_params (new multi_selection_math_view
280 (GtkMathViewProps.MathView_GMetaDOM.create p)) ~font_size ~log_verbosity)) []