Implemented action handling in Buttons and Menus
This commit is contained in:
parent
de9e165e2f
commit
22dffc8fda
5 changed files with 147 additions and 78 deletions
|
@ -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})
|
||||||
|
|
||||||
|
@ -34,8 +35,6 @@
|
||||||
[]
|
[]
|
||||||
(task-options!
|
(task-options!
|
||||||
midje {:autotest true})
|
midje {:autotest true})
|
||||||
|
|
||||||
(set-env! :resource-paths #{"src" "test"})
|
|
||||||
|
|
||||||
(comp (repl)
|
(comp (repl)
|
||||||
(midje)
|
(midje)
|
||||||
|
|
|
@ -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)))))))
|
||||||
|
|
|
@ -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})
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue