aboutsummaryrefslogtreecommitdiff
path: root/ide/coqide/wg_Segment.ml
diff options
context:
space:
mode:
Diffstat (limited to 'ide/coqide/wg_Segment.ml')
-rw-r--r--ide/coqide/wg_Segment.ml141
1 files changed, 141 insertions, 0 deletions
diff --git a/ide/coqide/wg_Segment.ml b/ide/coqide/wg_Segment.ml
new file mode 100644
index 0000000000..f115da662e
--- /dev/null
+++ b/ide/coqide/wg_Segment.ml
@@ -0,0 +1,141 @@
+(************************************************************************)
+(* * The Coq Proof Assistant / The Coq Development Team *)
+(* v * Copyright INRIA, CNRS and contributors *)
+(* <O___,, * (see version control and CREDITS file for authors & dates) *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(* * (see LICENSE file for the text of the license) *)
+(************************************************************************)
+
+open Util
+open Preferences
+
+type color = GDraw.color
+
+type model_event = [ `INSERT | `REMOVE | `SET of int * color ]
+
+class type model =
+object
+ method changed : callback:(model_event -> unit) -> unit
+ method length : int
+ method fold : 'a. ('a -> color -> 'a) -> 'a -> 'a
+end
+
+let i2f = float_of_int
+let f2i = int_of_float
+
+let color_eq (c1 : GDraw.color) (c2 : GDraw.color) = match c1, c2 with
+| `BLACK, `BLACK -> true
+| `COLOR c1, `COLOR c2 -> c1 == c2
+| `NAME s1, `NAME s2 -> String.equal s1 s2
+| `RGB (r1, g1, b1), `RGB (r2, g2, b2) -> r1 = r2 && g1 = g2 && b1 = b2
+| `WHITE, `WHITE -> true
+| _ -> false
+
+let set_cairo_color ctx c =
+ let open Gdk.Color in
+ let c = GDraw.color c in
+ let cast i = i2f i /. 65536. in
+ Cairo.set_source_rgb ctx (cast @@ red c) (cast @@ green c) (cast @@ blue c)
+
+class type segment_signals =
+object
+ inherit GObj.misc_signals
+ inherit GUtil.add_ml_signals
+ method clicked : callback:(int -> unit) -> GtkSignal.id
+end
+
+class segment_signals_impl obj (clicked : 'a GUtil.signal) : segment_signals =
+object
+ val after = false
+ inherit GObj.misc_signals obj
+ inherit GUtil.add_ml_signals obj [clicked#disconnect]
+ method clicked = clicked#connect ~after
+end
+
+class segment () =
+let box = GBin.frame () in
+let draw = GMisc.drawing_area ~packing:box#add () in
+
+object (self)
+
+ inherit GObj.widget box#as_widget
+
+ val mutable width = 1
+ val mutable height = 20
+ val mutable model : model option = None
+ val mutable default : color = `WHITE
+ val clicked = new GUtil.signal ()
+
+ initializer
+ box#misc#set_size_request ~height ();
+ let cb rect =
+ let w = rect.Gtk.width in
+ let h = rect.Gtk.height in
+ width <- w;
+ height <- h
+ in
+ let _ = box#misc#connect#size_allocate ~callback:cb in
+ let () = draw#event#add [`BUTTON_PRESS] in
+ let clicked_cb ev = match model with
+ | None -> true
+ | Some md ->
+ let x = GdkEvent.Button.x ev in
+ let len = md#length in
+ let idx = f2i ((x *. i2f len) /. i2f width) in
+ let () = clicked#call idx in
+ true
+ in
+ let _ = draw#event#connect#button_press ~callback:clicked_cb in
+ let cb show = if show then self#misc#show () else self#misc#hide () in
+ stick show_progress_bar self cb;
+ let cb ctx = self#refresh ctx; false in
+ let _ = draw#misc#connect#draw ~callback:cb in
+ ()
+
+ method set_model md =
+ model <- Some md;
+ let changed_cb _ = self#misc#queue_draw () in
+ md#changed ~callback:changed_cb
+
+ method private fill_range ctx color i j = match model with
+ | None -> ()
+ | Some md ->
+ let i = i2f i in
+ let j = i2f j in
+ let width = i2f width in
+ let len = i2f md#length in
+ let x = f2i ((i *. width) /. len) in
+ let x' = f2i ((j *. width) /. len) in
+ let w = x' - x in
+ set_cairo_color ctx color;
+ Cairo.rectangle ctx (i2f x) 0. ~w:(i2f w) ~h:(i2f height);
+ Cairo.fill ctx
+
+ method set_default_color color = default <- color
+ method default_color = default
+
+ method private refresh ctx = match model with
+ | None -> ()
+ | Some md ->
+ set_cairo_color ctx default;
+ Cairo.rectangle ctx 0. 0. ~w:(i2f width) ~h:(i2f height);
+ Cairo.fill ctx;
+ let make (k, cur, accu) v = match cur with
+ | None -> pred k, Some (k, k, v), accu
+ | Some (i, j, w) ->
+ if k = j - 1 && color_eq v w then pred k, Some (k, i, w), accu
+ else pred k, Some (k, k, v), (i, j, w) :: accu
+ in
+ let _, p, segments = md#fold make (md#length - 1, None, []) in
+ let segments = match p with
+ | None -> segments
+ | Some p -> p :: segments
+ in
+ List.iter (fun (i, j, v) -> self#fill_range ctx v i (j + 1)) segments
+
+ method connect =
+ new segment_signals_impl box#as_widget clicked
+
+end