diff --git a/project.clj b/project.clj index 0f8c5c1..5f96cf8 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,5 @@ (defproject hulkure "1.0.0-SNAPSHOT" :description "FIXME: write description" + :main hulkure.editor :dependencies [[org.clojure/clojure "1.4.0"] [org.clojure/data.json "0.2.0"]]) diff --git a/src/hulkure/board.clj b/src/hulkure/board.clj index 98d4f64..0fcbe44 100644 --- a/src/hulkure/board.clj +++ b/src/hulkure/board.clj @@ -1,6 +1,7 @@ (ns hulkure.board (:require [clojure.data.json :as json]) - (:use [hulkure.utils :only [filter-first]])) + (:use [hulkure.utils :only [filter-first + removev]])) (defn make-board [] {:fields [], ; contains fields. The keys :x and :y are handled like unique keys @@ -15,16 +16,30 @@ (defn- get-field-with-index [board x y] "returns [index field]" - (or (filter-first #(and (= x (% :x)) - (= y (% :y))) + (or (filter-first #(and (= x ((second %) :x)) + (= y ((second %) :y))) (map-indexed vector (board :fields))) [nil nil])) (defn- get-field-index [board x y] (first (get-field-with-index board x y))) -(defn get-field [board x y] - (last (get-field-with-index board x y))) +(defn get-field + ([board xy] + (get-field board (xy :x) (xy :y))) + ([board x y] + (last (get-field-with-index board x y)))) + +(defn remove-field + "remove field at coordinates x and y. Warning: does not handle figures at specified coordinates." + ([board xy] + (remove-field board (xy :x) (xy :y))) + ([board x y] + (let [[index field] (get-field-with-index board x y)] + (if index + (assoc board :fields (removev (board :fields) + index)) + board)))) (defn set-field [board field] "Update or add field if it does not exist" diff --git a/src/hulkure/editor.clj b/src/hulkure/editor.clj index 05a2f1a..0259a1f 100644 --- a/src/hulkure/editor.clj +++ b/src/hulkure/editor.clj @@ -1,27 +1,78 @@ (ns hulkure.editor + (:require [hulkure.board :as board]) (:import [javax.swing JFrame JPanel JMenuBar JMenu JMenuItem KeyStroke AbstractAction] [java.awt Graphics Color] - [java.awt.event KeyEvent ActionEvent ActionListener])) + [java.awt.event KeyEvent ActionEvent ActionListener MouseAdapter MouseEvent])) -(defn start-editor [] +(defn reset-board! [state] + (swap! state assoc :board (board/make-board))) + +(defn paint [#^Graphics this state g] + (.setColor g Color/BLACK) + (.fillRect g 0 0 (.getWidth this) (.getHeight this)) + (.setColor g Color/GRAY) + (dorun (map #(.fillRect g (inc (* 20 (% :x))) (inc (* 20 (% :y))) (- 20 2) (- 20 2)) + (get-in @state [:board :fields]))) + (when-let [mouse (@state :mouse-over)] + (do + (.setColor g Color/RED) + (.drawRect g (* 20 (mouse :x)) (* 20 (mouse :y)) 20 20)))) + +(defn translate-screen-to-board [x y] + {:x (int (/ x 20)) + :y (int (/ y 20))}) + +(defn make-mouse-adapter [state] + (proxy [MouseAdapter] [] + (mouseMoved [#^MouseEvent event] + (swap! state assoc :mouse-over (translate-screen-to-board(.getX event) (.getY event))) + (.repaint (@state :panel))) + (mouseClicked [#^MouseEvent event] + (let [coords (translate-screen-to-board (.getX event) (.getY event))] + (swap! state assoc :board (if (board/get-field (@state :board) coords) + (board/remove-field (@state :board) coords) + (board/set-field (@state :board) coords))) + (.repaint (@state :panel)))))) + +(defn make-content-pane [state] + (proxy [JPanel] [] + (paintComponent [#^Graphics g] + (paint this state g)))) + +(defn make-action-new [state] + (proxy [AbstractAction] ["New"] + (actionPerformed [e] + (reset-board! state) + (.repaint (@state :panel))))) + +(defn make-action-exit [] + (proxy [AbstractAction] ["Exit"] + (actionPerformed [e] + (System/exit 0)))) + +(defn start-editor [state] (let [frame (JFrame. "Editor") - actionListener (proxy [AbstractAction ActionListener] [] - (actionPerformed [e] - (prn e)))] + mouse-adapter (make-mouse-adapter state) + content-pane (make-content-pane state)] + (swap! state assoc :panel content-pane) (.setDefaultCloseOperation frame JFrame/DISPOSE_ON_CLOSE) - (.setContentPane frame (proxy [JPanel] [] - (paintComponent [#^Graphics g] - (.setColor g Color/BLACK) - (.fillRect g 0 0 (.getWidth this) (.getHeight this))))) + (.setContentPane frame content-pane) (.setJMenuBar frame (doto (JMenuBar.) - (.add (doto (JMenu. "File") - (.add (doto (JMenuItem. "New") - (.setAccelerator (KeyStroke/getKeyStroke KeyEvent/VK_N ActionEvent/CTRL_MASK)) - (.addActionListener actionListener))) - (.addSeparator) - (.add (doto (JMenuItem. "Exit") - (.setAccelerator (KeyStroke/getKeyStroke KeyEvent/VK_Q, ActionEvent/CTRL_MASK)) - (.addActionListener actionListener))))))) + (.add (doto (JMenu. "File") + (.add (doto (JMenuItem. (make-action-new state)) + (.setAccelerator (KeyStroke/getKeyStroke KeyEvent/VK_N ActionEvent/CTRL_MASK)))) + (.addSeparator) + (.add (doto (JMenuItem. (make-action-exit)) + (.setAccelerator (KeyStroke/getKeyStroke KeyEvent/VK_Q, ActionEvent/CTRL_MASK)))))))) + (.addMouseListener content-pane mouse-adapter) + (.addMouseMotionListener content-pane mouse-adapter) + (.addMouseWheelListener content-pane mouse-adapter) (.setSize frame 800 800) (.setVisible frame true) )) + + +(defn -main [& args] + (let [state (atom {})] + (reset-board! state) + (start-editor state))) diff --git a/src/hulkure/utils.clj b/src/hulkure/utils.clj index ab63b6e..4672a7f 100644 --- a/src/hulkure/utils.clj +++ b/src/hulkure/utils.clj @@ -1,4 +1,8 @@ (ns hulkure.utils) (defn filter-first [pred coll] - (first (filter pred coll))) \ No newline at end of file + (first (filter pred coll))) + +(defn removev [v index] + (vec (concat (subvec v 0 index) + (subvec v (inc index))))) \ No newline at end of file