     (-start [_ actions]
       (conj actions (new-line-action)))
     (-move [_ action x y]
-      (let [points (next-point (:points action) x y)]
+      (let [points (next-point (:points action) x y snap)]
         (assoc action :points points)))
     (-end [_ actions]
       actions)))
 
+(def square-tool
+  (reify
+    ITool
+    (-start [_ actions]
+      (conj actions (new-square-action)))
+    (-move [_ action x y]
+      (let [points (next-point (:points action) x y identity)]
+        (assoc action :points points)))
+    (-end [_ actions]
+      actions)))
+
+(def circle-tool
+  (reify
+    ITool
+    (-start [_ actions]
+      (conj actions (new-circle-action)))
+    (-move [_ action x y]
+      (if-let [o (:origin action)]
+        (assoc action :radius (distance o [x y]))
+        (assoc action :origin [x y])))
+    (-end [_ actions]
+      actions)))
+
 (def all-tools
   {:line straight-line-tool
-   :freehand freehand-tool})
+   :freehand freehand-tool
+   :square square-tool
+   :circle circle-tool})
 
 (defn current-tool []
   (all-tools (get-in @app-state [:tools :current])))

    (.stroke context)
    (.restore context)))

(defn new-line-action []
  (->LineAction [] (merge {:lineCap "round"
                           :lineJoin "round"} (get-in @app-state [:tools :props]))))
(def freehand-tool
  (reify
    ITool

      (adjust-points m points))
    points))

(defn next-point [points x y f]
  (if (zero? (count points))
    [[x y]]
    (let [points (assoc points 1 [x y])]
      (f points))))

(def straight-line-tool
  (reify
