From 2944bc4d1d7b60bafd48b6fb8b5728528c47c07a Mon Sep 17 00:00:00 2001 From: Devine Lu Linvega Date: Fri, 2 Aug 2019 16:40:30 +0900 Subject: [PATCH] Added kinetic bones?! --- README.md | 16 ++-- desktop/sources/scripts/commander.js | 8 +- desktop/sources/scripts/library.js | 134 +++++++++++++-------------- desktop/sources/scripts/ronin.js | 28 +++--- desktop/sources/scripts/surface.js | 20 ++-- examples/basics/gradients.lisp | 1 + examples/basics/theme.lisp | 29 ++++++ examples/misc/theme.lisp | 37 -------- 8 files changed, 131 insertions(+), 142 deletions(-) create mode 100644 examples/basics/theme.lisp delete mode 100644 examples/misc/theme.lisp diff --git a/README.md b/README.md index 1061450..087395c 100644 --- a/README.md +++ b/README.md @@ -38,20 +38,21 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i ## Library +- `(import path shape ~alpha)` Imports a graphic file with format. +- `(export path ~format ~quality)` Exports a graphic file with format. +- `(open path ~ratio)` Imports a graphic file and resizes the frame. +- `(exit ~force)` Exits Ronin. - `(pos ~x ~y)` Returns a position shape. +- `(line ax ay bx by)` Returns a line shape. - `(size w h)` Returns a size shape. - `(rect x y w h)` Returns a rect shape. - `(circle cx cy r)` Returns a circle shape. - `(ellipse cx cy rx ry)` Returns a ellipse shape. -- `(line ax ay bx by)` Returns a line shape. +- `(arc cx cy r sa ea)` Returns an arc shape. - `(poly ...pos)` Returns a poly shape. - `(text x y p t ~a ~f)` Returns a text shape. - `(svg x y d)` Returns a svg shape. -- `(arc cx cy r sa ea)` Returns an arc shape. - `(color r g b ~a)` Returns a color object. -- `(import path shape ~alpha)` Imports a graphic file with format. -- `(export path ~format ~quality)` Exports a graphic file with format. -- `(open path ~ratio)` Imports a graphic file and resizes the frame. - `(frame)` Returns a rect of the frame. - `(resize ~w)` Resizes the canvas to target w and h, returns the rect. - `(rescale ~w ~h)` Rescales the canvas to target ratio of w and h, returns the rect. @@ -71,10 +72,9 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i - `(popTransform)` - `(stroke shape color ~thickness)` Strokes a shape. - `(fill ~rect)` Fills a shape. +- `(clear ~rect)` Clears a rect. - `(gradient line ~colors 'black'])` Defines a gradient color. - `(guide shape color)` Draws a shape on the guide layer. -- `(clear ~rect)` Clears a rect. -- `(theme variable ~el)` - `(pixels fn ~q ~rect)` - `(saturation pixel q)` Change the saturation of pixels. - `(contrast pixel q)` Change the contrast of pixels. @@ -137,7 +137,6 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i - `(filepath ~path)` Returns the path of a file. - `(dirname ~path)` Returns the name of a folder. - `(filename ~path)` Returns the name of a file. -- `(exit ~force)` Exits Ronin. - `(offset a b)` Offsets pos a with pos b, returns a. - `(distance a b)` Get distance between positions. - `(echo ...args)` Print arguments to interface. @@ -147,6 +146,7 @@ Ronin helpers are keywords that facilitates adding coordinates from the canvas i - `(on event f)` Triggers on event. - `(test name a b)` - `(benchmark fn)` Logs time taken to execute a function. +- `(theme)` Get theme values. diff --git a/desktop/sources/scripts/commander.js b/desktop/sources/scripts/commander.js index 791ae1e..9f2867d 100644 --- a/desktop/sources/scripts/commander.js +++ b/desktop/sources/scripts/commander.js @@ -159,6 +159,10 @@ function Commander (ronin) { this.cache = this.cache.replace('$view', `(view $rect $rect)`) } else if (word === 'poly') { this.cache = this.cache.replace('$poly', `(poly $pos+)`) + } else if (word === 'move') { + this.cache = this.cache.replace('$move', `(transform:move $wh)`) + } else if (word === 'rotate') { + this.cache = this.cache.replace('$rotate', `(transform:rotate $a)`) } if (shape[word]) { @@ -183,7 +187,7 @@ function Commander (ronin) { if (word === 'line') { return `(line ${shape.a.x} ${shape.a.y} ${shape.b.x} ${shape.b.y})` } if (word === 'circle') { return `(circle ${shape.cx} ${shape.cy} ${shape.r})` } if (word === 'arc') { return `(arc ${shape.cx} ${shape.cy} ${shape.r} ${shape.sa} ${shape.ea})` } - if (word === 'x' || word === 'y' || word === 'xy' || word === 'wh') { return `${shape}` } + if (word === 'x' || word === 'y' || word === 'xy' || word === 'wh' || word === 'a') { return `${shape}` } return '' } @@ -264,7 +268,7 @@ function Commander (ronin) { // Splash this.splash = `; welcome to ronin -; v2.26 +; v2.28 (clear) (def logo-path "M60,60 L195,60 A45,45 0 0,1 240,105 A45,45 0 0,1 195,150 L60,150 M195,150 A45,45 0 0,1 240,195 L240,240 ") (stroke diff --git a/desktop/sources/scripts/library.js b/desktop/sources/scripts/library.js index a98ef5c..de4d768 100644 --- a/desktop/sources/scripts/library.js +++ b/desktop/sources/scripts/library.js @@ -3,12 +3,40 @@ function Library (ronin) { // Composition: Design programs to be connected to other programs. // Parsimony: Write a big program only when it is clear by demonstration that nothing else will do. + // IO + + this.import = async (path, shape, alpha = 1) => { // Imports a graphic file with format. + const img = new Image() + img.src = path + return ronin.surface.draw(img, shape, alpha) + } + + this.export = (path, format = 'image/png', quality = 1.0) => { // Exports a graphic file with format. + if (!path) { console.warn('Missing export path'); return path } + const dataUrl = ronin.surface.el.toDataURL(path.indexOf('.jpg') > -1 ? 'image/jpeg' : path.indexOf('.png') > -1 ? 'image/png' : format, quality) + const data = dataUrl.replace(/^data:image\/png;base64,/, '').replace(/^data:image\/jpeg;base64,/, '') + fs.writeFileSync(path, data, 'base64') + return path + } + + this.open = async (path, ratio = 1) => { // Imports a graphic file and resizes the frame. + return ronin.surface.open(path, ratio) + } + + this.exit = (force = false) => { // Exits Ronin. + ronin.source.quit(force) + } + // Shapes this.pos = (x = 0, y = 0) => { // Returns a position shape. return { x, y } } + this.line = (ax, ay, bx, by) => { // Returns a line shape. + return { a: this.pos(ax, ay), b: this.pos(bx, by) } + } + this.size = (w, h) => { // Returns a size shape. return { w, h } } @@ -25,8 +53,8 @@ function Library (ronin) { return { cx, cy, rx, ry } } - this.line = (ax, ay, bx, by) => { // Returns a line shape. - return { a: this.pos(ax, ay), b: this.pos(bx, by) } + this.arc = (cx, cy, r, sa, ea) => { // Returns an arc shape. + return { cx, cy, r, sa, ea } } this.poly = (...pos) => { // Returns a poly shape. @@ -41,35 +69,11 @@ function Library (ronin) { return { x, y, d } } - this.arc = (cx, cy, r, sa, ea) => { // Returns an arc shape. - return { cx, cy, r, sa, ea } - } - this.color = (r, g, b, a = 1) => { // Returns a color object. const hex = '#' + ('0' + parseInt(r, 10).toString(16)).slice(-2) + ('0' + parseInt(g, 10).toString(16)).slice(-2) + ('0' + parseInt(b, 10).toString(16)).slice(-2) return { r, g, b, a, hex, toString: () => { return `rgba(${r},${g},${b},${a})` }, 0: r, 1: g, 2: b, 3: a, f: [r / 255, g / 255, b / 255, a] } } - // - - this.import = async (path, shape, alpha = 1) => { // Imports a graphic file with format. - const img = new Image() - img.src = path - return ronin.surface.draw(img, shape, alpha) - } - - this.export = (path, format = 'image/png', quality = 1.0) => { // Exports a graphic file with format. - if (!path) { console.warn('Missing export path'); return path } - const dataUrl = ronin.surface.el.toDataURL(path.indexOf('.jpg') > -1 ? 'image/jpeg' : path.indexOf('.png') > -1 ? 'image/png' : format, quality) - const data = dataUrl.replace(/^data:image\/png;base64,/, '').replace(/^data:image\/jpeg;base64,/, '') - fs.writeFileSync(path, data, 'base64') - return path - } - - this.open = async (path, ratio = 1) => { // Imports a graphic file and resizes the frame. - return ronin.surface.open(path, ratio) - } - // Frame this.frame = () => { // Returns a rect of the frame. @@ -141,37 +145,28 @@ function Library (ronin) { // Transforms - this.move = (x, y) => { - ronin.surface.context.translate(x, y) - } - - this.rotate = (angle) => { - ronin.surface.context.rotate(angle) - } - - this.scale = (w, h) => { - ronin.surface.context.scale(w, h === undefined ? w : h) - } - - this.transform = (a, b, c, d, e, f) => { - // a:hscale b:hskew c:vskew d:vscale e:hmove f:vmove - ronin.surface.context.transform(a, b, c, d, e, f) - } - - this.setTransform = (a, b, c, d, e, f) => { - ronin.surface.context.setTransform(a, b, c, d, e, f) - } - - this.resetTransform = () => { - ronin.surface.context.resetTransform() - } - - this.pushTransform = () => { - ronin.surface.context.save() - } - - this.popTransform = () => { - ronin.surface.context.restore() + this.transform = { + push: () => { ronin.surface.context.save() }, + pop: () => { ronin.surface.context.restore() }, + reset: () => { + ronin.surface.context.resetTransform() + ronin.surface.guide.resetTransform() + }, + move: (x, y) => { + ronin.surface.context.translate(x, y) + this.guide(this.line(0, 0, x, y)) + ronin.surface.guide.translate(x, y) + }, + scale: (w, h) => { + ronin.surface.context.scale(w, h === undefined ? w : h) + this.guide(this.rect(0, 0, 50 * w, 50 * h)) + ronin.surface.guide.scale(w, h === undefined ? w : h) + }, + rotate: (a) => { + ronin.surface.context.rotate(a) + this.guide(this.arc(0, 0, 50, 0, a)) + ronin.surface.guide.rotate(a) + } } // Actions @@ -186,6 +181,12 @@ function Library (ronin) { return rect } + this.clear = (rect = this.frame()) => { // Clears a rect. + ronin.surface.clearGuide(rect) + ronin.surface.clear(rect) + return rect + } + this.gradient = (line, colors = ['white', 'black']) => { // Defines a gradient color. const gradient = ronin.surface.context.createLinearGradient(line.a.x, line.a.y, line.b.x, line.b.y) colors.forEach((color, i) => { @@ -199,17 +200,6 @@ function Library (ronin) { return shape } - this.clear = (rect = this.frame()) => { // Clears a rect. - ronin.surface.clearGuide(rect) - ronin.surface.clear(rect) - return rect - } - - this.theme = (variable, el = document.documentElement) => { - // ex. (theme "f_main") -> :root { --f_main: "#fff" } - return getComputedStyle(el).getPropertyValue(`--${variable}`) - } - // Pixels this.pixels = async (fn, q = 1, rect = this.frame()) => { @@ -541,10 +531,6 @@ function Library (ronin) { return require('path').parse(path).name } - this.exit = (force = false) => { // Exits Ronin. - ronin.source.quit(force) - } - this.offset = (a, b) => { // Offsets pos a with pos b, returns a. a.x += b.x a.y += b.y @@ -592,4 +578,8 @@ function Library (ronin) { console.log(`time taken: ${Date.now() - start}ms`) return result } + + // Accessors + + this.theme = ronin.theme.active // Get theme values. } diff --git a/desktop/sources/scripts/ronin.js b/desktop/sources/scripts/ronin.js index 44c8cc3..40e1e91 100644 --- a/desktop/sources/scripts/ronin.js +++ b/desktop/sources/scripts/ronin.js @@ -146,31 +146,33 @@ function Ronin () { const y = position.y const xy = x + ' ' + y const pos = { x, y } - const rect = { - x: this.mouseOrigin.x, - y: this.mouseOrigin.y, - w: this.mouseOrigin.x ? pos.x - this.mouseOrigin.x : 0, - h: this.mouseOrigin.y ? pos.y - this.mouseOrigin.y : 0 - } - const wh = rect.w + ' ' + rect.h const line = { a: { x: this.mouseOrigin.x, y: this.mouseOrigin.y }, b: { x: pos.x, y: pos.y } } + const size = { w: line.a.x ? pos.x - line.a.x : 0, h: line.a.y ? pos.y - line.a.y : 0 } + const rect = { + x: line.a.x, + y: line.a.y, + w: size.w, + h: size.h + } + const wh = rect.w + ' ' + rect.h const d = Math.sqrt(((line.a.x - line.b.x) * (line.a.x - line.b.x)) + ((line.a.y - line.b.y) * (line.a.y - line.b.y))) + const a = Math.atan2(pos.y - line.a.y, pos.x - line.a.x) const circle = { - cx: this.mouseOrigin.x, - cy: this.mouseOrigin.y, + cx: line.a.x, + cy: line.a.y, r: d.toFixed(2) } const arc = { - cx: this.mouseOrigin.x, - cy: this.mouseOrigin.y, + cx: line.a.x, + cy: line.a.y, r: d.toFixed(2), sa: 0, - ea: Math.atan2(position.y - this.mouseOrigin.y, position.x - this.mouseOrigin.x).toFixed(2) + ea: a.toFixed(2) } - return { x, y, xy, wh, d, line, rect, pos, circle, arc, type, 'is-down': type !== 'mouse-up' ? true : null } + return { x, y, xy, wh, d, a, line, rect, pos, size, circle, arc, type, 'is-down': type !== 'mouse-up' ? true : null } } // Zoom diff --git a/desktop/sources/scripts/surface.js b/desktop/sources/scripts/surface.js index 68213c4..64f7355 100644 --- a/desktop/sources/scripts/surface.js +++ b/desktop/sources/scripts/surface.js @@ -217,7 +217,7 @@ function Surface (ronin) { } } - this.resize = function (size, fit = false) { + this.resize = (size, fit = false) => { const frame = this.getFrame() if (frame.w === size.w && frame.h === size.h) { return } console.log('Surface', `Resize: ${size.w}x${size.h}`) @@ -234,10 +234,6 @@ function Surface (ronin) { } } - this.getFrame = function () { - return { x: 0, y: 0, w: this.el.width, h: this.el.height, t: 'rect', c: this.el.width / 2, m: this.el.height / 2 } - } - this.fitWindow = function (size) { const win = require('electron').remote.getCurrentWindow() const pad = { w: ronin.commander.isVisible === true ? 400 : 60, h: 60 } @@ -245,12 +241,16 @@ function Surface (ronin) { win.setSize(Math.floor((size.w / this.ratio) + pad.w), Math.floor((size.h / this.ratio) + pad.h), true) } - this.maximize = function () { + this.maximize = () => { this.resize(this.bounds()) } - this.bounds = function () { - return { x: 0, y: 0, w: ((window.innerWidth - 60) * this.ratio), h: ((window.innerHeight - 60) * this.ratio), t: 'rect' } + this.bounds = () => { + return { x: 0, y: 0, w: ((window.innerWidth - 60) * this.ratio), h: ((window.innerHeight - 60) * this.ratio) } + } + + this.getFrame = () => { + return { x: 0, y: 0, w: this.el.width, h: this.el.height, c: this.el.width / 2, m: this.el.height / 2 } } this.onResize = function () { @@ -326,10 +326,10 @@ function Surface (ronin) { return shape && !isNaN(shape.x) && !isNaN(shape.y) && shape.p && shape.t && shape.f && shape.a } function isLine (shape) { - return shape.a && shape.b && !isNaN(shape.a.x) && !isNaN(shape.a.y) && !isNaN(shape.b.x) && !isNaN(shape.b.y) + return shape && shape.a && shape.b && !isNaN(shape.a.x) && !isNaN(shape.a.y) && !isNaN(shape.b.x) && !isNaN(shape.b.y) } function isPoly (shape) { - return shape[0] && shape[1] && !isNaN(shape[0].x) && !isNaN(shape[0].y) && !isNaN(shape[1].x) && !isNaN(shape[1].y) + return shape && shape[0] && shape[1] && !isNaN(shape[0].x) && !isNaN(shape[0].y) && !isNaN(shape[1].x) && !isNaN(shape[1].y) } function fitRect (image, container) { diff --git a/examples/basics/gradients.lisp b/examples/basics/gradients.lisp index c71cf3d..b2beeea 100644 --- a/examples/basics/gradients.lisp +++ b/examples/basics/gradients.lisp @@ -1,6 +1,7 @@ ; gradients (clear) ; +(def frame-rect (frame)) (def radius (frame-rect:m)) ; diff --git a/examples/basics/theme.lisp b/examples/basics/theme.lisp new file mode 100644 index 0000000..686b22c --- /dev/null +++ b/examples/basics/theme.lisp @@ -0,0 +1,29 @@ +; display color from the theme. +; ex: theme:f_high +(clear) +(fill + (frame) theme:background) +(def color-box + (div + (:h + (frame)) 10)) +(defn print-value + (item id) + ( + (def box-y + (add + (mul id color-box) + (div color-box 2))) + (fill + (circle color-box box-y + (div color-box 2)) item) + (fill + (text 140 box-y 30 id) "white") + (fill + (text 200 box-y 30 + (of + (keys theme) id)) "white") + (fill + (text 400 box-y 30 item) "white"))) +(map + (values theme) print-value) \ No newline at end of file diff --git a/examples/misc/theme.lisp b/examples/misc/theme.lisp deleted file mode 100644 index 1aa5fce..0000000 --- a/examples/misc/theme.lisp +++ /dev/null @@ -1,37 +0,0 @@ -; theme -; reads color from the theme. -(clear) -(def col - (λ - (i) - (of - ( - (theme "f_high") - (theme "f_med") - (theme "f_low") - (theme "f_inv") - (theme "b_high") - (theme "b_med") - (theme "b_low") - (theme "b_inv")) - (mod i 8)))) -(def rec - (λ - (v i) - (if - (gt v 0) - ( - (fill - (circle - (add - (div - frame-rect:w 1.6) - (mul 1.5 v)) - (mul 10 v) - (mul v - (div v 5))) - (col i)) - (rec - (sub v 3) - (add i 1)))))) -(rec 40 0) \ No newline at end of file