diff --git a/desktop/main.js b/desktop/main.js index 4888cf5..9835437 100644 --- a/desktop/main.js +++ b/desktop/main.js @@ -11,8 +11,8 @@ app.on('ready', () => { app.win = new BrowserWindow({ width: 780, height: 392, - minWidth: 320, - minHeight: 320, + minWidth: 380, + minHeight: 380, backgroundColor: '#000', icon: path.join(__dirname, { darwin: 'icon.icns', linux: 'icon.png', win32: 'icon.ico' }[process.platform] || 'icon.ico'), resizable: true, diff --git a/desktop/sources/index.html b/desktop/sources/index.html index eca0f5a..985ea54 100644 --- a/desktop/sources/index.html +++ b/desktop/sources/index.html @@ -4,6 +4,7 @@ + @@ -22,11 +23,16 @@ const ronin = new Ronin(); ronin.controller = new Controller(); ronin.controller.add("default","*","About",() => { require('electron').shell.openExternal('https://github.com/hundredrabbits/Dotgrid'); },"CmdOrCtrl+,"); - ronin.controller.add("default","*","Fullscreen",() => { app.toggleFullscreen(); },"CmdOrCtrl+Enter"); - ronin.controller.add("default","*","Hide",() => { app.toggleVisible(); },"CmdOrCtrl+H"); - ronin.controller.add("default","*","Inspect",() => { app.inspect(); },"CmdOrCtrl+."); - ronin.controller.add("default","*","Reset",() => { dotgrid.reset(); dotgrid.theme.reset(); },"CmdOrCtrl+Backspace"); - ronin.controller.add("default","*","Quit",() => { app.exit(); },"CmdOrCtrl+Q"); + ronin.controller.add("default","*","Fullscreen",() => { app.toggleFullscreen() },"CmdOrCtrl+Enter"); + ronin.controller.add("default","*","Hide",() => { app.toggleVisible() },"CmdOrCtrl+H"); + ronin.controller.add("default","*","Inspect",() => { app.inspect() },"CmdOrCtrl+."); + ronin.controller.add("default","*","Reset",() => { dotgrid.reset(); dotgrid.theme.reset() },"CmdOrCtrl+Backspace"); + ronin.controller.add("default","*","Quit",() => { ronin.source.quit() },"CmdOrCtrl+Q"); + ronin.controller.add("default","File","New",() => { ronin.source.new() },"CmdOrCtrl+N") + ronin.controller.add("default","File","Save",() => { ronin.source.save() },"CmdOrCtrl+S") + ronin.controller.add("default","File","Save As",() => { ronin.source.saveAs() },"CmdOrCtrl+Shift+S") + ronin.controller.add("default","File","Open",() => { ronin.source.open() },"CmdOrCtrl+O") + ronin.controller.add("default","File","Revert",() => { ronin.source.revert() },"CmdOrCtrl+W") ronin.controller.addRole('default', 'Edit', 'undo') ronin.controller.addRole('default', 'Edit', 'redo') ronin.controller.addRole('default', 'Edit', 'cut') diff --git a/desktop/sources/links/main.css b/desktop/sources/links/main.css index b4a9e15..90d2a02 100644 --- a/desktop/sources/links/main.css +++ b/desktop/sources/links/main.css @@ -5,7 +5,7 @@ body { margin:0px; padding:0px; overflow:hidden; font-family:"input_mono_regular #ronin { height: calc(100vh - 60px); width:calc(100vw - 60px); -webkit-app-region: drag; padding: 30px;overflow: hidden; } #ronin #wrapper { overflow: hidden; position: relative; } #ronin #wrapper #commander { z-index: 9000; position: relative; width: 300px; height: calc(100vh - 60px); border-right: 1px solid #333; -webkit-app-region: no-drag; padding-right: 30px; transition: margin-left 250ms;} -#ronin #wrapper #commander textarea { background: none; width: 100%; height: calc(100vh - 75px); resize: none; font-size: 12px;color: white; } +#ronin #wrapper #commander textarea { background: none; width: 100%; height: calc(100vh - 80px); resize: none; font-size: 12px;color: white; line-height: 15px; padding-right: 15px} #ronin #wrapper #commander div#status { color:#555; position: absolute; bottom: 0px; } #ronin #wrapper #commander.hidden { margin-left:-331px; } diff --git a/desktop/sources/scripts/commander.js b/desktop/sources/scripts/commander.js index f1d8505..5602da3 100644 --- a/desktop/sources/scripts/commander.js +++ b/desktop/sources/scripts/commander.js @@ -11,9 +11,6 @@ function Commander (ronin) { host.appendChild(this.el) this._input.addEventListener('input', this.onInput) - - window.addEventListener('dragover', this.drag) - window.addEventListener('drop', this.drop) } this.start = function () { @@ -24,8 +21,9 @@ function Commander (ronin) { } this.run = function (txt = this._input.value) { - if (txt.indexOf('$') > -1) { console.log('Contains $'); return } + if (txt.indexOf('$') > -1) { ronin.log('Present: $'); return } console.log('========') + ronin.surface.maximize() const inter = new Lisp(txt, ronin.library) inter.toPixels() } @@ -126,12 +124,10 @@ function Commander (ronin) { // Display this.show = function () { - console.log('show') this.el.className = '' } this.hide = function () { - console.log('hide') this.el.className = 'hidden' } @@ -142,30 +138,4 @@ function Commander (ronin) { this.hide() } } - - // Events - - this.drag = (e) => { - e.stopPropagation() - e.preventDefault() - e.dataTransfer.dropEffect = 'copy' - } - - this.drop = (e) => { - e.preventDefault() - e.stopPropagation() - const file = e.dataTransfer.files[0] - if (!file || !file.name) { console.warn('File', 'Not a valid file.'); return } - if (file.name.indexOf('.lisp') > -1) { - const reader = new FileReader() - reader.onload = (e) => { - this.load(e.target.result) - this.show() - } - reader.readAsText(file) - } else if (file.path) { - this.injectPath(file.path) - this.show() - } - } } diff --git a/desktop/sources/scripts/ronin.js b/desktop/sources/scripts/ronin.js index 708519f..90e7700 100644 --- a/desktop/sources/scripts/ronin.js +++ b/desktop/sources/scripts/ronin.js @@ -15,6 +15,8 @@ function Ronin () { this.el.id = 'ronin' this.theme = new Theme(defaultTheme) + + this.source = new Source(this) this.commander = new Commander(this) this.surface = new Surface(this) this.library = new Library(this) @@ -28,10 +30,14 @@ function Ronin () { this.el.appendChild(this._wrapper) host.appendChild(this.el) this.theme.install() + + window.addEventListener('dragover', this.drag) + window.addEventListener('drop', this.drop) } this.start = function () { this.theme.start() + this.source.start() this.commander.start() this.surface.start() @@ -49,4 +55,26 @@ function Ronin () { this.load = function (content = this.default()) { } + // Events + + this.drag = (e) => { + e.stopPropagation() + e.preventDefault() + e.dataTransfer.dropEffect = 'copy' + } + + this.drop = (e) => { + e.preventDefault() + e.stopPropagation() + const file = e.dataTransfer.files[0] + if (!file || !file.name) { console.warn('File', 'Not a valid file.'); return } + const path = file.path ? file.path : file.name + if (path.indexOf('.lisp') > -1) { + this.source.read(path) + this.commander.show() + } else if (file.path) { + this.commander.injectPath(file.path) + this.commander.show() + } + } } diff --git a/desktop/sources/scripts/source.js b/desktop/sources/scripts/source.js new file mode 100644 index 0000000..f45e74e --- /dev/null +++ b/desktop/sources/scripts/source.js @@ -0,0 +1,156 @@ +'use strict' + +function Source (ronin) { + const fs = require('fs') + const path = require('path') + const { dialog, app } = require('electron').remote + + this.path = null + + this.start = function () { + this.new() + } + + this.new = function () { + console.log('Source', 'Make a new file..') + this.path = null + } + + this.open = function () { + console.log('Source', 'Open a file..') + let paths = dialog.showOpenDialog(app.win, { properties: ['openFile'], filters: [{ name: 'Ronin Lisp', extensions: ['lisp'] }] }) + if (!paths) { console.log('Nothing to load'); return } + this.read(paths[0]) + } + + this.save = function (quitAfter = false) { + console.log('Source', 'Save..', this.path) + if (this.path) { + this.write(this.path, this.generate(), quitAfter) + } else { + this.saveAs(quitAfter) + } + } + + this.saveAs = function (quitAfter = false) { + console.log('Source', 'Save a file as..') + dialog.showSaveDialog((loc) => { + if (loc === undefined) { return } + if (loc.indexOf('.lisp') < 0) { loc += '.lisp' } + this.write(loc, this.generate(), quitAfter) + this.path = loc + }) + } + + this.revert = function () { + if (!this.path) { return } + console.log('Source', 'Revert a file..') + this.read(this.path) + } + + // I/O + + this.write = function (loc, data = this.generate(), quitAfter = false) { + console.log('Source', 'Writing ' + loc) + fs.writeFileSync(loc, data) + if (quitAfter === true) { + app.exit() + } + } + + this.read = function (loc = this.path) { + if (!loc) { return } + if (!fs.existsSync(loc)) { console.warn('Source', 'File does not exist: ' + loc); return } + console.log('Source', 'Reading ' + loc) + this.path = loc + this.load(fs.readFileSync(this.path, 'utf8')) + } + + this.run = function () { + ronin.commander.run() + } + + this.load = function (data) { + ronin.commander._input.value = data + } + + this.quit = function () { + if (this.hasChanges() === true) { + this.verify() + } else { + app.exit() + } + } + + this.verify = function () { + let response = dialog.showMessageBox(app.win, { + type: 'question', + buttons: ['Cancel', 'Discard', 'Save'], + title: 'Confirm', + message: 'Unsaved data will be lost. Would you like to save your changes before leaving?', + icon: path.join(__dirname, '../icon.png') + }) + if (response === 2) { + this.save(true) + } else if (response === 1) { + app.exit() + } + } + + this.hasChanges = function () { + console.log('Source', 'Looking for changes..') + if (!this.path) { + console.log('Source', 'File is unsaved..') + if (ronin.commander._input.value.length() > 2) { + console.log('Source', `File is not empty.`) + return true + } + } else { + if (fs.existsSync(this.path)) { + console.log('Source', 'Comparing with last saved copy..') + const diff = isDifferent(fs.readFileSync(this.path, 'utf8'), this.generate()) + if (diff === true) { + console.log('Source', 'File has been changed.') + return true + } + } else { + console.log('Source', 'File does not exist.') + return true + } + } + } + + // Converters + + this.generate = function (str = ronin.commander._input.value) { + return `${str}` + } + + this.locate = function (name) { + if (!this.path) { return } + const loc = path.join(this.folder(), name) + return fs.existsSync(loc) ? loc : null + } + + // Etc + + this.name = function () { + return this.path ? path.basename(this.path, '.lisp') : null + } + + this.folder = function () { + return this.path ? path.dirname(this.path) : null + } + + this.toString = function () { + return this.path ? this.name() : 'unsaved' + } + + function isDifferent (a, b) { + return a.trim() !== b.trim() + } + + function clean (s) { + return s + } +} diff --git a/desktop/sources/scripts/surface.js b/desktop/sources/scripts/surface.js index f8db945..40ea8ab 100644 --- a/desktop/sources/scripts/surface.js +++ b/desktop/sources/scripts/surface.js @@ -119,6 +119,8 @@ function Surface (ronin) { if (ronin.commander._input.value === '') { this.maximize() } + const f = this.getFrame() + ronin.log(`resize ${f.w}x${f.h}`) } this.getFrame = function () {