diff options
-rw-r--r-- | ui/Root.js | 7 | ||||
-rw-r--r-- | ui/form/Form.js | 12 | ||||
-rw-r--r-- | ui/form/ListScrollForm.js | 4 | ||||
-rw-r--r-- | ui/tools/FilePickerForm.js | 88 | ||||
-rw-r--r-- | ui/tools/OpenFileDialog.js | 110 |
5 files changed, 214 insertions, 7 deletions
diff --git a/ui/Root.js b/ui/Root.js index 22c2c97..d306a41 100644 --- a/ui/Root.js +++ b/ui/Root.js @@ -90,4 +90,11 @@ module.exports = class Root extends DisplayElement { this.cursorMoved() } + + isChildOrSelfSelected(el) { + if (!this.selected) return false + if (this.selected === el) return true + if (this.selected.directAncestors.includes(el)) return true + return false + } } diff --git a/ui/form/Form.js b/ui/form/Form.js index 708de1f..ce064aa 100644 --- a/ui/form/Form.js +++ b/ui/form/Form.js @@ -80,15 +80,17 @@ module.exports = class Form extends FocusElement { this.updateSelectedElement() } - firstInput() { + firstInput(selectForm = true) { this.curIndex = 0 - this.updateSelectedElement() + if (selectForm || ( + this.root.isChildOrSelfSelected && this.root.isChildOrSelfSelected(this) + )) { + this.updateSelectedElement() + } } focused() { - if (this.root.select) { - this.root.select(this.inputs[this.curIndex]) - } + this.updateSelectedElement() } } diff --git a/ui/form/ListScrollForm.js b/ui/form/ListScrollForm.js index daa640a..a06efda 100644 --- a/ui/form/ListScrollForm.js +++ b/ui/form/ListScrollForm.js @@ -106,10 +106,10 @@ module.exports = class ListScrollForm extends Form { this.fixLayout() } - firstInput() { + firstInput(...args) { this.scrollItems = 0 - super.firstInput() + super.firstInput(...args) } getItemPos(item) { diff --git a/ui/tools/FilePickerForm.js b/ui/tools/FilePickerForm.js new file mode 100644 index 0000000..51d59a9 --- /dev/null +++ b/ui/tools/FilePickerForm.js @@ -0,0 +1,88 @@ +const fs = require('fs') +const util = require('util') +const path = require('path') + +const readdir = util.promisify(fs.readdir) +const stat = util.promisify(fs.stat) +const naturalSort = require('node-natural-sort') + +const Button = require('../form/Button') +const ListScrollForm = require('../form/ListScrollForm') + +module.exports = class FilePickerForm extends ListScrollForm { + fillItems(dirPath) { + this.inputs = [] + this.children = [] + + const button = new Button('..Loading..') + this.addInput(button) + this.firstInput(false) + + readdir(dirPath).then( + async items => { + this.removeInput(button) + + const processedItems = await Promise.all(items.map(item => { + const itemPath = path.resolve(dirPath, item) + return stat(itemPath).then(s => { + return { + path: itemPath, + label: item + (s.isDirectory() ? '/' : ''), + isDirectory: s.isDirectory() + } + }) + })) + + const sort = naturalSort({ + properties: { + caseSensitive: false + } + }) + processedItems.sort((a, b) => { + if (a.isDirectory === b.isDirectory) { + return sort(a.label, b.label) + } else { + if (a.isDirectory) { + return -1 + } else { + return +1 + } + } + }) + + processedItems.unshift({ + path: path.resolve(dirPath, '..'), + label: '../', + isDirectory: true + }) + + let y = 0 + for (const item of processedItems) { + const itemButton = new Button(item.label) + itemButton.y = y + y++ + this.addInput(itemButton) + + itemButton.on('pressed', () => { + if (item.isDirectory) { + this.emit('browsingDirectory', item.path) + this.fillItems(item.path) + } else { + this.emit('selected', item.path) + } + }) + } + + console.log('HALLO.', false) + this.firstInput(false) + this.fixLayout() + }, + () => { + button.text = 'Failed to read path! (Cancel)' + button.on('pressed', () => { + this.emit('canceled') + }) + }) + } +} + diff --git a/ui/tools/OpenFileDialog.js b/ui/tools/OpenFileDialog.js new file mode 100644 index 0000000..92bd4af --- /dev/null +++ b/ui/tools/OpenFileDialog.js @@ -0,0 +1,110 @@ +const path = require('path') + +const Button = require('../form/Button') +const Dialog = require('../Dialog') +const FilePickerForm = require('./FilePickerForm') +const Form = require('../form/Form') +const Label = require('../Label') +const TextInput = require('../form/TextInput') + +module.exports = class OpenFileDialog extends Dialog { + constructor() { + super() + + this.visible = false + + this.form = new Form() + this.pane.addChild(this.form) + + this.filePathLabel = new Label('Enter file path:') + this.filePathInput = new TextInput() + this.openButton = new Button('Open') + this.cancelButton = new Button('Cancel') + + this.filePickerForm = new FilePickerForm() + this.filePickerForm.captureTab = false + + this.form.addChild(this.filePathLabel) + this.form.addInput(this.filePathInput) + this.form.addInput(this.filePickerForm) + this.form.addInput(this.openButton) + this.form.addInput(this.cancelButton) + + this._resolve = null + + this.openButton.on('pressed', () => { + this._resolve(this.filePathInput.value) + }) + + this.filePathInput.on('value', () => { + this._resolve(this.filePathInput.value) + }) + + { + const cb = append => p => { + this.filePathInput.setValue((path.relative(__dirname, p) || '.') + append) + } + + this.filePickerForm.on('selected', cb('')) + this.filePickerForm.on('browsingDirectory', cb('/')) + } + + this.cancelButton.on('pressed', () => { + this._resolve(null) + }) + + const dir = (this.lastFilePath + ? path.relative(__dirname, path.dirname(this.lastFilePath)) + '/' + : './') + + this.filePathInput.setValue(dir) + this.filePickerForm.fillItems(dir) + } + + fixLayout() { + super.fixLayout() + + this.pane.w = Math.min(this.contentW, 40) + this.pane.h = Math.min(this.contentH, 20) + this.pane.centerInParent() + + this.form.w = this.pane.contentW + this.form.h = this.pane.contentH + + this.filePathLabel.x = 0 + this.filePathLabel.y = 0 + + this.filePathInput.x = this.filePathLabel.right + 2 + this.filePathInput.y = this.filePathLabel.y + this.filePathInput.w = this.form.contentW - this.filePathInput.x + + this.filePickerForm.x = 0 + this.filePickerForm.y = this.filePathInput.y + 2 + this.filePickerForm.w = this.form.contentW + this.filePickerForm.h = this.form.contentH - this.filePickerForm.y - 2 + + this.openButton.x = 0 + this.openButton.y = this.form.contentH - 1 + + this.cancelButton.x = this.openButton.right + 2 + this.cancelButton.y = this.openButton.y + } + + focused() { + this.form.firstInput() + } + + go() { + this.visible = true + this.root.select(this) + + return new Promise(resolve => { + this._resolve = resolve + }).then(filePath => { + this.visible = false + this.lastFilePath = filePath + return filePath + }) + } +} + |