diff --git a/main.js b/main.js index 032212d..1233cf3 100644 --- a/main.js +++ b/main.js @@ -29,8 +29,10 @@ app.win = null; app.on('ready', () => { - app.win = new BrowserWindow({width: 930, height: 540, minWidth: 930, minHeight: 540, backgroundColor:"#000", frame:false, autoHideMenuBar: true, icon: __dirname + '/icon.ico'}) + app.win = new BrowserWindow({width: 900, height: 540, minWidth: 900, minHeight: 540, backgroundColor:"#000", frame:false, autoHideMenuBar: true, icon: __dirname + '/icon.ico'}) + app.win.toggleDevTools(); + app.win.loadURL(`file://${__dirname}/sources/index.html`); app.win.on('closed', () => { diff --git a/sources/index.html b/sources/index.html index 7960c86..64830f5 100644 --- a/sources/index.html +++ b/sources/index.html @@ -1,6 +1,7 @@ + @@ -18,11 +19,14 @@ + + + - + diff --git a/sources/links/main.css b/sources/links/main.css index 62ca598..ead02cf 100644 --- a/sources/links/main.css +++ b/sources/links/main.css @@ -3,25 +3,27 @@ body { margin:0px; padding:0px; overflow:hidden; font-family:"input_mono_medium" yu { display:block; } +:root { --background: "#222"; --f_high: "#fff";--f_med: "#777";--f_low: "#444";--f_inv: "#000";--b_high: "#000";--b_med: "#affec7";--b_low: "#000";--b_inv: "#affec7"; } + #cursor { z-index:899; position: absolute; } #guide { z-index:810;position: absolute; transition: opacity 250ms; opacity: 0} #above { z-index:800; position: absolute; } #below { z-index:799; position: absolute; } -#ronin { background-color:#ccc; height: 100vh; width:100vw; background-image:url(../media/assets/grid.svg);} +#ronin { background:var(--b_low); height: 100vh; width:100vw; background-image:url(../media/assets/grid.svg);} #commander, #hint { width: 100vw;line-height: 40px;-webkit-user-select: none;-webkit-app-region: drag;z-index: 900;height: 40px; font-size:11px; cursor: default;} #commander { z-index: 9000;background: #000;bottom: 0px;position: relative; transition: top 150ms; } -#commander input { background: transparent;width: calc(100vw - 30px);display: block;line-height: 40px;font-size: 11px;color: white; margin-left:20px; z-index: 9000;position: relative; } +#commander input { background: transparent;width: calc(100vw - 30px);display: block;line-height: 40px;font-size: 11px;color: var(--f_low); margin-left:20px; z-index: 9000;position: relative; } #commander.hidden { top:-40px; } #commander.visible { top:0px; } -#hint { color:#666; padding-left:20px; position: absolute;top: 0px;} -#hint b { font-family: 'input_mono_regular'; color:#999;} +#hint { color:var(--f_med); padding-left:20px; position: absolute;top: 0px;} +#hint b { font-family: 'input_mono_regular'; color:var(--f_low);} #hint i { font-style: italic; } -#hint .autocomplete { background:white; color:black; } +#hint .autocomplete { background:var(--b_high); color:var(--f_low); } -#commander #cursor_hint { position: fixed;top: 0px;right: 10px;color: white; padding: 0px 10px; color:#555; font-size:11px; padding-right: 40px; } +#commander #cursor_hint { position: fixed;top: 0px;right: 10px;color: var(--f_med); padding: 0px 10px; font-size:11px; padding-right: 40px; } #commander #cursor_hint .mode {} #commander #cursor_hint .zoom::after { content:"*"; } #commander #cursor_hint .pick::after { content:"#"; } @@ -30,10 +32,10 @@ yu { display:block; } #commander #cursor_hint .drag::after { content:"/"; } #commander #cursor_hint .target_above::after { content:"^"; } #commander #cursor_hint .target_below::after { content:"v"; } -#commander icon.brush { display: block;width: 40px;height: 40px;position: absolute;top: 0px;right: 0px; } -#commander icon.brush icon.primary { display: block;width: 6px;height: 20px;border-radius: 20px;border-style: solid;top: 10px;left: 16px;position: absolute;background: pink;transform: rotate(23deg);} -#commander icon.brush icon.secondary { display: block;width: 6px;height: 20px;border-radius: 20px;border-style: solid;top: 10px;left: 24px;position: absolute;background: pink;transform: rotate(23deg);} -surface { display: block; background:pink; position: absolute; top:0px; transition: all 100ms; } +#commander #swatch { background:red; display: block; position:fixed; top:10px; right:10px; width:20px; height:20px; border-radius:10px; } +#commander #swatch .primary { background: red;display: block;position: fixed;top: 20px;right: 20px;width: 20px;height: 20px;border-radius: 10px; } + +surface { display: block; background:var(--background); position: absolute; top:0px; transition: all 100ms; } surface .layer { border-radius: 4px; overflow: hidden; width:100%; height:100%;} diff --git a/sources/scripts/controller.js b/sources/scripts/controller.js index e11fb58..0da4682 100644 --- a/sources/scripts/controller.js +++ b/sources/scripts/controller.js @@ -17,7 +17,14 @@ function Controller() console.log(`${mode}/${cat}/${label} <${accelerator}>`); } - this.set = function(mode) + this.add_role = function(mode,cat,label) + { + if(!this.menu[mode]){ this.menu[mode] = {}; } + if(!this.menu[mode][cat]){ this.menu[mode][cat] = {}; } + this.menu[mode][cat][label] = {role:label}; + } + + this.set = function(mode = "default") { this.mode = mode; this.commit(); @@ -31,7 +38,12 @@ function Controller() var submenu = []; for(name in m[cat]){ var option = m[cat][name]; - submenu.push({label:name,accelerator:option.accelerator,click:option.fn}) + if(option.role){ + submenu.push({role:option.role}) + } + else{ + submenu.push({label:name,accelerator:option.accelerator,click:option.fn}) + } } f.push({label:cat,submenu:submenu}); } @@ -76,7 +88,7 @@ function Controller() for(cat in menu){ var options = menu[cat]; for(id in options.submenu){ - var option = options.submenu[id]; + var option = options.submenu[id]; if(option.role){ continue; } acc.basic = (option.accelerator.toLowerCase() == key.toLowerCase()) ? option.label.toUpperCase().replace("TOGGLE ","").substr(0,8).trim() : acc.basic; acc.ctrl = (option.accelerator.toLowerCase() == ("CmdOrCtrl+"+key).toLowerCase()) ? option.label.toUpperCase().replace("TOGGLE ","").substr(0,8).trim() : acc.ctrl; } @@ -97,7 +109,7 @@ function Controller() {x:540, y:0, width:60, height:60, name:"9"}, {x:600, y:0, width:60, height:60, name:"0"}, {x:660, y:0, width:60, height:60, name:"-"}, - {x:720, y:0, width:60, height:60, name:"+"}, + {x:720, y:0, width:60, height:60, name:"plus"}, {x:780, y:0, width:120, height:60, name:"backspace"}, {x:0, y:60, width:90, height:60, name:"tab"}, {x:90, y:60, width:60, height:60, name:"q"}, diff --git a/sources/scripts/core/commander.js b/sources/scripts/core/commander.js index 2666755..a43bea1 100644 --- a/sources/scripts/core/commander.js +++ b/sources/scripts/core/commander.js @@ -120,7 +120,6 @@ function Commander() this.activate = function() { - ronin.cursor.update(); ronin.commander.autocomplete(); ronin.commander.show(); setTimeout(()=>{ronin.commander.focus},100) diff --git a/sources/scripts/core/cursor.js b/sources/scripts/core/cursor.js index 63553c8..22b7342 100644 --- a/sources/scripts/core/cursor.js +++ b/sources/scripts/core/cursor.js @@ -5,13 +5,11 @@ function Cursor(rune) this.query = null; this.mode = "vertex"; - this.color = "#000000" - this.color_alt = "#ffffff" this.size = 2; this.pos = {x:0,y:0}; this.target = null; - + this.mouse_pos = function(e) { var pos = {x:e.clientX,y:e.clientY}; @@ -30,25 +28,17 @@ function Cursor(rune) e.preventDefault(); var pos = ronin.cursor.mouse_pos(e); - ronin.cursor.pos = pos; ronin.commander.blur(); - // Color Pick - if(ronin.commander.input_el.value == "~"){ - ronin.brush.methods.pick.run({x:pos.x,y:pos.y}) - ronin.commander.input_el.value = ""; - ronin.commander.update(); - return; - } - ronin.cursor.line.origin = {x:pos.x,y:pos.y}; ronin.cursor.line.from = {x:pos.x,y:pos.y}; // Save original query ronin.cursor.query = ronin.commander.input_el.value; - if(ronin.commander.active_module()){ } + if(ronin.commander.active_module()){ /* DO NOTHING */ } + else if(e.shiftKey){ /* DO NOTHING */ } else if(e.altKey && e.shiftKey){ ronin.brush.methods.pick.run(pos); } else if(e.altKey){ ronin.brush.erase(ronin.cursor.line); } else{ ronin.brush.stroke(ronin.cursor.line); } @@ -69,13 +59,12 @@ function Cursor(rune) ronin.cursor.line.to = {x:pos.x,y:pos.y}; - if(e.altKey && e.shiftKey){ ronin.brush.methods.pick.run(pos); } + if(ronin.commander.active_module()){ ronin.cursor.inject_query(); } + else if(e.altKey && e.shiftKey){ ronin.brush.methods.pick.run(pos); } else if(e.shiftKey){ ronin.cursor.drag(ronin.cursor.line); } else if(e.altKey){ ronin.brush.erase(ronin.cursor.line); } else{ ronin.brush.stroke(ronin.cursor.line); } - ronin.cursor.inject_query(); - ronin.cursor.line.from = {x:pos.x,y:pos.y}; } @@ -84,7 +73,6 @@ function Cursor(rune) e.preventDefault(); var pos = ronin.cursor.mouse_pos(e); - ronin.cursor.pos = pos; ronin.cursor.line.destination = {x:pos.x,y:pos.y}; @@ -110,14 +98,6 @@ function Cursor(rune) ronin.cursor.target.context().putImageData(data, offset.x * -2, offset.y * -2); } - this.swap_colors = function() - { - var c = this.color_alt - this.color_alt = this.color; - this.color = c; - ronin.commander.update(); - } - this.swap_layer = function() { this.target = this.target.name == "above" ? ronin.layers.below : ronin.layers.above; @@ -195,9 +175,9 @@ function Cursor(rune) } return ` - ${ronin.frame.width}x${ronin.frame.height} + ${ronin.frame.width}X${ronin.frame.height} ${(ronin.frame.width/ronin.frame.height).toFixed(2)}:1 ${ronin.cursor.size}${ronin.frame.zoom.scale} - `; + ${ronin.brush.swatch.hint()}`; } function distance_between(a,b) diff --git a/sources/scripts/core/keyboard.js b/sources/scripts/core/keyboard.js index 23aaa83..e5d9812 100644 --- a/sources/scripts/core/keyboard.js +++ b/sources/scripts/core/keyboard.js @@ -11,7 +11,7 @@ function Keyboard() { ronin.keyboard.is_down[e.key] = true; - if(e.key == "Enter"){ + if(ronin.commander.is_focused() && e.key == "Enter"){ e.preventDefault(); ronin.commander.validate(); } diff --git a/sources/scripts/core/swatch.js b/sources/scripts/core/swatch.js new file mode 100644 index 0000000..44d7c99 --- /dev/null +++ b/sources/scripts/core/swatch.js @@ -0,0 +1,31 @@ +function Swatch() +{ + this.index = 0; + this.colors = []; + + this.start = function() + { + this.update(); + } + + this.update = function() + { + this.colors = [ronin.theme.active.f_high,ronin.theme.active.f_med,ronin.theme.active.f_low]; + } + + this.swap = function() + { + this.index += 1; + } + + this.color = function(offset = 0) + { + return this.colors[(this.index + offset) % this.colors.length]; + } + + this.hint = function() + { + this.update(); + return ``; + } +} \ No newline at end of file diff --git a/sources/scripts/modules/brush.js b/sources/scripts/modules/brush.js index 23be80f..aa1ee73 100644 --- a/sources/scripts/modules/brush.js +++ b/sources/scripts/modules/brush.js @@ -3,6 +3,7 @@ function Brush() Module.call(this,"brush"); this.speed = 0; + this.swatch = new Swatch(); this.pointers = [ new Pointer({offset:{x:0,y:0}}) @@ -92,11 +93,6 @@ function Pointer(options) return ronin.brush.thickness(line); } - this.color = function(line) - { - return ronin.cursor.color; - } - this.stroke = function(line,erase = false) { var ctx = ronin.cursor.target.context(); @@ -116,7 +112,7 @@ function Pointer(options) ctx.lineTo((line.to.x * 2) + this.options.offset.x,(line.to.y * 2) + this.options.offset.y); ctx.lineCap="round"; ctx.lineWidth = this.thickness(line); - ctx.strokeStyle = ronin.cursor.color; + ctx.strokeStyle = ronin.brush.swatch.color(); ctx.stroke(); ctx.closePath(); } diff --git a/sources/scripts/modules/frame.js b/sources/scripts/modules/frame.js index 69749f4..8b33ae3 100644 --- a/sources/scripts/modules/frame.js +++ b/sources/scripts/modules/frame.js @@ -8,13 +8,12 @@ function Frame() this.install = function() { ronin.el.appendChild(this.el); - this.el.style.backgroundColor = this.background; } this.methods.new = new Method("new","WxH","New Canvas",function(q){ ronin.layers.above.clear(); ronin.layers.below.clear(); - ronin.frame.resize_to({width:930,height:540}); + ronin.frame.resize_to({width:900,height:540}); }); this.width = 400; diff --git a/sources/scripts/ronin.js b/sources/scripts/ronin.js index 9ccd9cf..4c43db2 100644 --- a/sources/scripts/ronin.js +++ b/sources/scripts/ronin.js @@ -3,6 +3,7 @@ function Ronin() this.el = document.createElement('yu'); this.el.id = "ronin"; + this.theme = new Theme(); this.controller = new Controller(); this.keyboard = new Keyboard(); @@ -41,6 +42,9 @@ function Ronin() this.install = function() { + this.theme.start(); + this.brush.swatch.start(); + document.body.appendChild(this.el); this.frame.width = window.innerWidth; @@ -80,13 +84,21 @@ function Ronin() this.controller.add("default","File","Save Images(PNGs)",() => { ronin.io.methods.save.run(); },"CmdOrCtrl+S"); this.controller.add("default","File","Export Image(JPG)",() => { ronin.io.methods.export.run(); },"CmdOrCtrl+E"); + this.controller.add_role("default","Edit","undo"); + this.controller.add_role("default","Edit","redo"); + this.controller.add_role("default","Edit","cut"); + this.controller.add_role("default","Edit","copy"); + this.controller.add_role("default","Edit","paste"); + this.controller.add_role("default","Edit","delete"); + this.controller.add_role("default","Edit","selectall"); + this.controller.add("default","Layers","Above Layer",() => { ronin.cursor.select_layer(ronin.layers.above); },"c"); this.controller.add("default","Layers","Below Layer",() => { ronin.cursor.select_layer(ronin.layers.below); },"z"); - this.controller.add("default","Layers","Toggle Layer",() => { ronin.cursor.swap_layer(); },"x"); + this.controller.add("default","Layers","Toggle Layer",() => { ronin.cursor.brush.swatch.swap(); },"x"); this.controller.add("default","Brush","Inc Size",() => { ronin.brush.mod_size(1); },"]"); this.controller.add("default","Brush","Dec Size",() => { ronin.brush.mod_size(-1); },"["); - this.controller.add("default","Brush","Toggle Color",() => { ronin.cursor.swap_colors(); },"x"); + this.controller.add("default","Brush","Toggle Color",() => { ronin.brush.swatch.swap(); },"x"); this.controller.add("default","Commander","Show",() => { ronin.commander.activate(); },"`"); this.controller.add("default","Commander","Hide",() => { ronin.commander.deactivate(); },"Escape"); @@ -115,11 +127,16 @@ function Ronin() this.guide.update(); this.commander.update(); - this.frame.resize_to({width:930,height:540}); + this.frame.resize_to({width:900,height:540}); this.load(); } + this.reset = function() + { + this.theme.reset(); + } + this.load = function(content = this.default()) { diff --git a/sources/scripts/theme.js b/sources/scripts/theme.js new file mode 100644 index 0000000..c355259 --- /dev/null +++ b/sources/scripts/theme.js @@ -0,0 +1,80 @@ +function Theme() +{ + var app = this; + + this.el = document.createElement("style"); + this.el.type = 'text/css'; + this.default = { background: "#222", f_high: "#fff", f_med: "#777", f_low: "#444", f_inv: "#000", b_high: "#000", b_med: "#affec7", b_low: "#000", b_inv: "#affec7" } + this.active = this.default; + + this.start = function() + { + this.load(localStorage.theme ? localStorage.theme : this.default); + window.addEventListener('dragover',this.drag_enter); + window.addEventListener('drop', this.drag); + document.head.appendChild(this.el) + } + + this.load = function(t) + { + var theme = is_json(t) ? JSON.parse(t) : t; + + if(!theme.background){ return; } + + var css = ` + :root { + --background: ${theme.background}; + --f_high: ${theme.f_high}; + --f_med: ${theme.f_med}; + --f_low: ${theme.f_low}; + --f_inv: ${theme.f_inv}; + --b_high: ${theme.b_high}; + --b_med: ${theme.b_med}; + --b_low: ${theme.b_low}; + --b_inv: ${theme.b_inv}; + }`; + + this.active = theme; + this.el.textContent = css; + localStorage.setItem("theme", JSON.stringify(theme)); + } + + this.reset = function() + { + this.load(this.default); + } + + this.drag_enter = function(e) + { + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; + } + + this.drag = function(e) + { + e.preventDefault(); + e.stopPropagation(); + + var file = e.dataTransfer.files[0]; + + if(!file.name || !file.name.indexOf(".thm") < 0){ console.log("Theme","Not a theme"); return; } + + var reader = new FileReader(); + reader.onload = function(e){ + app.load(e.target.result); + }; + reader.readAsText(file); + } + + function is_json(text) + { + try{ + JSON.parse(text); + return true; + } + catch (error){ + return false; + } + } +} \ No newline at end of file