summaryrefslogtreecommitdiffstats
path: root/otherlibs/labltk/jpf/balloon.ml
blob: 7b2f2e074fe519549852c3225359a9e4f80586e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
(*************************************************************************)
(*                                                                       *)
(*                Objective Caml LablTk library                          *)
(*                                                                       *)
(*         Jun Furuse, projet Cristal, INRIA Rocquencourt                *)
(*                                                                       *)
(*   Copyright 1999 Institut National de Recherche en Informatique et    *)
(*   en Automatique and Kyoto University.  All rights reserved.          *)
(*   This file is distributed under the terms of the GNU Library         *)
(*   General Public License.                                             *)
(*                                                                       *)
(*************************************************************************)

(* $Id$ *)

open StdLabels

(* easy balloon help facility *)

open Tk
open Widget
open Protocol
open Support

(* switch -- if you do not want balloons, set false *)
let flag = ref true
let debug = ref false

(* We assume we have at most one popup label at a time *)
let topw = ref default_toplevel
and popupw = ref (Obj.magic dummy : message widget)

let configure_cursor w cursor = 
  (* DDDDDDDDDIIIIIIIRRRRRRRRTTTTTTTTYYYYYYY *)
  Protocol.tkCommand [| TkToken (name w); 
                    TkToken "configure";
                    TkToken "-cursor";
                    TkToken cursor |]

let put ~on: w ~ms: millisec mesg = 
  let t = ref None in
  let cursor = ref "" in

  let reset () = 
      begin
        match !t with
          Some t -> Timer.remove t
        | _ -> ()
      end;
      (* if there is a popup label, unmap it *)
      if Winfo.exists !topw && Wm.state !topw <> "withdrawn" then 
        begin
          Wm.withdraw !topw;
          if Winfo.exists w then configure_cursor w !cursor
        end
  and set ev =
    if !flag then
      t := Some (Timer.add ~ms: millisec ~callback: (fun () -> 
        t := None;
        if !debug then
          prerr_endline ("Balloon: " ^ Widget.name w);
        update_idletasks();
        Message.configure !popupw ~text: mesg; 
        raise_window !topw;
        Wm.geometry_set !topw (* 9 & 8 are some kind of magic... *)
          ("+"^(string_of_int (ev.ev_RootX + 9))^
           "+"^(string_of_int (ev.ev_RootY + 8)));
        Wm.deiconify !topw;
        cursor := cget w `Cursor;
        configure_cursor w "hand2"))
  in

  List.iter [[`Leave]; [`ButtonPress]; [`ButtonRelease]; [`Destroy];
             [`KeyPress]; [`KeyRelease]]
    ~f:(fun events -> bind w ~events ~extend:true ~action:(fun _ -> reset ()));
  List.iter [[`Enter]; [`Motion]] ~f:
    begin fun events ->
      bind w ~events ~extend:true ~fields:[`RootX; `RootY]
        ~action:(fun ev -> reset (); set ev)
    end

let init () =
  let t = Hashtbl.create 101 in
  Protocol.add_destroy_hook (fun w ->
    Hashtbl.remove t w);
  topw := Toplevel.create default_toplevel;
  Wm.overrideredirect_set !topw true;
  Wm.withdraw !topw;
  popupw := Message.create !topw ~name: "balloon"
              ~background: (`Color "yellow") ~aspect: 300;
  pack [!popupw];
  bind_class "all" ~events: [`Enter] ~extend:true ~fields:[`Widget] ~action:
    begin fun w ->
      try Hashtbl.find t w.ev_Widget
      with Not_found ->
        Hashtbl'.add t ~key:w.ev_Widget ~data: ();
        let x = Option.get w.ev_Widget ~name: "balloon" ~clas: "Balloon" in
        if x <> "" then put ~on: w.ev_Widget ~ms: 1000 x
    end