summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/votann/codex.clj44
-rw-r--r--src/votann/core.clj29
-rw-r--r--src/votann/current_list_widget.clj52
-rw-r--r--src/votann/enhancements_widget.clj11
-rw-r--r--src/votann/event_handler.clj54
-rw-r--r--src/votann/list_widget.clj15
-rw-r--r--src/votann/point_chart_widget.clj17
-rw-r--r--src/votann/tab_widget.clj23
-rw-r--r--src/votann/unit_widget.clj12
-rw-r--r--src/votann/units_and_points_widget.clj38
-rw-r--r--src/votann/util.clj48
11 files changed, 343 insertions, 0 deletions
diff --git a/src/votann/codex.clj b/src/votann/codex.clj
new file mode 100644
index 0000000..14d8ddf
--- /dev/null
+++ b/src/votann/codex.clj
@@ -0,0 +1,44 @@
+(ns votann.codex)
+
+(defrecord Unit [count points])
+
+(def kin-models
+ [{:name "Uthar The Destined"
+ :units [(Unit. "x1" 115)]}
+ {:name "Kahl"
+ :units [(Unit. "x1" 90)]}
+ {:name "Einhyr Champion"
+ :units [(Unit. "x1" 75)]}
+ {:name "Grimnyr"
+ :units [(Unit. "x3" 75)]}
+ {:name "Brokhyr Iron-Master"
+ :units [(Unit. "x3" 95)
+ (Unit. "x6" 190)]}
+ {:name "Hearthkyn Warriors"
+ :units [(Unit. "x10" 135)]}
+ {:name "Einhyr Hearthguard"
+ :units [(Unit. "x5" 165)
+ (Unit. "x10" 330)]}
+ {:name "Cthonian Beserks"
+ :units [(Unit. "x5" 135)
+ (Unit. "x10" 270)]}
+ {:name "Hernkyn Pioneers"
+ :units [(Unit. "x3" 105)
+ (Unit. "x6" 210)]}
+ {:name "Sagitaur"
+ :units [(Unit. "x1" 120)]}
+ {:name "Brokhyr Thunderkyn"
+ :units [(Unit. "x3" 95)
+ (Unit. "x6" 190)]}
+ {:name "Hekaton Land Fortress"
+ :units [(Unit. "x1" 245)]}])
+
+(def kin-enhancements
+ [{:name "A Long List"
+ :units [(Unit. "x1" 15)]}
+ {:name "Apprasing Glare"
+ :units [(Unit. "x1" 20)]}
+ {:name "Grim Demeanour"
+ :units [(Unit. "x1" 20)]}
+ {:name "Wayfarers Grace"
+ :units [(Unit. "x1" 20)]}])
diff --git a/src/votann/core.clj b/src/votann/core.clj
new file mode 100644
index 0000000..50322eb
--- /dev/null
+++ b/src/votann/core.clj
@@ -0,0 +1,29 @@
+(ns votann.core
+ (:gen-class)
+ (:require [votann.util :refer [get-resource-path]]
+ [votann.event-handler :refer [map-event-handler *list-units]]
+ [votann.tab_widget :refer [tab-widget]]
+ [cljfx.api :as fx]))
+
+(defn root-view [data]
+ {:fx/type :stage
+ :max-width 1253
+ :max-height 860
+ :icons [(get-resource-path (str "leagues-of-votann/icon256x256.png"))
+ (get-resource-path (str "leagues-of-votann/icon48x48.png"))
+ (get-resource-path (str "leagues-of-votann/icon32x32.png"))]
+ :showing true
+ :title "Votann"
+ :scene {:fx/type :scene
+ :root {:fx/type :stack-pane
+ :children [{:fx/type :tab-pane
+ :tabs (tab-widget data)}]}}})
+
+(def renderer
+ (fx/create-renderer
+ :middleware (fx/wrap-map-desc assoc :fx/type root-view)
+ :opts {:fx.opt/map-event-handler map-event-handler}))
+
+(defn -main
+ [& args]
+ (fx/mount-renderer *list-units renderer))
diff --git a/src/votann/current_list_widget.clj b/src/votann/current_list_widget.clj
new file mode 100644
index 0000000..9f54f0a
--- /dev/null
+++ b/src/votann/current_list_widget.clj
@@ -0,0 +1,52 @@
+(ns votann.current-list-widget
+ (:require [cljfx.api :as fx]))
+
+(defn current-list [data]
+ (vec (for [[index unit] (map-indexed vector data)]
+ {:fx/type :v-box
+ :padding 5
+ :children [{:fx/type :label
+ :text (:name unit)}
+ {:fx/type :h-box
+ :alignment :center-left
+ :spacing 5
+ :children [{:fx/type :button
+ :on-mouse-clicked {:event/type :event/remove-unit-click
+ :event/target {:index index
+ :points (:points unit)}}
+ :on-key-pressed {:event/type :event/remove-unit-enter
+ :event/target {:index index
+ :points (:points unit)}}
+ :text "Remove"}
+ {:fx/type :label
+ :text (str (:points unit) "pts")}]}]})))
+
+(defn current-list-label-widget [{:keys [points]}]
+ {:fx/type :v-box
+ :alignment :center
+ :children [
+ {:fx/type :label
+ :style "-fx-font-size: 18px; -fx-font-weight: bold;"
+ :text "Current List"}
+ {:fx/type :h-box
+ :alignment :center
+ :spacing 50
+ :children [{:fx/type :button
+ :on-mouse-clicked {:event/type :event/restart-click}
+ :on-key-pressed {:event/type :event/restart-enter}
+ :text "Restart"}
+ {:fx/type :label
+ :style "-fx-font-size: 18px; -fx-font-weight: bold;"
+ :text (str points " pts")}
+ {:fx/type :button
+ :on-mouse-clicked {:event/type :event/undo-unit-click}
+ :on-key-pressed {:event/type :event/undo-unit-enter}
+ :text "Undo"}]}
+ ]})
+
+(defn current-list-widget [{:keys [units]}]
+ {:fx/type :scroll-pane
+ :content {:fx/type :v-box
+ :alignment :top-center
+ :pref-height 600
+ :children (current-list units)}})
diff --git a/src/votann/enhancements_widget.clj b/src/votann/enhancements_widget.clj
new file mode 100644
index 0000000..65a99a2
--- /dev/null
+++ b/src/votann/enhancements_widget.clj
@@ -0,0 +1,11 @@
+(ns votann.enhancements-widget
+ (:require [votann.util :refer [get-resource-path]]
+ [cljfx.api :as fx]))
+
+(def enhancements-view-widget
+ {:fx/type :scroll-pane
+ :content {:fx/type :h-box
+ :children [{:fx/type :image-view
+ :fit-width 1233
+ :preserve-ratio true
+ :image (get-resource-path (str "leagues-of-votann/enhancements.png"))}]}})
diff --git a/src/votann/event_handler.clj b/src/votann/event_handler.clj
new file mode 100644
index 0000000..89d9795
--- /dev/null
+++ b/src/votann/event_handler.clj
@@ -0,0 +1,54 @@
+(ns votann.event-handler
+ (:import [javafx.scene.input KeyCode KeyEvent]))
+
+(def *list-units (atom {:points 0 :units []}))
+
+(defn enter-event [function e]
+ (if (= KeyCode/ENTER (.getCode ^KeyEvent (:fx/event e)))
+ (function e)))
+
+(defn undo-points [_]
+ (if-not (empty? (get-in @*list-units [:units]))
+ (let [points (:points (last (:units @*list-units)))]
+ (swap! *list-units assoc :points (max 0 (- (:points @*list-units) points)))
+ (swap! *list-units update-in [:units] pop))))
+
+(defn restart-list [_]
+ (if-not (empty? (get-in @*list-units [:units]))
+ (do
+ (swap! *list-units assoc :points 0)
+ (swap! *list-units assoc-in [:units] []))))
+
+(defn add-unit [e]
+ (swap! *list-units assoc :points (+ (:points @*list-units) (:points (:event/target e))))
+ (swap! *list-units update-in [:units] conj (:event/target e)))
+
+(defn remove-unit [e]
+ (do
+ (swap! *list-units assoc :points (max 0 (- (:points @*list-units) (:points (:event/target e)))))
+ (swap! *list-units update :units #(vec (concat (subvec % 0 (:index (:event/target e))) (subvec % (inc (:index (:event/target e)))))))))
+
+(defn map-event-handler [e]
+ (cond (= :event/undo-unit-click (:event/type e))
+ (undo-points e)
+
+ (= :event/undo-unit-enter (:event/type e))
+ (enter-event undo-points e)
+
+ (= :event/restart-click (:event/type e))
+ (restart-list e)
+
+ (= :event/restart-enter (:event/type e))
+ (enter-event restart-list e)
+
+ (= :event/remove-unit-click (:event/type e))
+ (remove-unit e)
+
+ (= :event/remove-unit-enter (:event/type e))
+ (enter-event remove-unit e)
+
+ (= :event/add-unit-click (:event/type e))
+ (add-unit e)
+
+ (= :event/add-unit-enter (:event/type e))
+ (enter-event add-unit e)))
diff --git a/src/votann/list_widget.clj b/src/votann/list_widget.clj
new file mode 100644
index 0000000..efd751e
--- /dev/null
+++ b/src/votann/list_widget.clj
@@ -0,0 +1,15 @@
+(ns votann.list-widget
+ (:require [votann.point-chart-widget :refer [point-chart-widget]]
+ [votann.units-and-points-widget :refer [unit-and-points-widget]]
+ [votann.current-list-widget :refer [current-list-label-widget current-list-widget]]
+ [cljfx.api :as fx]))
+
+(defn left-widget [data]
+ {:fx/type :v-box
+ :alignment :center
+ :children [(point-chart-widget data) (current-list-label-widget data) (current-list-widget data)]})
+
+(defn list-view-widget [data]
+ {:fx/type :h-box
+ :alignment :center
+ :children [(left-widget data) unit-and-points-widget]})
diff --git a/src/votann/point_chart_widget.clj b/src/votann/point_chart_widget.clj
new file mode 100644
index 0000000..c4ac331
--- /dev/null
+++ b/src/votann/point_chart_widget.clj
@@ -0,0 +1,17 @@
+(ns votann.point-chart-widget
+ (:require [cljfx.api :as fx]
+ [votann.util :refer [ext-recreate-on-key-changed]]))
+
+(defn chart-data [units]
+ (for [unit (set units)]
+ {:fx/type :pie-chart-data
+ :name (:name unit)
+ :pie-value (* (:points unit) (count (filter #(= (:name %) (:name unit)) units)))}))
+
+(defn point-chart-widget [{:keys [units]}]
+ {:fx/type ext-recreate-on-key-changed
+ :key units
+ :desc {:fx/type :pie-chart
+ :pref-height 600
+ :title "Point Distribution"
+ :data (chart-data units)}})
diff --git a/src/votann/tab_widget.clj b/src/votann/tab_widget.clj
new file mode 100644
index 0000000..ab6a8ae
--- /dev/null
+++ b/src/votann/tab_widget.clj
@@ -0,0 +1,23 @@
+(ns votann.tab_widget
+ (:require [votann.list-widget :refer [list-view-widget]]
+ [votann.util :refer [get-models unit-file-name]]
+ [votann.unit-widget :refer [unit-view-widget]]
+ [votann.enhancements-widget :refer [enhancements-view-widget]]
+ [cljfx.api :as fx]))
+
+(defn tab-widget [data]
+ (vec (apply merge
+ (vec (apply merge
+ [{:fx/type :tab
+ :text "List"
+ :closable false
+ :content (list-view-widget data)}]
+ (vec (for [unit get-models]
+ {:fx/type :tab
+ :text unit
+ :closable false
+ :content (unit-view-widget (unit-file-name unit))}))))
+ [{:fx/type :tab
+ :text "Enhancements"
+ :closable false
+ :content enhancements-view-widget}])))
diff --git a/src/votann/unit_widget.clj b/src/votann/unit_widget.clj
new file mode 100644
index 0000000..5d31b99
--- /dev/null
+++ b/src/votann/unit_widget.clj
@@ -0,0 +1,12 @@
+(ns votann.unit-widget
+ (:require [votann.util :refer [get-resource-path]]
+ [cljfx.api :as fx]))
+
+(defn unit-view-widget [unit-file-name]
+ {:fx/type :scroll-pane
+ :content {:fx/type :v-box
+ :alignment :center
+ :children [{:fx/type :image-view
+ :image (get-resource-path (str "leagues-of-votann/" unit-file-name "-front.png"))}
+ {:fx/type :image-view
+ :image (get-resource-path (str "leagues-of-votann/" unit-file-name "-back.png"))}]}})
diff --git a/src/votann/units_and_points_widget.clj b/src/votann/units_and_points_widget.clj
new file mode 100644
index 0000000..48018dd
--- /dev/null
+++ b/src/votann/units_and_points_widget.clj
@@ -0,0 +1,38 @@
+(ns votann.units-and-points-widget
+ (:require [votann.util :refer [get-units]]
+ [cljfx.api :as fx]))
+
+
+(def units-points-label-widget
+ {:fx/type :label
+ :style "-fx-font-size: 18px; -fx-font-weight: bold;"
+ :text "Units & Points"})
+
+(def unit-points-list-widget
+ (vec (for [unit get-units]
+ {:fx/type :v-box
+ :padding 5
+ :children [{:fx/type :label
+ :text (:name unit)}
+ {:fx/type :h-box
+ :alignment :center-left
+ :spacing 5
+ :children [{:fx/type :button
+ :on-mouse-clicked {:event/type :event/add-unit-click
+ :event/target {:name (:name unit)
+ :points (:points unit)}}
+ :on-key-pressed {:event/type :event/add-unit-enter
+ :event/target {:name (:name unit)
+ :points (:points unit)}}
+ :text "Add"}
+ {:fx/type :label
+ :text (str (:points unit) " pts")}]}]})))
+
+(def unit-and-points-widget
+ {:fx/type :scroll-pane
+ :fit-to-width true
+ :min-width 175
+ :content
+ {:fx/type :v-box
+ :alignment :center
+ :children (vec (apply merge [units-points-label-widget] unit-points-list-widget))}})
diff --git a/src/votann/util.clj b/src/votann/util.clj
new file mode 100644
index 0000000..2706a58
--- /dev/null
+++ b/src/votann/util.clj
@@ -0,0 +1,48 @@
+(ns votann.util
+ (:require [votann.codex :refer [kin-models kin-enhancements]]
+ [cljfx.lifecycle :as fx.lifecycle]
+ [cljfx.component :as fx.component]
+ [clojure.string :as string]))
+
+(def get-models
+ (vec (for [model kin-models]
+ (:name model))))
+
+(def get-units
+ (->> (concat kin-models kin-enhancements)
+ (map #(for [unit (:units %)]
+ {:name (str (:name %) " " (:count unit))
+ :points (:points unit)}))
+ (apply concat)
+ vec))
+
+(defn get-resource-path [file]
+ (.toExternalForm (clojure.java.io/resource file)))
+
+(comment get-local-path)
+
+(defn unit-file-name [unit]
+ (string/lower-case (string/replace unit " " "-")))
+
+(defn remove-by-index [data index]
+ (vec (concat (subvec data 0 index)
+ (subvec data (inc index)))))
+
+(def ext-recreate-on-key-changed
+ "Extension lifecycle that recreates its component when lifecycle's key is changed
+
+ Supported keys:
+ - `:key` (required) - a value that determines if returned component should be recreated
+ - `:desc` (required) - a component description with additional lifecycle semantics"
+ (reify fx.lifecycle/Lifecycle
+ (create [_ {:keys [key desc]} opts]
+ (with-meta {:key key
+ :child (fx.lifecycle/create fx.lifecycle/dynamic desc opts)}
+ {`fx.component/instance #(-> % :child fx.component/instance)}))
+ (advance [this component {:keys [key desc] :as this-desc} opts]
+ (if (= (:key component) key)
+ (update component :child #(fx.lifecycle/advance fx.lifecycle/dynamic % desc opts))
+ (do (fx.lifecycle/delete this component opts)
+ (fx.lifecycle/create this this-desc opts))))
+ (delete [_ component opts]
+ (fx.lifecycle/delete fx.lifecycle/dynamic (:child component) opts))))