diff --git a/README.md b/README.md index 7bb8ee9..1045a83 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,22 @@ Ronin is a simple open-source graphic design tool. +## Cursor +- `$` replace with **Pos**. +- `$+shift` replace with **Rect**. + ## Modules ## brush Missing documentation. +### Methods + ### Settings - `size`, default 4 - `color`, default #000 - `opacity`, default 1 -### Methods - ### Ports - `speed->` **(0/50)** The cursor speed. - `distance->` **(0/9999)** The cursor distance. @@ -26,26 +30,28 @@ Missing documentation. Manager for the canvas size +### Methods +- `resize:WxH` Resize canvas to size. +- `rescale:0.5` Rescale canvas to float. +- `crop:X,Y|WxH` Crop canvas to rect. +- `clear:` Erase entire canvas +- `fill:#f00` Fill entire canvas with color + ### Settings - `width`, default 930 - `height`, default 540 -### Methods -- `resize:`, no details. -- `rescale:`, no details. -- `crop:`, no details. - ### Ports ## line Drawing lines. Tween expects something in the `$&$>>$&$` format. -### Settings - ### Methods -- `tween:`, no details. -- `stroke:`, no details. +- `stroke:x1,y1&x2,y2` Stroke positions. +- `tween:tween:$&$>>$&$ step->thickness` Stroke lines between strokes. + +### Settings ### Ports - `step->` **(0/100)** The tween line index.. @@ -55,43 +61,43 @@ Drawing lines. Tween expects something in the `$&$>>$&$` format. File import/export tools. +### Methods +- `load:browser` Press enter to open the file browser. +- `draw:X,Y|WxH` Draw the loaded image pixels. +- `save:name` Export canvas. + ### Settings - `anchor`, default [object Object] -### Methods -- `import:`, no details. -- `load:`, no details. -- `save:`, no details. - ### Ports ## path Trace lines and to draw shapes. +### Methods +- `stroke:x,y&` +- `fill:x,y&` + ### Settings - `thickness`, default 30 - `color`, default black - `cap`, default square -### Methods -- `stroke:`, no details. -- `fill:`, no details. - ### Ports ## magnet Cursor magnetisation settings, changes are reflected on the grid layer. +### Methods +- `lock:undefined` undefined +- `unlock:undefined` undefined + ### Settings - `size`, default 0 - `step`, default 4 -### Methods -- `lock:`, no details. -- `unlock:`, no details. - ### Ports diff --git a/TODO.md b/TODO.md index 9c9cdb2..5157316 100644 --- a/TODO.md +++ b/TODO.md @@ -1,25 +1,31 @@ ## TODOs ### Commander -- Parse multicommand with `;` + +### Module +- Move preview into method. ### Path - Origin marker -- Export SVG value ### IO - Import `.rin` files - Export `.rin` file +- Negative positions ### Type - Implement +### Transform +- Implement + ### Docs - Add shortcuts - Write tutorial ### Brush - Finish Port draft +- Color picker ### Line - Preview support \ No newline at end of file diff --git a/main.js b/main.js index c869ae3..2b47d9a 100644 --- a/main.js +++ b/main.js @@ -56,7 +56,7 @@ app.on('ready', () => is_shown = true; }) // Open the DevTools. - win.webContents.openDevTools() + // win.webContents.openDevTools() }) app.on('window-all-closed', () => diff --git a/sources/index.html b/sources/index.html index 4d89bad..f1933b2 100644 --- a/sources/index.html +++ b/sources/index.html @@ -8,6 +8,7 @@ + diff --git a/sources/scripts/core/commander.js b/sources/scripts/core/commander.js index 0156e5e..4a9a8d9 100644 --- a/sources/scripts/core/commander.js +++ b/sources/scripts/core/commander.js @@ -14,8 +14,10 @@ function Commander() this.validate = function(q = ronin.commander.query()) { + console.info(q.string) if(!ronin.modules[q.module]){ console.log("Unknown module",q.module); return; } if(q.raw.indexOf("$") > -1){ console.log("Variables present"); return; } + if(q.raw.indexOf(";") > -1){ this.validate_multi(q); return; } // Update settings for(setting_id in q.settings){ @@ -38,6 +40,32 @@ function Commander() ronin.guide.update(); } + this.queue = []; + + this.validate_multi = function(q) + { + var queue = []; + var queries = q.string.split(";"); + + for(id in queries){ + var q = new Query(queries[id].trim()); + queue.push(q); + } + this.queue = queue; + this.run_queue(); + } + + this.run_queue = function() + { + if(ronin.commander.queue.length == 0){ return; } + + ronin.commander.validate(ronin.commander.queue[0]); + + ronin.commander.queue = ronin.commander.queue.splice(1,ronin.commander.queue.length-1) + + setTimeout(ronin.commander.run_queue,250); + } + this.update = function() { var q = ronin.commander.query(); diff --git a/sources/scripts/core/docs.js b/sources/scripts/core/docs.js index 0417b38..656949d 100644 --- a/sources/scripts/core/docs.js +++ b/sources/scripts/core/docs.js @@ -5,16 +5,24 @@ function Docs() var html = ""; html += this.print_intro(); + html += "## Cursor\n"; + html += "- `$` replace with **Pos**.\n"; + html += "- `$+shift` replace with **Rect**.\n\n"; + html += "## Modules\n"; html += this.print_modules(ronin.modules); - html += this.print_license(); - dialog.showSaveDialog((fileName) => { - if (fileName === undefined){ return; } - fs.writeFile(fileName, html, (err) => { - if(err){ alert("An error ocurred creating the file "+ err.message); return; } - }); + // dialog.showSaveDialog((fileName) => { + // if (fileName === undefined){ return; } + // console.log(fileName) + // fs.writeFile(fileName, html, (err) => { + // if(err){ alert("An error ocurred creating the file "+ err.message); return; } + // }); + // }); + + fs.writeFile("/Users/VillaMoirai/Github/HundredRabbits/Ronin/README.md", html, (err) => { + if(err){ alert("An error ocurred creating the file "+ err.message); return; } }); return html; @@ -36,13 +44,24 @@ function Docs() var module = modules[module_name]; html += "## "+module_name+"\n\n"; html += module.docs+"\n\n"; - html += this.print_settings(module.settings)+"\n"; html += this.print_methods(module.methods)+"\n"; + html += this.print_settings(module.settings)+"\n"; html += this.print_ports(module.ports)+"\n"; } return html+"\n"; } + this.print_methods = function(methods) + { + var html = "### Methods\n"; + + for(method_name in methods){ + var method = methods[method_name]; + html += "- `"+method_name+":"+method.params+"` "+method.info+"\n"; + } + return html; + } + this.print_settings = function(settings) { var html = "### Settings\n"; @@ -54,16 +73,6 @@ function Docs() return html; } - this.print_methods = function(methods) - { - var html = "### Methods\n"; - - for(method_name in methods){ - var method_val = methods[method_name]; - html += "- `"+method_name+":`, no details.\n"; - } - return html; - } this.print_ports = function(ports) { diff --git a/sources/scripts/core/method.js b/sources/scripts/core/method.js index e2598a6..af85f5b 100644 --- a/sources/scripts/core/method.js +++ b/sources/scripts/core/method.js @@ -1,10 +1,9 @@ -function Method(name,params,info = "Missing documentation") +function Method(name,params,info = "Missing documentation",f) { this.name = name; this.params = params; this.info = info; - - this.run = null; + this.run = f; this.hint = function() { @@ -13,6 +12,6 @@ function Method(name,params,info = "Missing documentation") this.docs = function() { - return "["+this.params+"] "+this.info+""; + return ""+this.params+" "+this.info+""; } } \ No newline at end of file diff --git a/sources/scripts/core/query.js b/sources/scripts/core/query.js index bfcf5aa..92062bb 100644 --- a/sources/scripts/core/query.js +++ b/sources/scripts/core/query.js @@ -1,5 +1,6 @@ function Query(query_str = "") { + this.string = query_str; this.module = query_str.split(" ")[0]; var parts = query_str.split(" ").splice(1); this.raw = parts.join(" "); diff --git a/sources/scripts/modules/filter.js b/sources/scripts/modules/filter.js new file mode 100644 index 0000000..767e64e --- /dev/null +++ b/sources/scripts/modules/filter.js @@ -0,0 +1,18 @@ +function Filter() +{ + Module.call(this,"filter","Pixel filter"); + + this.methods.balance = new Method("balance","#ff0033","Filter color balance.",function(q){ + var color = {r:1,g:0,b:0.5}; + var originalData = ronin.render.context().getImageData(0, 0, ronin.frame.settings.width*2, ronin.frame.settings.height*2); + var data = originalData.data; + + for(var i = 0; i < data.length; i += 4) { + data[i] = data[i] * (color.r + 0.5); + data[i + 1] = data[i + 1] * (color.g + 0.5); + data[i + 2] = data[i + 2] * (color.b + 0.5); + } + + ronin.preview.context().putImageData(originalData, 0, 0); + }); +} \ No newline at end of file diff --git a/sources/scripts/modules/frame.js b/sources/scripts/modules/frame.js index 313912a..33cd173 100644 --- a/sources/scripts/modules/frame.js +++ b/sources/scripts/modules/frame.js @@ -4,24 +4,14 @@ function Frame() this.settings = {width:400,height:400}; - this.methods = {}; - - this.methods.resize = new Method("resize","WxH"); - - this.methods.resize.run = function(q) - { + this.methods.resize = new Method("resize","WxH","Resize canvas to size.",function(q){ var data = ronin.render.select(0,0,ronin.frame.settings.width,ronin.frame.settings.height); - ronin.render.clear(); ronin.frame.resize_to(q); ronin.render.context().putImageData(data, 0, 0); - } + }); - this.methods.rescale = new Method("rescale","X,Y|WxH"); - - this.methods.rescale.run = function(p) - { - // Create a canvas copy + this.methods.rescale = new Method("rescale","0.5","Rescale canvas to float.",function(p){ var copy_canvas = document.createElement("canvas"); copy_canvas.width = ronin.frame.settings.width * 2; copy_canvas.height = ronin.frame.settings.height * 2; @@ -30,33 +20,25 @@ function Frame() var new_size = {width:ronin.frame.settings.width * p,height:ronin.frame.settings.height * p}; - // Paste ronin.render.clear(); ronin.frame.resize_to(new_size); ronin.render.context().drawImage(copy_ctx.canvas,0,0,new_size.width * 2,new_size.height * 2); - } + }); - this.methods.crop = new Method("crop","X,Y|WxH"); - this.methods.crop.run = function(p) - { + this.methods.crop = new Method("crop","X,Y|WxH","Crop canvas to rect.",function(p){ var data = ronin.render.select(p.x,p.y,p.width,p.height); - ronin.render.clear(); ronin.frame.resize_to(p); ronin.render.context().putImageData(data, 0, 0); - } + }); - this.methods.clear = new Method("clear","X,Y|WxH"); - this.methods.clear.run = function(q) - { - ronin.render.fill("blue"); - } + this.methods.clear = new Method("clear","","Erase entire canvas",function(q){ + ronin.render.clear(); + }); - this.methods.fill = new Method("fill","X,Y|WxH"); - this.methods.fill.run = function(q) - { + this.methods.fill = new Method("fill","#f00","Fill entire canvas with color",function(q){ ronin.render.fill(q); - } + }); this.resize_to = function(size) { diff --git a/sources/scripts/modules/io.js b/sources/scripts/modules/io.js index 344f97e..f551024 100644 --- a/sources/scripts/modules/io.js +++ b/sources/scripts/modules/io.js @@ -1,17 +1,10 @@ function IO() { Module.call(this,"io","File import/export tools."); - - this.settings = {anchor:{x:0,y:0,width:200,height:200}}; - - this.methods = {}; this.image = null; - this.methods.load = new Method("load","browser","Press enter to open the file browser."); - - this.methods.load.run = function(q) - { + this.methods.load = new Method("load","browser","Press enter to open the file browser.",function(q){ var filepath = dialog.showOpenDialog({properties: ['openFile']}); if(!filepath){ console.log("Nothing to load"); return; } @@ -25,38 +18,17 @@ function IO() ronin.commander.inject("io draw:20,20|100x100"); } }); - } + }); - this.methods.draw = new Method("draw","X,Y|WxH","Draw the loaded image pixels."); - - this.methods.draw.run = function(q) - { + this.methods.draw = new Method("draw","X,Y|WxH","Draw the loaded image pixels.",function(q){ if(!ronin.io.image){ return; } ronin.io.draw_image(ronin.render.context(),ronin.io.image,ronin.commander.query().methods.draw); ronin.io.image = null; ronin.preview.clear(); - } + }); - this.methods.save = new Method("save","name"); - - this.methods.save.run = function(q) - { - // TODO - ronin.io.render(); - } - - this.preview = function(q) - { - ronin.preview.clear(); - - if(ronin.commander.query().methods.draw && this.image){ - this.draw_image(ronin.preview.context(),this.image,ronin.commander.query().methods.draw); - } - } - - this.render = function() - { + this.methods.save = new Method("save","name","Export canvas.",function(q){ var fs = require('fs'); var data = ronin.render.to_base64('jpg').replace(/^data:image\/\w+;base64,/, ""); var buf = new Buffer(data, 'base64'); @@ -65,54 +37,14 @@ function IO() if (fileName === undefined){ return; } fs.writeFile(fileName+'.jpg', buf); }); - } + }); - this.drag_over = function(e) + this.preview = function(q) { - e.stopPropagation(); - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; - } + ronin.preview.clear(); - this.drop = function(e) - { - e.stopPropagation(); - e.preventDefault(); - var files = e.dataTransfer.files; - var file = files[0]; - - if (!file.type.match(/image.*/)) { console.log("Not image"); return false; } - - var reader = new FileReader(); - - reader.onload = function(event) - { - ronin.io.inject(event.target.result); - } - reader.readAsDataURL(file); - } - - this.inject = function(data_url) - { - var img = new Image(); - img.src = data_url; - - var width = parseInt(img.naturalWidth * 0.5); - var height = parseInt(img.naturalHeight * 0.5); - - // if(height > 700){ - // width *= 0.5; - // height *= 0.5; - // } - // if(height > 1400){ - // width *= 0.25; - // height *= 0.25; - // } - - ronin.frame.methods.resize({width:parseInt(width),height:parseInt(height)}) - - img.onload = function() { - ronin.render.context().drawImage(img, 0,0,width * 2,height * 2); + if(ronin.commander.query().methods.draw && this.image){ + this.draw_image(ronin.preview.context(),this.image,ronin.commander.query().methods.draw); } } diff --git a/sources/scripts/modules/line.js b/sources/scripts/modules/line.js index 15a32be..6bef715 100644 --- a/sources/scripts/modules/line.js +++ b/sources/scripts/modules/line.js @@ -2,14 +2,14 @@ function Line() { Module.call(this,"line","Drawing lines. Tween expects something in the `$&$>>$&$` format."); - this.methods = {}; - - this.ports = {}; this.ports.step = new Port(this,"step",false,true,0,100,"The tween line index."); this.ports.thickness = new Port(this,"thickness",true,true,1,100,"The tween line thickness."); - this.methods.tween = function(q) // line tween:$&$>>$&$ step->thickness - { + this.methods.stroke = new Method("stroke","x1,y1&x2,y2","Stroke positions.",function(q){ + ronin.line.stroke_multi(q) + }) + + this.methods.tween = new Method("tween","tween:$&$>>$&$ step->thickness","Stroke lines between strokes.",function(q){ var from = q.from; var to = q.to; @@ -20,12 +20,7 @@ function Line() ronin.line.stroke_multi(new_positions); ronin.line.ports.step.write(ronin.line.ports.step.value+1); } - } - - this.methods.stroke = function(q) - { - ronin.line.stroke_multi(q) - } + }) this.preview = function(q) { diff --git a/sources/scripts/modules/magnet.js b/sources/scripts/modules/magnet.js index f7b1631..424d72b 100644 --- a/sources/scripts/modules/magnet.js +++ b/sources/scripts/modules/magnet.js @@ -4,21 +4,17 @@ function Magnet() this.settings = {size:0,step:4}; - this.methods.lock = function(q) - { + this.methods.lock = new Method("lock","10x10","Magnetize cursor",function(q){ var size = parseInt(q); - ronin.magnet.settings.size = size; - if(size < 5){ this.unlock(); return; } - + ronin.magnet.settings.size = size; ronin.grid.draw(size,ronin.magnet.settings.step); - } + }) - this.methods.unlock = function(q) - { + this.methods.unlock = new Method("unlock","","Release cursor",function(q){ ronin.magnet.settings.size = 0; ronin.grid.clear(); - } + }) this.filter = function(pos) { diff --git a/sources/scripts/modules/path.js b/sources/scripts/modules/path.js index d18bb4a..3f5af1a 100644 --- a/sources/scripts/modules/path.js +++ b/sources/scripts/modules/path.js @@ -4,9 +4,7 @@ function Path() this.settings = {thickness:30,color:"black",cap:"square"}; - this.methods.stroke = new Method("stroke","x,y&"); - this.methods.stroke.run = function(q) - { + this.methods.stroke = new Method("stroke","x,y&","",function(q){ ronin.preview.clear(); var path = ronin.path.create_path(q); @@ -19,11 +17,9 @@ function Path() ctx.strokeStyle = "black"; ctx.stroke(new Path2D(path)); ctx.closePath(); - } + }); - this.methods.fill = new Method("fill","x,y&"); - this.methods.fill.run = function(q) - { + this.methods.fill = new Method("fill","x,y&","",function(q){ ronin.preview.clear(); var path = ronin.path.create_path(q); @@ -36,7 +32,7 @@ function Path() ctx.fillStyle = "black"; ctx.fill(new Path2D(path)); ctx.closePath(); - } + }); this.preview = function(q) { diff --git a/sources/scripts/ronin.js b/sources/scripts/ronin.js index 4608c2b..a4fbbe7 100644 --- a/sources/scripts/ronin.js +++ b/sources/scripts/ronin.js @@ -20,6 +20,7 @@ function Ronin() this.line = new Line(); this.path = new Path(); this.magnet = new Magnet(); + this.filter = new Filter(); this.layers = { grid : this.grid, @@ -35,7 +36,8 @@ function Ronin() line : this.line, io : this.io, path : this.path, - magnet : this.magnet + magnet : this.magnet, + filter : this.filter }; this.install = function() @@ -74,11 +76,5 @@ function Ronin() this.cursor.update(); this.preview.update(); this.commander.update(); - - // this.commander.input_el.value = "io import:~/Desktop/test.png anchor=$"; - // this.commander.input_el.value = "path stroke:$+"; - - // this.commander.input_el.value = "magnet lock:"; - // this.commander.inject("line tween:$&$&$>>$&$&$ step->thickness"); } } \ No newline at end of file