Implemented action handling in Buttons and Menus

This commit is contained in:
Daniel Ziltener 2015-01-18 04:26:18 +00:00
parent de9e165e2f
commit 22dffc8fda
5 changed files with 147 additions and 78 deletions

View file

@ -26,7 +26,8 @@
:scm {:url "https://bitbucket.com/zilti/clojurefx"} :scm {:url "https://bitbucket.com/zilti/clojurefx"}
:license {"name" "GNU Lesser General Public License 3.0" :license {"name" "GNU Lesser General Public License 3.0"
"url" "http://www.gnu.org/licenses/lgpl-3.0.txt"}} "url" "http://www.gnu.org/licenses/lgpl-3.0.txt"}}
midje {:test-paths #{"test"}} midje {:test-paths #{"test"}
:sources #{"src" "test"}}
typed {:namespaces #{'clojurefx.clojurefx 'clojurefx.protocols 'clojurefx.scripting}} typed {:namespaces #{'clojurefx.clojurefx 'clojurefx.protocols 'clojurefx.scripting}}
repl {:server true}) repl {:server true})
@ -35,8 +36,6 @@
(task-options! (task-options!
midje {:autotest true}) midje {:autotest true})
(set-env! :resource-paths #{"src" "test"})
(comp (repl) (comp (repl)
(midje) (midje)
(watch) (watch)

View file

@ -5,22 +5,26 @@
[taoensso.timbre :as timbre] [taoensso.timbre :as timbre]
[clojure.java.io :as io] [clojure.java.io :as io]
[clojure.zip :as zip] [clojure.zip :as zip]
[clojurefx.protocols :refer :all] [clojurefx.protocols :as p]
[clojure.java.io :refer :all])) [clojure.java.io :refer :all]))
(defonce force-toolkit-init (javafx.embed.swing.JFXPanel.)) (defonce force-toolkit-init (javafx.embed.swing.JFXPanel.))
;; ## Threading helpers ;; ## Threading helpers
(defn run-later*" (ann run-later* [(Fn [-> Any]) -> nil])
Simple wrapper for Platform/runLater. You should use run-later. (defn run-later*"
Simple wrapper for Platform/runLater. You should use run-later.
" [f] " [f]
(javafx.application.Platform/runLater f)) (tc-ignore (assert (instance? Runnable f))
(javafx.application.Platform/runLater f))
nil)
(defmacro run-later [& body] (defmacro run-later [& body]
`(run-later* (fn [] ~@body))) `(run-later* (fn [] ~@body)))
(defn run-now*" (ann run-now* (All [x] [[-> x] -> x]))
(defn run-now* "
A modification of run-later waiting for the running method to return. You should use run-now. A modification of run-later waiting for the running method to return. You should use run-now.
" [f] " [f]
(if (javafx.application.Platform/isFxApplicationThread) (if (javafx.application.Platform/isFxApplicationThread)
@ -39,48 +43,44 @@ Simple wrapper for Platform/runLater. You should use run-later.
(import (javafx.scene.control Labeled Label TextField TextArea CheckBox ComboBox Menu MenuItem MenuBar (import (javafx.scene.control Labeled Label TextField TextArea CheckBox ComboBox Menu MenuItem MenuBar
MenuButton ContextMenu ToolBar SplitPane ScrollPane Accordion MenuButton ContextMenu ToolBar SplitPane ScrollPane Accordion
TitledPane TabPane Tab TableColumnBase Labeled) TitledPane TabPane Tab TableColumnBase Labeled ButtonBase)
(javafx.scene Node Scene Parent) (javafx.scene Node Scene Parent)
(javafx.scene.layout Pane VBox) (javafx.scene.layout Pane VBox)
(javafx.stage Stage) (javafx.stage Stage)
(javafx.collections FXCollections ObservableList) (javafx.collections FXCollections ObservableList)
(javafx.css Styleable) (javafx.css Styleable)
(javafx.event Event ActionEvent EventTarget)
(java.util Collection)) (java.util Collection))
;; TODO Use pred-substitute for tc-assert?
(defn tc-assert [clazz :- Class value :- Any & [message :- String]] (defn tc-assert [clazz :- Class value :- Any & [message :- String]]
(try (assert (instance? clazz value)) (try (assert (instance? clazz value))
(catch AssertionError e (tc-ignore (error (if message message "") e) (catch AssertionError e (tc-ignore (error (if message message "") e)
(error "Expected:" clazz "Actual:" (type value)) (error "Expected:" clazz "Actual:" (type value))
(throw e))))) (throw e)))))
(ann pred-substitute [Class -> (Fn [Any -> Boolean])]) (defn pred-protocol [proto :- (HMap :mandatory {:impls (Map Keyword Class)}) check :- Any] :- Boolean
(defn pred-substitute [clazz]
(clojure.core.typed/pred* (quote clazz) 'clojurefx.clojurefx
(fn [arg] (boolean (instance? clazz arg)))))
(defn pred-protocol [proto check]
(let [impls (keys (proto :impls)) (let [impls (keys (proto :impls))
check (type check)] check (type check)]
(reduce #(or %1 (isa? check %2)) false impls))) (reduce #(or %1 (isa? check %2)) false impls)))
;;## Shadows ;;## Shadows
(extend-protocol FXMeta (tc-ignore
clojure.lang.IObj (extend-protocol p/FXMeta
(meta [this] (clojure.core/meta this)) clojure.lang.IObj
(with-meta [this metadata] (clojure.core/with-meta this metadata)) (meta [this] (clojure.core/meta this))
Node (with-meta [this metadata] (clojure.core/with-meta this metadata))
(meta [this] (.getUserData ^Node this)) Node
(with-meta [this metadata] (.setUserData ^Node this metadata) this) (meta [this] (.getUserData ^Node this))
MenuItem (with-meta [this metadata] (.setUserData ^Node this metadata) this)
(meta [this] (.getUserData ^MenuItem this)) MenuItem
(with-meta [this metadata] (.setUserData ^MenuItem this metadata) this)) (meta [this] (.getUserData ^MenuItem this))
(with-meta [this metadata] (.setUserData ^MenuItem this metadata) this)))
;;## Standard ;;## Standard
(tc-ignore (tc-ignore
(extend-protocol FXValue (extend-protocol p/FXValue
Labeled Labeled
(get-value [this] (.getText ^Label this)) (get-value [this] (.getText ^Label this))
(set-value! [this value] (tc-assert String value) (.setText ^Label this ^String value) this) (set-value! [this value] (tc-assert String value) (.setText ^Label this ^String value) this)
@ -112,13 +112,13 @@ Simple wrapper for Platform/runLater. You should use run-later.
(set-value! [this value] (tc-assert String value) (.setText ^MenuItem this ^String value) this))) (set-value! [this value] (tc-assert String value) (.setText ^MenuItem this ^String value) this)))
(tc-ignore (tc-ignore
(extend-protocol FXId (extend-protocol p/FXId
Styleable Styleable
(get-id [this] (.getId ^Styleable this)) (get-id [this] (.getId ^Styleable this))
(set-id! [this id] (tc-assert String id) (.setId ^Styleable this ^String id) this))) (set-id! [this id] (tc-assert String id) (.setId ^Styleable this ^String id) this)))
(tc-ignore (tc-ignore
(extend-protocol FXParent (extend-protocol p/FXParent
Pane Pane
(get-subnodes [this] (.getChildren ^Pane this)) (get-subnodes [this] (.getChildren ^Pane this))
(set-subnodes! [this nodes] (.setAll ^ObservableList (.getChildren ^Pane this) ^Collection nodes) this) (set-subnodes! [this nodes] (.setAll ^ObservableList (.getChildren ^Pane this) ^Collection nodes) this)
@ -148,7 +148,7 @@ Simple wrapper for Platform/runLater. You should use run-later.
(set-subnodes! [this nodes] (.setAll ^ObservableList (.getPanes ^Accordion this) ^Collection nodes) this))) (set-subnodes! [this nodes] (.setAll ^ObservableList (.getPanes ^Accordion this) ^Collection nodes) this)))
(tc-ignore (tc-ignore
(extend-protocol FXContainer (extend-protocol p/FXContainer
Tab Tab
(get-content [this] (.getContent ^Tab this)) (get-content [this] (.getContent ^Tab this))
(set-content! [this node] (.setContent ^Tab this ^Node node) this) (set-content! [this node] (.setContent ^Tab this ^Node node) this)
@ -160,7 +160,7 @@ Simple wrapper for Platform/runLater. You should use run-later.
(set-content! [this node] (.setContent ^ScrollPane this ^Node node) this))) (set-content! [this node] (.setContent ^ScrollPane this ^Node node) this)))
(tc-ignore (tc-ignore
(extend-protocol FXGraphic (extend-protocol p/FXGraphic
Labeled Labeled
(get-graphic [this] (.getGraphic ^Labeled this)) (get-graphic [this] (.getGraphic ^Labeled this))
(set-graphic! [this graphic] (.setGraphic ^Labeled this ^Node graphic)) (set-graphic! [this graphic] (.setGraphic ^Labeled this ^Node graphic))
@ -168,60 +168,99 @@ Simple wrapper for Platform/runLater. You should use run-later.
(get-graphic [this] (.getGraphic ^Menu this)) (get-graphic [this] (.getGraphic ^Menu this))
(set-graphic! [this graphic] (.setGraphic ^Menu this ^Node graphic)))) (set-graphic! [this graphic] (.setGraphic ^Menu this ^Node graphic))))
(extend-protocol FXStyleSetter (tc-ignore
Node (extend-protocol p/FXStyleSetter
(set-style! [this style] (.setStyle ^Node this ^String style) this) Node
MenuItem (set-style! [this style] (.setStyle ^Node this ^String style) this)
(set-style! [this style] (.setStyle ^MenuItem this ^String style) this)) MenuItem
(set-style! [this style] (.setStyle ^MenuItem this ^String style) this)))
(extend-type Styleable (tc-ignore
FXStyleable (extend-type Styleable
(get-css-meta [this] (.getCssMetaData ^Styleable this)) p/FXStyleable
(get-pseudo-class-styles [this] (.getPseudoClassStyles ^Styleable this)) (get-css-meta [this] (.getCssMetaData ^Styleable this))
(get-style [this] (.getStyle ^Styleable this)) (get-pseudo-class-styles [this] (.getPseudoClassStyles ^Styleable this))
(get-style-classes [this] (.getStyleClass ^Styleable this)) (get-style [this] (.getStyle ^Styleable this))
(set-style-classes! [this classes] (.setAll ^ObservableList (.getStyleClass ^Styleable this) classes) this) (get-style-classes [this] (.getStyleClass ^Styleable this))
(get-styleable-parent [this] (.getStyleableParent ^Styleable this)) (set-style-classes! [this classes] (.setAll ^ObservableList (.getStyleClass ^Styleable this) classes) this)
(get-type-selector [this] (.getTypeSelector ^Styleable this))) (get-styleable-parent [this] (.getStyleableParent ^Styleable this))
(get-type-selector [this] (.getTypeSelector ^Styleable this))))
(declare bind-event)
(tc-ignore
(extend-protocol p/FXOnAction
ButtonBase
(set-action! [this action] (.setOnAction ^ButtonBase this (bind-event action)) this)
(fire! [this] (.fire this))
MenuItem
(set-action! [this action] (.setOnAction ^ButtonBase this (bind-event action)) this)
(fire! [this] (.fire this))))
;;## Special Types ;;## Special Types
(extend-type Stage ;;### javafx.event
FXStage
(get-title [this] (.getTitle ^Stage this))
(set-title! [this title] (.setTitle ^Stage this ^String title))
(get-scene [this] (.getScene ^Stage this))
(set-scene! [this scene] (.setScene ^Stage this ^Scene scene)))
(extend-type Scene (tc-ignore
FXScene (extend-type Event
(get-root [this] (.getRoot ^Scene this)) p/FXEvent
(set-root! [this root] (.setRoot ^Scene this ^Parent root) this)) (source [this] (.getSource ^Event this))
(consume! [this] (.consume ^Event this) this)
(copy [this new-src new-target] (.copy ^Event this new-src new-target))
(event-type [this] (.getEventType this))
(target [this] (.getTarget this))
(consumed? [this] (.isConsumed this))))
;;### javafx.stage
(tc-ignore
(extend-type Stage
p/FXStage
(get-title [this] (.getTitle ^Stage this))
(set-title! [this title] (.setTitle ^Stage this ^String title))
(get-scene [this] (.getScene ^Stage this))
(set-scene! [this scene] (.setScene ^Stage this ^Scene scene))))
;;### javafx.scene
(tc-ignore
(extend-type Scene
p/FXScene
(get-root [this] (.getRoot ^Scene this))
(set-root! [this root] (.setRoot ^Scene this ^Parent root) this)))
;;## Event handling helper
(tc-ignore
(defn bind-event
[handler :- (All [[A :variance :covariant :< Event]] (Fn [A -> Any]))] :- javafx.event.EventHandler
(reify javafx.event.EventHandler
(handle [_ event] (handler event)))))
;;## IdMapper ;;## IdMapper
(defn fxzipper [root] (defn fxzipper [root]
(zip/zipper (fn branch? [node] (zip/zipper (fn branch? [node :- Any] :- Boolean
(or (pred-protocol FXParent node) (pred-protocol FXContainer node))) (or (pred-protocol p/FXParent node) (pred-protocol p/FXContainer node)))
(fn children [node] (fn children [node :- (U p/FXParent p/FXContainer)] :- java.util.List
(if (pred-protocol FXParent node) (if (pred-protocol p/FXParent node)
(into [] (get-subnodes node)) (into [] (p/get-subnodes node))
[(get-content node)])) [(p/get-content node)]))
(fn make-node [node children] (fn make-node [node :- (U p/FXParent p/FXContainer) children :- Any] :- (U p/FXParent p/FXContainer)
(if (pred-protocol FXParent node) (if (pred-protocol p/FXParent node)
(set-subnodes! node children) (p/set-subnodes! node children)
(set-content! node children))) (p/set-content! node children)))
root)) root))
(defn get-node-by-id [graph id] (tc-ignore
(loop [zipper (fxzipper graph)] (defn get-node-by-id [graph id]
(cond (zip/end? zipper) nil (loop [zipper (fxzipper graph)]
(= (get-id (zip/node zipper)) (name id)) (zip/node zipper) (cond (zip/end? zipper) nil
:else (recur (zip/next zipper))))) (= (p/get-id (zip/node zipper)) (name id)) (zip/node zipper)
:else (recur (zip/next zipper))))))
(defn get-id-map [graph] (tc-ignore
(loop [zipper (fxzipper graph) (defn get-id-map [graph]
ids {}] (loop [zipper (fxzipper graph)
(if (zip/end? zipper) ids {}]
ids (if (zip/end? zipper)
(recur (zip/next zipper) ids
(assoc ids (keyword (get-id (zip/node zipper))) (zip/node zipper)))))) (recur (zip/next zipper)
(assoc ids (keyword (p/get-id (zip/node zipper))) (zip/node zipper)))))))

View file

@ -22,6 +22,7 @@
(def getter first) (def getter first)
(def setter second) (def setter second)
(ann translation-map (Atom1 (Map Keyword (Vec clojure.lang.Var))))
(def translation-map (def translation-map
(atom {;;; FXValue (atom {;;; FXValue
:text (with-meta [#'get-value #'set-value!] {:argument String :parent FXValue}) :text (with-meta [#'get-value #'set-value!] {:argument String :parent FXValue})

View file

@ -27,7 +27,7 @@
(defalias FXElement (U FXValue FXId)) (defalias FXElement (U FXValue FXId))
(defprotocol [[A :variance :covariant] (defprotocol [[A :variance :covariant]
[B :variance :covariant]] [B :variance :covariant :< Seqable]]
FXParent FXParent
"The ClojureFX extension to javafx.scene.Parent." "The ClojureFX extension to javafx.scene.Parent."
(get-subnodes [this :- A] :- B) (get-subnodes [this :- A] :- B)
@ -63,8 +63,26 @@
(defalias FXStyled (U FXStyleable FXStyleSetter)) (defalias FXStyled (U FXStyleable FXStyleSetter))
(defprotocol [[A :variance :covariant]]
FXOnAction
(set-action! [this :- A action :- [javafx.event.EventHandler -> Any]] :- A)
(fire! [this :- A] :- nil))
;;## Special Types ;;## Special Types
;;### javafx.event
(defprotocol [[A :variance :covariant :< javafx.event.Event]]
FXEvent
(source [this :- A] :- Any)
(consume! [this :- A] :- A)
(copy [this :- A newSource :- Object newTarget :- javafx.event.EventTarget] :- A)
(event-type [this :- A] :- javafx.event.EventType)
(target [this :- A] :- javafx.event.EventTarget)
(consumed? [this :- A] :- Boolean))
;;### javafx.stage
(defprotocol [[A :variance :covariant :< javafx.stage.Stage] (defprotocol [[A :variance :covariant :< javafx.stage.Stage]
[B :variance :covariant :< javafx.scene.Scene]] [B :variance :covariant :< javafx.scene.Scene]]
FXStage FXStage
@ -73,6 +91,8 @@
(get-scene [this :- A] :- B) (get-scene [this :- A] :- B)
(set-scene! [this :- A scene :- B] :- A)) (set-scene! [this :- A scene :- B] :- A))
;;### javafx.scene
(defprotocol [[A :variance :covariant :< javafx.scene.Scene] (defprotocol [[A :variance :covariant :< javafx.scene.Scene]
[B :variance :covariant :< javafx.scene.Parent]] [B :variance :covariant :< javafx.scene.Parent]]
FXScene FXScene

View file

@ -10,6 +10,16 @@
;;## Element testing ;;## Element testing
;;## Event testing
(def button (new Button))
(def fired? (atom false))
(facts "Events"
(fact "Adding an event handler"
(set-action! button (fn [event] (reset! fired? true))) => button)
(fact "Firing the event and checking the result"
(do (fire! button)
@fired?) => true))
;;## IdMapper ;;## IdMapper
(def example-graph (def example-graph
(factory/compile (factory/compile