;; This Source Code Form is subject to the terms of the Mozilla Public ;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; ;; Copyright (c) KALEIDOS INC (ns app.main.ui.cursors (:require [app.common.uri :as u] [clojure.core :as c] [clojure.java.io :as io] [cuerdas.core :as str])) (def cursor-folder "images/cursors") (def default-hotspot-x 12) (def default-hotspot-y 12) (def default-rotation 0) (def default-height 20) (defn parse-svg [svg-data] (-> svg-data ;; Remove the header (str/replace #"(?i)<\?xml[^\?]*\?>", "") ;; Remove comments (str/replace #"<\!\-\-(.*?(?=\-\->))\-\->" "") ;; Remove end of line (str/replace #"\r?\n|\r" " ") ;; Replace double quotes for single (str/replace #"\"" "'") ;; Remove the svg root tag (str/replace #"(?i)" "") ;; And the closing tag (str/replace #"(?i)<\/svg>" "") ;; Remove some defs that can be redundant (str/replace #"" "") ;; Unifies the spaces into single space (str/replace #"\s+" " ") ;; Remove spaces at the beginning of the svg (str/replace #"^\s+" "") ;; Remove spaces at the end (str/replace #"\s+$" ""))) (defn encode-svg-cursor [id rotation x y height] (let [svg-path (str cursor-folder "/" (name id) ".svg") data (-> svg-path io/resource slurp parse-svg) data (u/percent-encode data) data (if rotation (str/fmt "%3Cg transform='rotate(%s 8,8)'%3E%s%3C/g%3E" rotation data) data)] (str "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='20px' " "height='" height "px' %3E" data "%3C/svg%3E\") " x " " y ", auto"))) (defmacro cursor-ref "Creates a static cursor given its name, rotation and x/y hotspot" ([id] (encode-svg-cursor id default-rotation default-hotspot-x default-hotspot-y default-height)) ([id rotation] (encode-svg-cursor id rotation default-hotspot-x default-hotspot-y default-height)) ([id rotation x y] (encode-svg-cursor id rotation x y default-height)) ([id rotation x y height] (encode-svg-cursor id rotation x y height))) (defmacro cursor-fn "Creates a dynamic cursor that can be rotated in runtime" [id initial] (let [[cp1 cp2] (-> (encode-svg-cursor id "$$$" default-hotspot-x default-hotspot-y default-height) (str/split #"\$\$\$"))] `(fn [rot#] (str/concat ~cp1 (+ ~initial rot#) ~cp2)))) (defmacro collect-cursors [] (let [ns-info (:ns &env)] `(cljs.core/js-obj ~@(->> (:defs ns-info) (map val) (filter (fn [entry] (-> entry :meta :cursor))) (mapcat (fn [{:keys [name] :as entry}] [(-> name c/name str/camel str/capital) name]))))))