changeset 28:828795987d4c

Some ideas.
author Mikhail Kryshen <mikhail@kryshen.net>
date Mon, 05 Jul 2010 06:11:42 +0400
parents 61bc04f94d61
children 6975b9a71eec
files src/indyvon/component.clj src/indyvon/core.clj src/indyvon/core_new.clj
diffstat 3 files changed, 163 insertions(+), 420 deletions(-) [+]
line wrap: on
line diff
--- a/src/indyvon/component.clj	Sun Jul 04 06:03:48 2010 +0400
+++ b/src/indyvon/component.clj	Mon Jul 05 06:11:42 2010 +0400
@@ -5,46 +5,45 @@
 ;;
 
 (ns indyvon.component
-  (:use indyvon.core indyvon.layers)
+  (:use indyvon.core)
   (:import (java.awt Component Dimension Color)
            (javax.swing JFrame JPanel)))
 
 (defn- font-context [component]
   (.getFontRenderContext (.getFontMetrics component (.getFont component))))
 
-(defn paint-component [component layer context graphics]
+(defn paint-component [component layer graphics event-dispatcher]
   (let [size (.getSize component)
         width (.width size)
-        height (.height size)
-        context (assoc context
-                  :target component
-                  :font-context (.getFontRenderContext graphics)
-                  :update-fn #(.repaint component))]
+        height (.height size)]
     (.clearRect graphics 0 0 width height)
-    (draw! layer context graphics 0 0 width height false))
-  (commit (:dispatcher context)))
+    (binding [*path* nil
+              *graphics* graphics
+              *font-context*' (.getFontRenderContext graphics)
+              *event-dispatcher* event-dispatcher
+              *update* #(.repaint component)
+              *bounds* (indyvon.core.Bounds. 0 0 width height)]
+      (render! layer nil)
+      (commit event-dispatcher))))
 
-(defn preferred-size [component layer context]
-  (let [context (assoc context
-                  :target component
-                  :font-context (font-context component))
-        s (size layer context)]
-    (Dimension. (s 0) (s 1))))
+(defn preferred-size [component layer]
+  (binding [*path* nil
+            *font-context*' (font-context component)]
+    (let [s (size layer nil)]
+      (Dimension. (:width s) (:height s)))))
 
 (defn make-jpanel
   ([layer]
      (make-jpanel layer (make-event-dispatcher)))
   ([layer event-dispatcher]
-     (let [context (default-context)
-           context (assoc context :dispatcher event-dispatcher)
-           panel
+     (let [panel
            (proxy [JPanel] []
              (paintComponent [g]
-                (paint-component this layer context g))
+                (paint-component this layer g event-dispatcher))
              (getPreferredSize []
-                (preferred-size this layer context)))]
+                (preferred-size this layer)))]
+       (.setBackground panel (:back-color *theme*))
        (listen! event-dispatcher panel)
-       (.setBackground panel (-> context :theme :back-color))
        panel)))
 
 (comment
--- a/src/indyvon/core.clj	Sun Jul 04 06:03:48 2010 +0400
+++ b/src/indyvon/core.clj	Mon Jul 05 06:11:42 2010 +0400
@@ -8,145 +8,92 @@
   (:import (java.awt Color Font)
            (java.awt.event MouseListener MouseMotionListener)))
 
-(def *context*)
-(def *graphics*)
-
+(defrecord Location [x y])
 (defrecord Size [width height])
 (defrecord Bounds [x y width height])
 
+(def *graphics*)
 (def *font-context*)
 (def *bounds*)
-(def *theme*)
 (def *target*)
 (def *update*)
 (def *event-dispatcher*)
+(def *path*)
+
+(defrecord Theme [fore-color back-color border-color font])
+     
+(defn- default-theme []
+  (Theme. Color/BLACK Color/WHITE Color/BLUE (Font. "Sans" Font/PLAIN 12)))
+
+(def *theme* (default-theme))
 
 (defprotocol Layer
   "Basic UI element."
-  (render! [this context graphics])
-  (size [this context]))
+  (render! [this opts])
+  (size [this opts]))
+
+(defn layer? [x]
+  (satisfies? Layer x)) 
+
+(defprotocol EventDispatcher
+  (listen! [this component])
+  (register [this handle-path])
+  (handler [this handle-path event-id f])
+  (commit [this]))
 
 ;; TODO: modifiers
 (defrecord MouseEvent [id when x y x-on-screen y-on-screen button])
 
-(defprotocol MouseHandler
-  "Layers that also satisfy this protocol will recieve mouse events."
-  (handle-mouse [this context event]))
-
-(defprotocol EventDispatcher
-  (listen! [this component])
-  (register [this context])
-  (commit [this])
-  (hovered? [this layer])
-  (picked? [this layer]))
-
-(defprotocol Anchored
-  "Provide anchor point for Layers. Used by viewport."
-  (anchor [this context h-align v-align]
-          "Anchor point: [x y], h-align could be :left, :center
-           or :right, v-align is :top, :center or :bottom"))
+(defn- apply-theme [graphics]
+  (doto graphics
+    (.setColor (:fore-color *theme*))
+    (.setFont (:font *theme*))))
 
-;; Default implementation of Anchored for any Layer.
-(extend-protocol Anchored
-  indyvon.core.Layer
-  (anchor [this context h-align v-align]
-          (if (and (= h-align :left)
-                   (= v-align :top))
-            [0 0]
-            (let [size (size this context)]
-              [(case h-align
-                 :top 0
-                 :center (/ (size 0) 2)
-                 :right (size 0))
-               (case v-align
-                 :left 0
-                 :center (/ (size 1) 2)
-                 :bottom (size 1))]))))
-
-(defrecord Theme [fore-color back-color border-color font])
+(defn with-translate* [x y w h f & args]
+  (let [graphics (apply-theme (.create *graphics* x y w h))]
+    (try
+      (apply with-bindings* {#'*bounds* (Bounds. (+ x (:x *bounds*))
+                                                 (+ y (:y *bounds*))
+                                                 w h)
+                             #'*graphics* graphics}
+             f args)
+      (finally
+       (.dispose graphics)))))
 
-(defn default-theme []
-  (Theme. Color/BLACK Color/WHITE Color/BLUE (Font. "Sans" Font/PLAIN 12)))
-  
-(defrecord LayerContext
-  [handle           ; Identifies context for dispatching mouse
-                    ; entered/exited and mainaining keyboard focus.
-   parent           ; Parent context.
-   x y width height ; Geometry.
-   update-fn        ; Call to request repaint.
-   dispatcher       ; Event dispatcher.
-   font-context     ; An instance of java.awt.font.FontRenderContext.
-   theme            ; An instance of Theme.
-   target           ; Component.
-   handlers])       ; Map: event-id -> handler fn.
+(defmacro with-translate [x y w h & body]
+  `(with-translate* ~x ~y ~w ~h (fn [] ~@body)))
 
-(defn default-context []
-  (LayerContext. nil nil 0 0 0 0 nil nil nil (default-theme) nil nil))
-
-(defn update [context]
-  ((:update-fn context)))
+(defn with-handle* [handle f & args]
+  (let [path (cons handle *path*)]
+    (register *event-dispatcher* path)
+    (apply with-bindings* {#'*path* path} f args)))
 
-(defn- make-graphics [graphics x y w h clip]
-  (if clip
-    (.create graphics x y w h)
-    (doto (.create graphics)
-      (.translate x y))))
-
-(defn- apply-theme [graphics theme]
-  (doto graphics
-    (.setColor (:fore-color theme))
-    (.setFont (:font theme))))
+(defmacro with-handle [handle & body]
+  `(with-handle* ~handle (fn [] ~@body)))
 
-;; (defn with-context* [opts fn & args]
-;;   (let [context (apply assoc *context*
-;;                        :parent *context*
-;;                        :handlers nil
-;;                        opts)
-;;         graphics (make-graphics *graphics* x y w h false)
-;;         graphics (apply-theme graphics (:theme context))]
-;;     (try
-;;       (register (:dispatcher context) context)
-;;       (with-bindings* {#'*context* context
-;;                        #'*graphics* graphics}
-;;         fn args)
-;;       (finally
-;;        (.dispose graphics)))))
+(defn handle-event* [event-id f & args]
+  (let [f (if args #(f % args) f)]
+    (handler *event-dispatcher* *path* event-id f)))
 
-;; (defmacro with-context [opts & body]
-;;   `(with-context* ~opts #(~@body)))
+(defmacro handle-event [event-id name & body]
+  `(handle-event* ~event-id (fn [~name] ~@body)))
 
-(defn draw!
-  "Render layer in a new graphics context."
-  ([layer context graphics]
-     (draw! layer context graphics
-                    0 0 (:width context) (:height context)))
-  ([layer context graphics x y]
-     (draw! layer context graphics x y true))
-  ([layer context graphics x y clip]
-     (let [s (size layer context)]
-       (draw! layer context graphics
-              x y (s 0) (s 1) clip)))
-  ([layer context graphics x y w h]
-     (draw! layer context graphics
-            x y w h true))
-  ([layer context graphics x y w h clip]
-     (let [context (assoc context
-                     :handle layer
-                     :parent context
-                     :x (+ (:x context) x)
-                     :y (+ (:y context) y)
-                     :width w
-                     :height h)
-           graphics (make-graphics graphics x y w h clip)
-           graphics (apply-theme graphics (:theme context))]
-       (try
-         (register (:dispatcher context) context)
-         (render! layer context graphics)
-         (finally
-          (.dispose graphics))))))
+(defn- geometry-vec [geometry]
+  (if (vector? geometry)
+    geometry
+    [(:x geometry) (:y geometry) (:width geometry) (:height geometry)]))
+
+(defn draw! [layer geometry & args]
+  "Draw a layer. Geometry is either a map or vector [x y] or
+   [x y width height]."
+  (let [[x y w h] (geometry-vec geometry)
+        size (if-not (and w h) (size layer args))
+        w (or w (:width size))
+        h (or h (:height size))]
+    (with-translate* x y w h render! layer args)))
 
 ;;
-;; EventDispatcher implementation
+;; EventDispatcher
 ;;
 
 (def awt-events
@@ -158,25 +105,28 @@
       java.awt.event.MouseEvent/MOUSE_PRESSED  :mouse-pressed
       java.awt.event.MouseEvent/MOUSE_RELEASED :mouse-released})
 
-(defn- registered-parent
-  "Returns first context parent registered for event processing."
-  [context-tree context]
-  (let [parent (:parent context)]
-    (cond
-     (nil? parent) nil
-     (contains? context-tree parent) parent
-     :default (recur context-tree parent))))
+(defrecord DispatcherNode [id bounds children handlers])
+
+(defn- add-child [node child]
+  (assoc node :children (cons child (:children node))))
 
-(defn- add-context
-  [context-tree context]
-  (let [parent (registered-parent context-tree context)]
-    (assoc context-tree parent (cons context (context-tree parent))
-           context nil)))
+(defn- add-path [tree path]
+  (let [parent-path (next path)
+        parent-node (get tree parent-path)
+        node (DispatcherNode. path *bounds* nil
+                              (get-in tree [path :handlers]))]
+    (assoc tree
+      parent-path (add-child parent-node node)
+      path node)))
+
+(defn add-handler [tree path event-id f]
+  (let [keys [path :handlers event-id]]
+  (assoc-in tree keys (cons f (get-in tree keys)))))
 
 (defn- inside?
-  ([x y context]
-     (inside? x y (:x context) (:y context)
-              (:width context) (:height context)))
+  ([x y bounds]
+     (inside? x y (:x bounds) (:y bounds)
+              (:width bounds) (:height bounds)))
   ([px py x y w h]
      (and (>= px x)
           (>= py y)
@@ -184,13 +134,13 @@
           (< py (+ y h)))))
 
 (defn- under-cursor
-  "Returns a sequence of contexts under cursor."
-  ([context-tree x y]
-     (under-cursor context-tree x y nil))
-  ([context-tree x y context]
-     (some #(if (inside? x y %)
-              (conj (under-cursor context-tree x y %) %))
-           (context-tree context))))
+  "Returns a sequence of nodes under cursor."
+  ([tree x y]
+     (under-cursor tree x y nil))
+  ([tree x y node]
+     (some #(if (inside? x y (:bounds %))
+              (conj (under-cursor tree x y %) %))
+           (get tree (:children node)))))
 
 (defn- remove-all [coll1 coll2 pred]
   (filter #(not (some (partial pred %) coll2)) coll1))
@@ -203,30 +153,26 @@
                (.getButton event)))
 
 (defn- translate-and-dispatch
-  ([contexts event]
-     (translate-and-dispatch contexts event (awt-events (.getID event))))
-  ([contexts event id]
-     (doseq [context contexts]
-       (if-let [handler (get (:handlers context) id)]
-         (handler context (translate-mouse-event
-                           event (:x context) (:y context) id))))
+  ([nodes event]
+     (translate-and-dispatch nodes event (awt-events (.getID event))))
+  ([nodes event id]
+     (doseq [node nodes
+             :let [bounds (:bounds node)
+                   event (translate-mouse-event event
+                           (:x bounds) (:y bounds) id)]
+             handler (get (:handlers node) id)]
+       ;; TODO restore more of the original context.
+       (with-bindings* {#'*bounds* bounds} handler event))
      id))
 
-(defn- context-id [context]
-  (loop [context context
-         id nil]
-    (if context
-      (recur (:parent context) (cons (:handle context) id))
-      id)))
-
 (defn- dispatch-mouse-motion*
-  "Dispatches mouse motion events. Returns a new set of contexts which
+  "Dispatches mouse motion events. Returns a new set of nodes which
   currently are under cursor."
-  [hovered context-tree event]
+  [hovered tree event]
   (let [x (.getX event)
         y (.getY event)
-        hovered2 (under-cursor context-tree x y)
-        pred #(= (context-id %1) (context-id %2))
+        hovered2 (under-cursor tree x y)
+        pred #(= (:id %1) (:id %2))
         exited (remove-all hovered hovered2 pred)
         entered (remove-all hovered2 hovered pred)
         moved (remove-all hovered2 entered pred)]
@@ -236,12 +182,12 @@
     hovered2))
 
 (defn- dispatch-mouse-motion
-  [hovered-ref context-tree event]
+  [hovered-ref tree event]
   (dosync
-   (alter hovered-ref dispatch-mouse-motion* context-tree event)))
+   (alter hovered-ref dispatch-mouse-motion* tree event)))
 
 (defn- dispatch-mouse-button*
-  "Dispatches mouse button events. Returns a new set of contexts which
+  "Dispatches mouse button events. Returns a new set of nodes which
   currently are picked with a pressed button."
   [picked hovered event]
   (if (= (translate-and-dispatch hovered event) :mouse-pressed)
@@ -254,8 +200,10 @@
    (alter picked-ref dispatch-mouse-button* @hovered-ref event)))
 
 (defn make-event-dispatcher []
-  (let [context-tree-r (ref {}) ; register
-        context-tree (ref {})   ; dispatch
+  (let [root-node (DispatcherNode. nil nil nil nil)
+        tree-i {nil root-node} ; initial
+        tree-r (ref tree-i)    ; register
+        tree (ref tree-i)      ; dispatch
         hovered (ref '())
         picked (ref '())]
     (reify
@@ -264,19 +212,18 @@
         (doto component
           (.addMouseListener this)
           (.addMouseMotionListener this)))
-     (register [this context]
-        (if (:handlers context)
-          (dosync (alter context-tree-r add-context context))))
+     (register [this path]
+        (dosync (alter tree-r add-path path)))
+     (handler [this path event-id f]
+        (dosync (alter tree-r add-handler path event-id f)))
      (commit [this]
-        (dosync (ref-set context-tree @context-tree-r)
-                (ref-set context-tree-r {})))
-     (picked? [this layer] false)
-     (hovered? [this layer] false)
+        (dosync (ref-set tree @tree-r)
+                (ref-set tree-r tree-i)))
      MouseListener
      (mouseEntered [this event]
-        (dispatch-mouse-motion hovered @context-tree event))
+        (dispatch-mouse-motion hovered @tree event))
      (mouseExited [this event]
-        (dispatch-mouse-motion hovered @context-tree event))
+        (dispatch-mouse-motion hovered @tree event))
      (mouseClicked [this event]
         (dispatch-mouse-button picked hovered event))
      (mousePressed [this event]
@@ -287,4 +234,29 @@
      (mouseDragged [this event]
         (translate-and-dispatch @picked event))
      (mouseMoved [this event]
-        (dispatch-mouse-motion hovered @context-tree event)))))
+        (dispatch-mouse-motion hovered @tree event)))))
+
+;;
+;; ИДЕИ:
+;;
+;; Контекст: биндинги или запись?
+;;
+;; Установка обработчиков (в контексте слоя):
+;;
+;; (listen
+;;   (:mouse-entered e
+;;     ...)
+;;   (:mouse-exited e
+;;     ...))
+;;
+;; Не надо IMGUI.
+;; Построение сцены путем декорирования слоев:
+;;
+;; (listener
+;;  (:action e (println e))
+;;  (:mouse-dragged e (println e))
+;;  (theme :font "Helvetica-14"
+;;    (vbox
+;;      (button (text-layer "Button 1"))
+;;      (button (text-layer "Button 2")))))
+;;
--- a/src/indyvon/core_new.clj	Sun Jul 04 06:03:48 2010 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-;; Copyright (C) 2010 Mikhail Kryshen <mikhail@kryshen.net>
-;;
-;; This file is part of Indyvon.
-;;
-
-(ns indyvon.core_new
-  (:import (java.awt Color Font)
-           (java.awt.event MouseListener MouseMotionListener)))
-
-(defrecord Location [x y])
-(defrecord Size [width height])
-(defrecord Bounds [x y width height])
-
-(def *graphics*)
-(def *font-context*)
-(def *bounds*)
-(def *theme*)
-(def *target*)
-(def *update*)
-(def *event-dispatcher*)
-(def *path*)
-
-(defprotocol Layer
-  "Basic UI element."
-  (render! [this opts])
-  (size [this opts]))
-
-(defn layer? [x]
-  (satisfies? Layer x)) 
-
-(defprotocol EventDispatcher
-  (listen! [this component])
-  (register [this handle-path])
-  (handler [this handle-path event-id f])
-  (commit [this]))
-
-;; TODO: modifiers
-(defrecord MouseEvent [id when x y x-on-screen y-on-screen button])
-
-(defn with-translate* [x y w h f & args]
-  (let [graphics (.create *graphics* x y w h)]  
-    (try
-      (apply with-bindings* {#'*bounds* (Bounds. (+ x (:x *bounds*))
-                                                 (+ y (:y *bounds*))
-                                                 w h)
-                             #'*graphics* graphics}
-             f args)
-      (finally
-       (.dispose graphics)))))
-
-(defn with-handle* [handle f & args]
-  (let [path (cons handle *path*)]
-    (register *event-dispatcher* path)
-    (apply with-bindings* {#'*path* path} f args)))
-
-(defn- geometry-vec [geometry]
-  (if (vector? geometry)
-    geometry
-    [(:x geometry) (:y geometry) (:width geometry) (:height geometry)]))
-
-(defn draw! [layer geometry & args]
-  "Draw a layer. Geometry is either a map or vector [x y] or
-   [x y width height]."
-  (let [[x y w h] (geometry-vec geometry)
-        size (if-not (and w h) (size layer args))
-        w (or w (:width size))
-        h (or h (:height size))]
-    (with-translate* x y w h render! layer args)))
-
-(defn draw-root! [layer width height graphics event-dispatcher]
-  (with-bindings* {#'*path* nil
-                   #'*graphics* graphics
-                   #'*event-dispatcher* event-dispatcher
-                   #'*bounds* (Bounds. 0 0 width height)}
-    render! layer))
-
-;;
-;; EventDispatcher
-;;
-
-(def awt-events
-     {java.awt.event.MouseEvent/MOUSE_CLICKED  :mouse-clicked
-      java.awt.event.MouseEvent/MOUSE_DRAGGED  :mouse-dragged
-      java.awt.event.MouseEvent/MOUSE_ENTERED  :mouse-entered
-      java.awt.event.MouseEvent/MOUSE_EXITED   :mouse-exited
-      java.awt.event.MouseEvent/MOUSE_MOVED    :mouse-moved
-      java.awt.event.MouseEvent/MOUSE_PRESSED  :mouse-pressed
-      java.awt.event.MouseEvent/MOUSE_RELEASED :mouse-released})
-
-(defrecord DispatcherNode [id bounds children handlers])
-
-(defn- add-child [node child]
-  (assoc node :children (cons child (:children node))))
-
-(defn- add-path [tree path]
-  (let [parent-path (next path)
-        parent-node (get tree parent-path)
-        node (DispatcherNode. path *bounds* nil
-                              (get-in tree [path :handlers]))]
-    (assoc tree
-      parent-path (add-child parent-node node)
-      path node)))
-
-(defn add-handler [tree path event-id f]
-  (let [keys [path :handlers event-id]]
-  (assoc-in tree keys (cons f (get-in tree keys)))))
-
-(defn- inside?
-  ([x y bounds]
-     (inside? x y (:x bounds) (:y bounds)
-              (:width bounds) (:height bounds)))
-  ([px py x y w h]
-     (and (>= px x)
-          (>= py y)
-          (< px (+ x w))
-          (< py (+ y h)))))
-
-(defn- under-cursor
-  "Returns a sequence of nodes under cursor."
-  ([tree x y]
-     (under-cursor tree x y nil))
-  ([tree x y node]
-     (some #(if (inside? x y (:bounds %))
-              (conj (under-cursor tree x y %) %))
-           (get tree (:children node)))))
-
-(defn- remove-all [coll1 coll2 pred]
-  (filter #(not (some (partial pred %) coll2)) coll1))
-
-(defn- translate-mouse-event
-  [event x y id]
-  (MouseEvent. id (.getWhen event)
-               (- (.getX event) x) (- (.getY event) y)
-               (.getXOnScreen event) (.getYOnScreen event)
-               (.getButton event)))
-
-(defn- translate-and-dispatch
-  ([nodes event]
-     (translate-and-dispatch nodes event (awt-events (.getID event))))
-  ([nodes event id]
-     (doseq [node nodes
-             :let [bounds (:bounds node)
-                   event (translate-mouse-event event
-                           (:x bounds) (:y bounds) id)]
-             handler (get (:handlers node) id)]
-       ;; TODO restore more of the original context.
-       (with-bindings* {#'*bounds* bounds} handler event))
-     id))
-
-(defn- dispatch-mouse-motion*
-  "Dispatches mouse motion events. Returns a new set of nodes which
-  currently are under cursor."
-  [hovered tree event]
-  (let [x (.getX event)
-        y (.getY event)
-        hovered2 (under-cursor tree x y)
-        pred #(= (:id %1) (:id %2))
-        exited (remove-all hovered hovered2 pred)
-        entered (remove-all hovered2 hovered pred)
-        moved (remove-all hovered2 entered pred)]
-    (translate-and-dispatch exited event :mouse-exited)
-    (translate-and-dispatch entered event :mouse-entered)
-    (translate-and-dispatch moved event :mouse-moved)
-    hovered2))
-
-(defn- dispatch-mouse-motion
-  [hovered-ref tree event]
-  (dosync
-   (alter hovered-ref dispatch-mouse-motion* tree event)))
-
-(defn- dispatch-mouse-button*
-  "Dispatches mouse button events. Returns a new set of nodes which
-  currently are picked with a pressed button."
-  [picked hovered event]
-  (if (= (translate-and-dispatch hovered event) :mouse-pressed)
-    hovered
-    nil))
-
-(defn- dispatch-mouse-button
-  [picked-ref hovered-ref event]
-  (dosync
-   (alter picked-ref dispatch-mouse-button* @hovered-ref event)))
-
-(defn make-event-dispatcher []
-  (let [root-node (DispatcherNode. nil nil nil nil)
-        tree-i {nil root-node} ; initial
-        tree-r (ref tree-i)    ; register
-        tree (ref tree-i)      ; dispatch
-        hovered (ref '())
-        picked (ref '())]
-    (reify
-     EventDispatcher
-     (listen! [this component]
-        (doto component
-          (.addMouseListener this)
-          (.addMouseMotionListener this)))
-     (register [this path]
-        (dosync (alter tree-r add-path path)))
-     (handler [this path event-id f]
-        (dosync (alter tree-r add-handler path event-id f)))
-     (commit [this]
-        (dosync (ref-set tree @tree-r)
-                (ref-set tree-r tree-i)))
-     MouseListener
-     (mouseEntered [this event]
-        (dispatch-mouse-motion hovered @tree event))
-     (mouseExited [this event]
-        (dispatch-mouse-motion hovered @tree event))
-     (mouseClicked [this event]
-        (dispatch-mouse-button picked hovered event))
-     (mousePressed [this event]
-        (dispatch-mouse-button picked hovered event))
-     (mouseReleased [this event]
-        (dispatch-mouse-button picked hovered event))
-     MouseMotionListener
-     (mouseDragged [this event]
-        (translate-and-dispatch @picked event))
-     (mouseMoved [this event]
-        (dispatch-mouse-motion hovered @tree event)))))
-
-;; (with-handle :button1
-;;   (draw! button [5 5 100 200] "Cick Me!"))
-
-;; (when-event :action :button1
-;;     ...)
-
-;; (handle-event :mouse-entered :button1
-;;     ...)