From e159d5fa9609bfa66809b7b097d52d8116b624de Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Sun, 8 Dec 2024 23:22:58 +0100 Subject: [PATCH 01/22] Implemented keyboard shortcuts. Signed-off-by: ubi de feo --- backend/ipc.js | 6 ++++ index.js | 48 ++++++++++++++++++++++++-- preload.js | 25 ++++++++++++-- ui/arduino/main.js | 6 +++- ui/arduino/store.js | 44 +++++++++++++++++++++++ ui/arduino/views/components/toolbar.js | 13 +++---- 6 files changed, 131 insertions(+), 11 deletions(-) diff --git a/backend/ipc.js b/backend/ipc.js index 8bace22..467cbff 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -129,9 +129,15 @@ module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { return response != opt.cancelId }) + ipcMain.handle('reload', (event, message = 'ciao, cane') => { + console.log('reload?') + win.webContents.send('reload', message) + }) + win.on('close', (event) => { console.log('BrowserWindow', 'close') event.preventDefault() win.webContents.send('check-before-close') }) + } diff --git a/index.js b/index.js index 57eba4c..dcf8def 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -const { app, BrowserWindow, ipcMain, dialog } = require('electron') +const { app, BrowserWindow, ipcMain, dialog, globalShortcut } = require('electron') const path = require('path') const fs = require('fs') @@ -57,4 +57,48 @@ function createWindow () { }) } -app.on('ready', createWindow) +function shortcutAction(key) { + win.webContents.send('shortcut-cmd', key); +} + +// Shortcuts +function registerShortcuts() { + globalShortcut.register('CommandOrControl+R', () => { + console.log('Running Program') + shortcutAction('r') + }) + globalShortcut.register('CommandOrControl+H', () => { + console.log('Stopping Program (Halt)') + shortcutAction('h') + }) + globalShortcut.register('CommandOrControl+S', () => { + console.log('Saving File') + shortcutAction('s') + }) + + globalShortcut.register('CommandOrControl+Shift+R', () => { + console.log('Resetting Board') + shortcutAction('R') + }) + globalShortcut.register('CommandOrControl+Shift+C', () => { + console.log('Connect to Board') + shortcutAction('C') + }) + globalShortcut.register('CommandOrControl+Shift+D', () => { + console.log('Disconnect from Board') + shortcutAction('D') + }) +} + +app.on('ready', () => { + createWindow() + registerShortcuts() + + win.on('focus', () => { + registerShortcuts() + }) + win.on('blur', () => { + globalShortcut.unregisterAll() + }) + +}) \ No newline at end of file diff --git a/preload.js b/preload.js index ddcb8aa..0ed2abb 100644 --- a/preload.js +++ b/preload.js @@ -3,6 +3,8 @@ const { contextBridge, ipcRenderer } = require('electron') const path = require('path') const MicroPython = require('micropython.js') +const { emit, platform } = require('process') +// const { platform } = requireprocess.platform const board = new MicroPython() board.chunk_size = 192 board.chunk_sleep = 200 @@ -155,12 +157,31 @@ const Window = { setWindowSize: (minWidth, minHeight) => { ipcRenderer.invoke('set-window-size', minWidth, minHeight) }, + anyShortcut: (callback, key) => { + ipcRenderer.on('shortcut-cmd', (event, k) => { + // Get the active element + const activeElement = document.activeElement; + // Check if the active element is the terminal + const isTerminalFocused = activeElement.classList.contains('xterm-helper-textarea'); + // Only trigger callback if terminal is not focused AND we're in editor view + if (!isTerminalFocused) { + console.log('shortcut-cmd-r executed') + callback(k); + } + }) + }, + + beforeClose: (callback) => ipcRenderer.on('check-before-close', callback), confirmClose: () => ipcRenderer.invoke('confirm-close'), isPackaged: () => ipcRenderer.invoke('is-packaged'), - openDialog: (opt) => ipcRenderer.invoke('open-dialog', opt) -} + openDialog: (opt) => ipcRenderer.invoke('open-dialog', opt), + getOS: () => platform, + isWindows: () => platform === 'win32', + isMac: () => platform === 'darwin', + isLinux: () => platform === 'linux' +} contextBridge.exposeInMainWorld('BridgeSerial', Serial) contextBridge.exposeInMainWorld('BridgeDisk', Disk) diff --git a/ui/arduino/main.js b/ui/arduino/main.js index bf693df..267e6d1 100644 --- a/ui/arduino/main.js +++ b/ui/arduino/main.js @@ -46,11 +46,15 @@ window.addEventListener('load', () => { app.use(store); app.route('*', App) app.mount('#app') - app.emitter.on('DOMContentLoaded', () => { if (app.state.diskNavigationRoot) { app.emitter.emit('refresh-files') } }) + app.emitter.on('', () => { + if (app.state.diskNavigationRoot) { + app.emitter.emit('refresh-files') + } + }) }) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index c748905..be77d8f 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -24,6 +24,7 @@ async function confirm(msg, cancelMsg, confirmMsg) { async function store(state, emitter) { win.setWindowSize(720, 640) + state.platform = window.BridgeWindow.getOS() state.view = 'editor' state.diskNavigationPath = '/' state.diskNavigationRoot = getDiskNavigationRootFromStorage() @@ -57,6 +58,8 @@ async function store(state, emitter) { state.isTerminalBound = false + state.shortcutsContext = 'editor' + const newFile = createEmptyFile({ parentFolder: null, // Null parent folder means not saved? source: 'disk' @@ -1360,6 +1363,47 @@ async function store(state, emitter) { await win.confirmClose() }) + // win.shortcutCmdR(() => { + // // Only run if we can execute + + // }) + + win.anyShortcut((key) => { + if (key === 'C') { + emitter.emit('open-connection-dialog') + } + if (key === 'D') { + emitter.emit('disconnect') + } + if (key === 'R') { + if (state.view != 'editor') return + emitter.emit('reset') + } + if (key === 'r') { + if (state.view != 'editor') return + runCode() + } + if (key === 'h') { + if (state.view != 'editor') return + stopCode() + } + if (key === 's') { + if (state.view != 'editor') return + emitter.emit('save') + } + + }) + + function runCode() { + if (canExecute({ view: state.view, isConnected: state.isConnected })) { + emitter.emit('run') + } + } + function stopCode() { + if (canExecute({ view: state.view, isConnected: state.isConnected })) { + emitter.emit('stop') + } + } function createFile(args) { const { source, diff --git a/ui/arduino/views/components/toolbar.js b/ui/arduino/views/components/toolbar.js index 3512ef9..fa8e87e 100644 --- a/ui/arduino/views/components/toolbar.js +++ b/ui/arduino/views/components/toolbar.js @@ -9,12 +9,13 @@ function Toolbar(state, emit) { view: state.view, isConnected: state.isConnected }) - + const metaKeyString = state.platform === 'darwin' ? 'Cmd' : 'Ctrl' + return html`
${Button({ icon: state.isConnected ? 'connect.svg' : 'disconnect.svg', - tooltip: state.isConnected ? 'Disconnect' : 'Connect', + tooltip: state.isConnected ? `Disconnect (${metaKeyString}+Shift+D)` : `Connect (${metaKeyString}+Shift+C)`, onClick: () => emit('open-connection-dialog'), active: state.isConnected })} @@ -23,19 +24,19 @@ function Toolbar(state, emit) { ${Button({ icon: 'run.svg', - tooltip: 'Run', + tooltip: `Run (${metaKeyString}+r)`, disabled: !_canExecute, onClick: () => emit('run') })} ${Button({ icon: 'stop.svg', - tooltip: 'Stop', + tooltip: `Stop (${metaKeyString}+h)`, disabled: !_canExecute, onClick: () => emit('stop') })} ${Button({ icon: 'reboot.svg', - tooltip: 'Reset', + tooltip: `Reset (${metaKeyString}+Shift+r)`, disabled: !_canExecute, onClick: () => emit('reset') })} @@ -44,7 +45,7 @@ function Toolbar(state, emit) { ${Button({ icon: 'save.svg', - tooltip: 'Save', + tooltip: `Save (${metaKeyString}+s)`, disabled: !_canSave, onClick: () => emit('save') })} From bfcc2c68d24d33eaeb60f4e0b27c4d5f447cde02 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Sun, 8 Dec 2024 23:31:45 +0100 Subject: [PATCH 02/22] Renamed method to onKeyboardShortcut. Signed-off-by: ubi de feo --- backend/ipc.js | 5 ----- preload.js | 2 +- ui/arduino/store.js | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/backend/ipc.js b/backend/ipc.js index 467cbff..dfe5917 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -129,11 +129,6 @@ module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { return response != opt.cancelId }) - ipcMain.handle('reload', (event, message = 'ciao, cane') => { - console.log('reload?') - win.webContents.send('reload', message) - }) - win.on('close', (event) => { console.log('BrowserWindow', 'close') event.preventDefault() diff --git a/preload.js b/preload.js index 0ed2abb..bf31e73 100644 --- a/preload.js +++ b/preload.js @@ -157,7 +157,7 @@ const Window = { setWindowSize: (minWidth, minHeight) => { ipcRenderer.invoke('set-window-size', minWidth, minHeight) }, - anyShortcut: (callback, key) => { + onKeyboardShortcut: (callback, key) => { ipcRenderer.on('shortcut-cmd', (event, k) => { // Get the active element const activeElement = document.activeElement; diff --git a/ui/arduino/store.js b/ui/arduino/store.js index be77d8f..b471329 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1368,7 +1368,7 @@ async function store(state, emitter) { // }) - win.anyShortcut((key) => { + win.onKeyboardShortcut((key) => { if (key === 'C') { emitter.emit('open-connection-dialog') } From c6d8d91d5fe7d243428801d0cc3101d6eac3b743 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Sun, 8 Dec 2024 23:33:20 +0100 Subject: [PATCH 03/22] Removed whitespace. Signed-off-by: ubi de feo --- backend/ipc.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/ipc.js b/backend/ipc.js index dfe5917..cabb54e 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -133,6 +133,5 @@ module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { console.log('BrowserWindow', 'close') event.preventDefault() win.webContents.send('check-before-close') - }) - + }) } From 45a582a188b21e84e2e0f64a8688316822f51773 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Sun, 8 Dec 2024 23:33:46 +0100 Subject: [PATCH 04/22] Removed whitespace. Signed-off-by: ubi de feo --- backend/ipc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ipc.js b/backend/ipc.js index cabb54e..8bace22 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -133,5 +133,5 @@ module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { console.log('BrowserWindow', 'close') event.preventDefault() win.webContents.send('check-before-close') - }) + }) } From 4c648a3add143d194f1f6934243db7cbd49a9dee Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Sun, 8 Dec 2024 23:39:56 +0100 Subject: [PATCH 05/22] Removed leftover test code from main.js. Signed-off-by: ubi de feo --- ui/arduino/main.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ui/arduino/main.js b/ui/arduino/main.js index 267e6d1..ce52be1 100644 --- a/ui/arduino/main.js +++ b/ui/arduino/main.js @@ -51,10 +51,4 @@ window.addEventListener('load', () => { app.emitter.emit('refresh-files') } }) - app.emitter.on('', () => { - if (app.state.diskNavigationRoot) { - app.emitter.emit('refresh-files') - } - }) - }) From ed7f83955bb127f0cfab2afa0be80b0023708af1 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Sun, 8 Dec 2024 23:43:58 +0100 Subject: [PATCH 06/22] Removed unnecessary shortcutsContext member. --- ui/arduino/store.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index b471329..0a1d337 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -58,8 +58,6 @@ async function store(state, emitter) { state.isTerminalBound = false - state.shortcutsContext = 'editor' - const newFile = createEmptyFile({ parentFolder: null, // Null parent folder means not saved? source: 'disk' From 9a490c23090387e8e814d9b0f0c58e2fe6681a43 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Sun, 8 Dec 2024 23:57:23 +0100 Subject: [PATCH 07/22] Removed accelerator shortcuts from Menu items for Reload and Dev Tools. Signed-off-by: ubi de feo --- backend/menu.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/menu.js b/backend/menu.js index 6b62cdf..6fa13f5 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -10,7 +10,6 @@ module.exports = function registerMenu(win) { submenu: [ { role: 'about'}, { type: 'separator' }, - { role: 'services' }, { type: 'separator' }, { role: 'hide' }, { role: 'hideOthers' }, @@ -54,8 +53,8 @@ module.exports = function registerMenu(win) { { label: 'View', submenu: [ - { role: 'reload' }, - { role: 'toggleDevTools' }, + { role: 'reload', accelerator: '' }, + { role: 'toggleDevTools', accelerator: ''}, { type: 'separator' }, { role: 'resetZoom' }, { role: 'zoomIn' }, From 177b7d1117b9f3e4f561b98ef6a302af385b39dc Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Mon, 9 Dec 2024 08:30:35 +0100 Subject: [PATCH 08/22] Implemented Board menu item. Signed-off-by: ubi de feo --- backend/ipc.js | 5 +++++ backend/menu.js | 38 ++++++++++++++++++++++++++++++++++++-- index.js | 7 ++++++- preload.js | 7 ++++++- ui/arduino/store.js | 13 +++++++++++++ 5 files changed, 66 insertions(+), 4 deletions(-) diff --git a/backend/ipc.js b/backend/ipc.js index 8bace22..f42e822 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -129,6 +129,11 @@ module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { return response != opt.cancelId }) + ipcMain.handle('update-menu-state', (event, state) => { + const registerMenu = require('./menu.js') + registerMenu(win, state) + }) + win.on('close', (event) => { console.log('BrowserWindow', 'close') event.preventDefault() diff --git a/backend/menu.js b/backend/menu.js index 6fa13f5..ef56591 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -2,7 +2,7 @@ const { app, Menu } = require('electron') const path = require('path') const openAboutWindow = require('about-window').default -module.exports = function registerMenu(win) { +module.exports = function registerMenu(win, state = {}) { const isMac = process.platform === 'darwin' const template = [ ...(isMac ? [{ @@ -11,7 +11,7 @@ module.exports = function registerMenu(win) { { role: 'about'}, { type: 'separator' }, { type: 'separator' }, - { role: 'hide' }, + { role: 'hide', accelerator: 'CmdOrCtrl+Shift+H' }, { role: 'hideOthers' }, { role: 'unhide' }, { type: 'separator' }, @@ -50,6 +50,40 @@ module.exports = function registerMenu(win) { ]) ] }, + { + label: 'Board', + submenu: [ + { + label: 'Connect', + accelerator: 'CmdOrCtrl+Shift+C', + click: () => win.webContents.send('shortcut-cmd', 'C') + }, + { + label: 'Disconnect', + accelerator: 'CmdOrCtrl+Shift+D', + click: () => win.webContents.send('shortcut-cmd', 'D') + }, + { role: 'separator' }, + { + label: 'Run', + accelerator: 'CmdOrCtrl+R', + enabled: state.isConnected && state.view === 'editor', + click: () => win.webContents.send('shortcut-cmd', 'r') + }, + { + label: 'Stop', + accelerator: 'CmdOrCtrl+H', + enabled: state.isConnected && state.view === 'editor', + click: () => win.webContents.send('shortcut-cmd', 'h') + }, + { + label: 'Reset', + accelerator: 'CmdOrCtrl+Shift+R', + enabled: state.isConnected && state.view === 'editor', + click: () => win.webContents.send('shortcut-cmd', 'R') + } + ] + }, { label: 'View', submenu: [ diff --git a/index.js b/index.js index dcf8def..68bc3c8 100644 --- a/index.js +++ b/index.js @@ -49,8 +49,13 @@ function createWindow () { win.show() }) + const initialMenuState = { + isConnected: false, + view: 'editor' + } + registerIPCHandlers(win, ipcMain, app, dialog) - registerMenu(win) + registerMenu(win, initialMenuState) app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow() diff --git a/preload.js b/preload.js index bf31e73..a88a4dd 100644 --- a/preload.js +++ b/preload.js @@ -180,7 +180,12 @@ const Window = { getOS: () => platform, isWindows: () => platform === 'win32', isMac: () => platform === 'darwin', - isLinux: () => platform === 'linux' + isLinux: () => platform === 'linux', + + updateMenuState: (state) => { + return ipcRenderer.invoke('update-menu-state', state) + } + } contextBridge.exposeInMainWorld('BridgeSerial', Serial) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index 0a1d337..10193fc 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -81,6 +81,14 @@ async function store(state, emitter) { emitter.emit('render') } + // Menu management + const updateMenu = () => { + window.BridgeWindow.updateMenuState({ + isConnected: state.isConnected, + view: state.view + }) + } + // START AND BASIC ROUTING emitter.on('select-disk-navigation-root', async () => { const folder = await selectDiskFolder() @@ -98,6 +106,7 @@ async function store(state, emitter) { emitter.emit('refresh-files') } emitter.emit('render') + updateMenu() }) // CONNECTION DIALOG @@ -143,11 +152,13 @@ async function store(state, emitter) { } // Stop whatever is going on // Recover from getting stuck in raw repl + await serial.getPrompt() clearTimeout(timeout_id) // Connected and ready state.isConnecting = false state.isConnected = true + updateMenu() if (state.view === 'editor' && state.panelHeight <= PANEL_CLOSED) { state.panelHeight = state.savedPanelHeight } @@ -181,6 +192,7 @@ async function store(state, emitter) { state.boardNavigationPath = '/' emitter.emit('refresh-files') emitter.emit('render') + updateMenu() }) emitter.on('connection-timeout', async () => { state.isConnected = false @@ -1646,4 +1658,5 @@ async function getHelperFullPath() { '' ) } + } From c6ec1804ae42b7786cd8a4ac2be3c5de7f736dfc Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Mon, 9 Dec 2024 08:55:42 +0100 Subject: [PATCH 09/22] Menu cleanup. Signed-off-by: ubi de feo --- backend/menu.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/menu.js b/backend/menu.js index ef56591..574a798 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -34,7 +34,6 @@ module.exports = function registerMenu(win, state = {}) { { role: 'copy' }, { role: 'paste' }, ...(isMac ? [ - { role: 'pasteAndMatchStyle' }, { role: 'selectAll' }, { type: 'separator' }, { @@ -108,7 +107,7 @@ module.exports = function registerMenu(win, state = {}) { { type: 'separator' }, { role: 'window' } ] : [ - { role: 'close' } + ]) ] }, From 1fb588e01529cb6c0c4d4ccc146bfdb99a082e89 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Mon, 9 Dec 2024 13:48:32 +0100 Subject: [PATCH 10/22] Added ESC key listener. Enabled it on connection dialog. Signed-off-by: ubi de feo --- index.js | 3 +++ ui/arduino/store.js | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/index.js b/index.js index 68bc3c8..97cffc5 100644 --- a/index.js +++ b/index.js @@ -92,6 +92,9 @@ function registerShortcuts() { globalShortcut.register('CommandOrControl+Shift+D', () => { console.log('Disconnect from Board') shortcutAction('D') + }), + globalShortcut.register('Escape', () => { + shortcutAction('ESC') }) } diff --git a/ui/arduino/store.js b/ui/arduino/store.js index 10193fc..396050c 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1401,6 +1401,11 @@ async function store(state, emitter) { if (state.view != 'editor') return emitter.emit('save') } + if (key === 'ESC') { + if (state.isConnectionDialogOpen) { + emitter.emit('close-connection-dialog') + } + } }) From 861b658c590bb243ba076157adf9aa1caee9054e Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Mon, 9 Dec 2024 18:34:46 +0100 Subject: [PATCH 11/22] Added Clear Terminal shortcut Meta+k. Signed-off-by: ubi de feo --- index.js | 9 +++++++++ preload.js | 19 +++++++++++-------- ui/arduino/store.js | 9 +++++++++ ui/arduino/views/components/repl-panel.js | 2 +- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 97cffc5..67375fe 100644 --- a/index.js +++ b/index.js @@ -93,6 +93,15 @@ function registerShortcuts() { console.log('Disconnect from Board') shortcutAction('D') }), + globalShortcut.register('CommandOrControl+K', () => { + console.log('Clear Terminal') + shortcutAction('K') + }), + // Future: Toggle REPL Panel + // globalShortcut.register('CommandOrControl+T', () => { + // console.log('Toggle Terminal') + // shortcutAction('T') + // }), globalShortcut.register('Escape', () => { shortcutAction('ESC') }) diff --git a/preload.js b/preload.js index a88a4dd..dfb48d1 100644 --- a/preload.js +++ b/preload.js @@ -159,15 +159,18 @@ const Window = { }, onKeyboardShortcut: (callback, key) => { ipcRenderer.on('shortcut-cmd', (event, k) => { - // Get the active element - const activeElement = document.activeElement; - // Check if the active element is the terminal - const isTerminalFocused = activeElement.classList.contains('xterm-helper-textarea'); + + // Only trigger callback if terminal is not focused AND we're in editor view - if (!isTerminalFocused) { - console.log('shortcut-cmd-r executed') - callback(k); - } + // This has been deemed unnecessary since there are no real conflicts with the terminal + // The REPL shortcuts Ctrl+a|b|c|d are not used as application shortcuts and will + // only be triggered when the user has focused the REPL + // The code is left here for reference + // const activeElement = document.activeElement; + // const isTerminalFocused = activeElement.classList.contains('xterm-helper-textarea'); + // if (!isTerminalFocused) { + callback(k); + // } }) }, diff --git a/ui/arduino/store.js b/ui/arduino/store.js index 396050c..540c19f 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1389,6 +1389,15 @@ async function store(state, emitter) { if (state.view != 'editor') return emitter.emit('reset') } + if (key === 'K') { + if (state.view != 'editor') return + emitter.emit('clear-terminal') + } + // Future: Toggle REPL panel + // if (key === 'T') { + // if (state.view != 'editor') return + // emitter.emit('clear-terminal') + // } if (key === 'r') { if (state.view != 'editor') return runCode() diff --git a/ui/arduino/views/components/repl-panel.js b/ui/arduino/views/components/repl-panel.js index ac1760c..b56c531 100644 --- a/ui/arduino/views/components/repl-panel.js +++ b/ui/arduino/views/components/repl-panel.js @@ -50,7 +50,7 @@ function ReplOperations(state, emit) { Button({ icon: 'delete.svg', size: 'small', - tooltip: 'Clean', + tooltip: `Clean (${state.platform === 'darwin' ? 'Cmd' : 'Ctrl'}+k)`, onClick: () => emit('clear-terminal') }) ] From afadd3fa9ea7c4bfb87be481ec6d03650bf34d4a Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Tue, 10 Dec 2024 12:54:37 +0100 Subject: [PATCH 12/22] Testing disconnect before manual reload. Signed-off-by: ubi de feo --- backend/ipc.js | 5 +++++ backend/menu.js | 15 ++++++++++++++- index.js | 18 ++++++++++++++++++ preload.js | 9 +++++++++ ui/arduino/store.js | 12 ++++++++++++ 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/backend/ipc.js b/backend/ipc.js index f42e822..eefd348 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -139,4 +139,9 @@ module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { event.preventDefault() win.webContents.send('check-before-close') }) + + // handle disconnection before reload + ipcMain.handle('prepare-reload', async (event) => { + return win.webContents.send('before-reload') + }) } diff --git a/backend/menu.js b/backend/menu.js index 574a798..6aa2051 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -86,7 +86,20 @@ module.exports = function registerMenu(win, state = {}) { { label: 'View', submenu: [ - { role: 'reload', accelerator: '' }, + { + label: 'Reload', + accelerator: '', + click: async () => { + try { + win.webContents.send('cleanup-before-reload') + setTimeout(() => { + win.reload() + }, 500) + } catch(e) { + console.error('Reload from menu failed:', e) + } + } + }, { role: 'toggleDevTools', accelerator: ''}, { type: 'separator' }, { role: 'resetZoom' }, diff --git a/index.js b/index.js index 67375fe..8c0409e 100644 --- a/index.js +++ b/index.js @@ -49,6 +49,24 @@ function createWindow () { win.show() }) + win.webContents.on('before-reload', async (event) => { + // Prevent the default reload behavior + event.preventDefault() + + try { + // Tell renderer to do cleanup + win.webContents.send('cleanup-before-reload') + + // Wait for cleanup then reload + setTimeout(() => { + // This will trigger a page reload, but won't trigger 'before-reload' again + win.reload() + }, 500) + } catch(e) { + console.error('Reload preparation failed:', e) + } + }) + const initialMenuState = { isConnected: false, view: 'editor' diff --git a/preload.js b/preload.js index dfb48d1..210d81f 100644 --- a/preload.js +++ b/preload.js @@ -174,6 +174,15 @@ const Window = { }) }, + onBeforeReload: (callback) => { + ipcRenderer.on('cleanup-before-reload', async () => { + try { + await callback() + } catch(e) { + console.error('Cleanup before reload failed:', e) + } + }) + }, beforeClose: (callback) => ipcRenderer.on('check-before-close', callback), confirmClose: () => ipcRenderer.invoke('confirm-close'), diff --git a/ui/arduino/store.js b/ui/arduino/store.js index 540c19f..a43cfcc 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1364,6 +1364,18 @@ async function store(state, emitter) { emitter.emit('render') }) + win.onBeforeReload(async () => { + // Perform any cleanup needed + if (state.isConnected) { + await serial.disconnect() + state.isConnected = false + state.panelHeight = PANEL_CLOSED + state.boardFiles = [] + state.boardNavigationPath = '/' + } + // Any other cleanup needed + }) + win.beforeClose(async () => { const hasChanges = !!state.openFiles.find(f => f.hasChanges) if (hasChanges) { From 88fe9a2af3a357f483641fe2700bcdc709d74f31 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Wed, 11 Dec 2024 16:40:54 +0100 Subject: [PATCH 13/22] Implemented ALT option to run code selection. Signed-off-by: ubi de feo --- index.js | 4 ++++ ui/arduino/store.js | 13 +++++++++++-- ui/arduino/views/components/elements/button.js | 2 +- ui/arduino/views/components/toolbar.js | 8 +++++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 8c0409e..efb675e 100644 --- a/index.js +++ b/index.js @@ -90,6 +90,10 @@ function registerShortcuts() { console.log('Running Program') shortcutAction('r') }) + globalShortcut.register('CommandOrControl+Alt+R', () => { + console.log('Running Code Selection') + shortcutAction('_r') + }) globalShortcut.register('CommandOrControl+H', () => { console.log('Stopping Program (Halt)') shortcutAction('h') diff --git a/ui/arduino/store.js b/ui/arduino/store.js index fcaa0de..dca01bd 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -203,7 +203,7 @@ async function store(state, emitter) { }) // CODE EXECUTION - emitter.on('run', async () => { + emitter.on('run', async (selection = false) => { log('run') const openFile = state.openFiles.find(f => f.id == state.editingFile) let code = openFile.editor.editor.state.doc.toString() @@ -211,7 +211,7 @@ async function store(state, emitter) { // If there is a selection, run only the selected code const startIndex = openFile.editor.editor.state.selection.ranges[0].from const endIndex = openFile.editor.editor.state.selection.ranges[0].to - if (endIndex - startIndex > 0) { + if (endIndex - startIndex > 0 && selection) { selectedCode = openFile.editor.editor.state.doc.toString().substring(startIndex, endIndex) // Checking to see if the user accidentally double-clicked some whitespace // While a random selection would yield an error when executed, @@ -1430,6 +1430,10 @@ async function store(state, emitter) { if (state.view != 'editor') return runCode() } + if (key === '_r') { + if (state.view != 'editor') return + runCodeSelection() + } if (key === 'h') { if (state.view != 'editor') return stopCode() @@ -1451,6 +1455,11 @@ async function store(state, emitter) { emitter.emit('run') } } + function runCodeSelection() { + if (canExecute({ view: state.view, isConnected: state.isConnected })) { + emitter.emit('run', true) + } + } function stopCode() { if (canExecute({ view: state.view, isConnected: state.isConnected })) { emitter.emit('stop') diff --git a/ui/arduino/views/components/elements/button.js b/ui/arduino/views/components/elements/button.js index 7030d49..3d888dd 100644 --- a/ui/arduino/views/components/elements/button.js +++ b/ui/arduino/views/components/elements/button.js @@ -2,7 +2,7 @@ function Button(args) { const { size = '', icon = 'connect.svg', - onClick = () => false, + onClick = (e) => false, disabled = false, active = false, tooltip, diff --git a/ui/arduino/views/components/toolbar.js b/ui/arduino/views/components/toolbar.js index d5f6a7a..b63e243 100644 --- a/ui/arduino/views/components/toolbar.js +++ b/ui/arduino/views/components/toolbar.js @@ -26,7 +26,13 @@ function Toolbar(state, emit) { icon: 'run.svg', tooltip: `Run (${metaKeyString}+r)`, disabled: !_canExecute, - onClick: () => emit('run') + onClick: (e) => { + if (e.altKey) { + emit('run', true) + }else{ + emit('run') + } + } })} ${Button({ icon: 'stop.svg', From 9908d4a7789f0026f41adfa7f86f6e84fcaff9e0 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Thu, 12 Dec 2024 13:40:32 +0100 Subject: [PATCH 14/22] Refactored menu and global shortcuts into constants file. Signed-off-by: ubi de feo --- backend/menu.js | 38 ++++++---- backend/shortcuts.js | 23 ++++++ index.js | 88 +++++++++++++---------- preload.js | 6 +- ui/arduino/store.js | 20 +++--- ui/arduino/views/components/repl-panel.js | 2 +- 6 files changed, 114 insertions(+), 63 deletions(-) create mode 100644 backend/shortcuts.js diff --git a/backend/menu.js b/backend/menu.js index 6aa2051..e7ee2d9 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -1,6 +1,7 @@ const { app, Menu } = require('electron') const path = require('path') const openAboutWindow = require('about-window').default +const shortcuts = require('./shortcuts.js') module.exports = function registerMenu(win, state = {}) { const isMac = process.platform === 'darwin' @@ -54,32 +55,45 @@ module.exports = function registerMenu(win, state = {}) { submenu: [ { label: 'Connect', - accelerator: 'CmdOrCtrl+Shift+C', - click: () => win.webContents.send('shortcut-cmd', 'C') + accelerator: shortcuts.menu.CONNECT, + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.CONNECT) }, { label: 'Disconnect', - accelerator: 'CmdOrCtrl+Shift+D', - click: () => win.webContents.send('shortcut-cmd', 'D') + accelerator: shortcuts.menu.DISCONNECT, + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.DISCONNECT) }, - { role: 'separator' }, + { type: 'separator' }, { label: 'Run', - accelerator: 'CmdOrCtrl+R', + accelerator: shortcuts.menu.RUN, + enabled: state.isConnected && state.view === 'editor', + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.RUN) + }, + { + label: 'Run selection', + accelerator: shortcuts.menu.RUN_SELECTION, enabled: state.isConnected && state.view === 'editor', - click: () => win.webContents.send('shortcut-cmd', 'r') + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.RUN_SELECTION) }, { label: 'Stop', - accelerator: 'CmdOrCtrl+H', + accelerator: shortcuts.menu.STOP, enabled: state.isConnected && state.view === 'editor', - click: () => win.webContents.send('shortcut-cmd', 'h') + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.STOP) }, { label: 'Reset', - accelerator: 'CmdOrCtrl+Shift+R', + accelerator: shortcuts.menu.RESET, + enabled: state.isConnected && state.view === 'editor', + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.RESET) + }, + { type: 'separator' }, + { + label: 'Clear terminal', + accelerator: shortcuts.menu.CLEAR_TERMINAL, enabled: state.isConnected && state.view === 'editor', - click: () => win.webContents.send('shortcut-cmd', 'R') + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.CLEAR_TERMINAL) } ] }, @@ -100,7 +114,7 @@ module.exports = function registerMenu(win, state = {}) { } } }, - { role: 'toggleDevTools', accelerator: ''}, + { role: 'toggleDevTools'}, { type: 'separator' }, { role: 'resetZoom' }, { role: 'zoomIn' }, diff --git a/backend/shortcuts.js b/backend/shortcuts.js new file mode 100644 index 0000000..93026a2 --- /dev/null +++ b/backend/shortcuts.js @@ -0,0 +1,23 @@ +module.exports = { + global: { + CONNECT: 'CommandOrControl+Shift+C', + DISCONNECT: 'CommandOrControl+Shift+D', + SAVE: 'CommandOrControl+S', + RUN: 'CommandOrControl+R', + RUN_SELECTION: 'CommandOrControl+Alt+R', + STOP: 'CommandOrControl+H', + RESET: 'CommandOrControl+Shift+R', + CLEAR_TERMINAL: 'CommandOrControl+L', + ESC: 'Escape' + }, + menu: { + CONNECT: 'CmdOrCtrl+Shift+C', + DISCONNECT: 'CmdOrCtrl+Shift+D', + SAVE: 'CmdOrCtrl+S', + RUN: 'CmdOrCtrl+R', + RUN_SELECTION: 'CmdOrCtrl+Alt+R', + STOP: 'CmdOrCtrl+H', + RESET: 'CmdOrCtrl+Shift+R', + CLEAR_TERMINAL: 'CmdOrCtrl+L', + } +} diff --git a/index.js b/index.js index efb675e..b11d662 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ const { app, BrowserWindow, ipcMain, dialog, globalShortcut } = require('electron') const path = require('path') const fs = require('fs') +const shortcuts = require('./backend/shortcuts.js').global const registerIPCHandlers = require('./backend/ipc.js') const registerMenu = require('./backend/menu.js') @@ -86,47 +87,58 @@ function shortcutAction(key) { // Shortcuts function registerShortcuts() { - globalShortcut.register('CommandOrControl+R', () => { - console.log('Running Program') - shortcutAction('r') - }) - globalShortcut.register('CommandOrControl+Alt+R', () => { - console.log('Running Code Selection') - shortcutAction('_r') - }) - globalShortcut.register('CommandOrControl+H', () => { - console.log('Stopping Program (Halt)') - shortcutAction('h') - }) - globalShortcut.register('CommandOrControl+S', () => { - console.log('Saving File') - shortcutAction('s') + Object.entries(shortcuts).forEach(([command, shortcut]) => { + globalShortcut.register(shortcut, () => { + shortcutAction(shortcut) + }); }) + // shortcuts.forEach(element => { + // globalShortcut.register(element, () => { + + // shortcutAction(element) + // }); + // }); + // globalShortcut.register(shortcuts.RUN, () => { + // console.log('Running Program') + // shortcutAction(shortcuts.RUN) + // }) + // globalShortcut.register('CommandOrControl+Alt+R', () => { + // console.log('Running Code Selection') + // shortcutAction('meta_alt_r') + // }) + // globalShortcut.register('CommandOrControl+H', () => { + // console.log('Stopping Program (Halt)') + // shortcutAction('meta_h') + // }) + // globalShortcut.register('CommandOrControl+S', () => { + // console.log('Saving File') + // shortcutAction('meta_s') + // }) - globalShortcut.register('CommandOrControl+Shift+R', () => { - console.log('Resetting Board') - shortcutAction('R') - }) - globalShortcut.register('CommandOrControl+Shift+C', () => { - console.log('Connect to Board') - shortcutAction('C') - }) - globalShortcut.register('CommandOrControl+Shift+D', () => { - console.log('Disconnect from Board') - shortcutAction('D') - }), - globalShortcut.register('CommandOrControl+K', () => { - console.log('Clear Terminal') - shortcutAction('K') - }), - // Future: Toggle REPL Panel - // globalShortcut.register('CommandOrControl+T', () => { - // console.log('Toggle Terminal') - // shortcutAction('T') + // globalShortcut.register('CommandOrControl+Shift+R', () => { + // console.log('Resetting Board') + // shortcutAction('meta_shift_r') + // }) + // globalShortcut.register(shortcuts.CONNECT, () => { + // console.log('Connect to Board') + // shortcutAction(shortcuts.CONNECT) + // }) + // globalShortcut.register(shortcuts.DISCONNECT, () => { + // console.log('Disconnect from Board') + // shortcutAction(shortcuts.DISCONNECT) // }), - globalShortcut.register('Escape', () => { - shortcutAction('ESC') - }) + // globalShortcut.register('CommandOrControl+K', () => { + // console.log('Clear Terminal') + // shortcutAction('K') + // }), + // // Future: Toggle REPL Panel + // // globalShortcut.register('CommandOrControl+T', () => { + // // console.log('Toggle Terminal') + // // shortcutAction('T') + // // }), + // globalShortcut.register('Escape', () => { + // shortcutAction('ESC') + // }) } app.on('ready', () => { diff --git a/preload.js b/preload.js index 210d81f..bf78552 100644 --- a/preload.js +++ b/preload.js @@ -1,7 +1,7 @@ console.log('preload') const { contextBridge, ipcRenderer } = require('electron') const path = require('path') - +const shortcuts = require('./backend/shortcuts.js').global const MicroPython = require('micropython.js') const { emit, platform } = require('process') // const { platform } = requireprocess.platform @@ -196,8 +196,8 @@ const Window = { updateMenuState: (state) => { return ipcRenderer.invoke('update-menu-state', state) - } - + }, + getShortcuts: () => shortcuts } contextBridge.exposeInMainWorld('BridgeSerial', Serial) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index dca01bd..d10304d 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -3,6 +3,8 @@ const serial = window.BridgeSerial const disk = window.BridgeDisk const win = window.BridgeWindow +const shortcuts = window.BridgeWindow.getShortcuts() + const newFileContent = `# This program was created in Arduino Lab for MicroPython print('Hello, MicroPython!') @@ -1407,17 +1409,17 @@ async function store(state, emitter) { // }) win.onKeyboardShortcut((key) => { - if (key === 'C') { + if (key === shortcuts.CONNECT) { emitter.emit('open-connection-dialog') } - if (key === 'D') { + if (key === shortcuts.DISCONNECT) { emitter.emit('disconnect') } - if (key === 'R') { + if (key === shortcuts.RESET) { if (state.view != 'editor') return emitter.emit('reset') } - if (key === 'K') { + if (key === shortcuts.CLEAR_TERMINAL) { if (state.view != 'editor') return emitter.emit('clear-terminal') } @@ -1426,23 +1428,23 @@ async function store(state, emitter) { // if (state.view != 'editor') return // emitter.emit('clear-terminal') // } - if (key === 'r') { + if (key === shortcuts.RUN) { if (state.view != 'editor') return runCode() } - if (key === '_r') { + if (key === shortcuts.RUN_SELECTION) { if (state.view != 'editor') return runCodeSelection() } - if (key === 'h') { + if (key === shortcuts.STOP) { if (state.view != 'editor') return stopCode() } - if (key === 's') { + if (key === shortcuts.SAVE) { if (state.view != 'editor') return emitter.emit('save') } - if (key === 'ESC') { + if (key === shortcuts.ESC) { if (state.isConnectionDialogOpen) { emitter.emit('close-connection-dialog') } diff --git a/ui/arduino/views/components/repl-panel.js b/ui/arduino/views/components/repl-panel.js index b56c531..3974d50 100644 --- a/ui/arduino/views/components/repl-panel.js +++ b/ui/arduino/views/components/repl-panel.js @@ -50,7 +50,7 @@ function ReplOperations(state, emit) { Button({ icon: 'delete.svg', size: 'small', - tooltip: `Clean (${state.platform === 'darwin' ? 'Cmd' : 'Ctrl'}+k)`, + tooltip: `Clean (${state.platform === 'darwin' ? 'Cmd' : 'Ctrl'}+L)`, onClick: () => emit('clear-terminal') }) ] From 0fa99b18b97f80544d501d25c7ba63d0d50608ca Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Thu, 12 Dec 2024 14:03:51 +0100 Subject: [PATCH 15/22] Changed 'selection' to 'onlySelected'. Signed-off-by: ubi de feo --- ui/arduino/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index d10304d..aff39ce 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -205,7 +205,7 @@ async function store(state, emitter) { }) // CODE EXECUTION - emitter.on('run', async (selection = false) => { + emitter.on('run', async (onlySelected = false) => { log('run') const openFile = state.openFiles.find(f => f.id == state.editingFile) let code = openFile.editor.editor.state.doc.toString() @@ -213,7 +213,7 @@ async function store(state, emitter) { // If there is a selection, run only the selected code const startIndex = openFile.editor.editor.state.selection.ranges[0].from const endIndex = openFile.editor.editor.state.selection.ranges[0].to - if (endIndex - startIndex > 0 && selection) { + if (endIndex - startIndex > 0 && onlySelected) { selectedCode = openFile.editor.editor.state.doc.toString().substring(startIndex, endIndex) // Checking to see if the user accidentally double-clicked some whitespace // While a random selection would yield an error when executed, From 530dbc693156d36f8af01ec98dc2fa3328893c2c Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Thu, 12 Dec 2024 14:50:13 +0100 Subject: [PATCH 16/22] Moved registerMenu to file scope. Signed-off-by: ubi de feo --- backend/ipc.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/ipc.js b/backend/ipc.js index eefd348..12f2127 100644 --- a/backend/ipc.js +++ b/backend/ipc.js @@ -1,4 +1,6 @@ const fs = require('fs') +const registerMenu = require('./menu.js') + const { openFolderDialog, listFolder, @@ -130,7 +132,6 @@ module.exports = function registerIPCHandlers(win, ipcMain, app, dialog) { }) ipcMain.handle('update-menu-state', (event, state) => { - const registerMenu = require('./menu.js') registerMenu(win, state) }) From a019c999ea42cac6d6c5bada02ab454dbdffbd7d Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Fri, 13 Dec 2024 07:42:37 +0100 Subject: [PATCH 17/22] Only save if openFile (tab) has changes. Signed-off-by: ubi de feo --- ui/arduino/store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index aff39ce..93ed152 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1599,6 +1599,7 @@ function pickRandom(array) { function canSave({ view, isConnected, openFiles, editingFile }) { const isEditor = view === 'editor' const file = openFiles.find(f => f.id === editingFile) + if (!file.hasChanges) return false // Can only save on editor if (!isEditor) return false // Can always save disk files From b0511201bb2b82add369ed5da02c1cef2d6a2e6d Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Fri, 13 Dec 2024 09:15:44 +0100 Subject: [PATCH 18/22] Added view switch, replaced editor icon, updated shortcuts. Signed-off-by: ubi de feo --- backend/menu.js | 32 ++++++++++++++++++-------- backend/shortcuts.js | 4 ++++ ui/arduino/media/code.svg | 3 +++ ui/arduino/store.js | 8 +++++++ ui/arduino/views/components/toolbar.js | 14 +++++------ 5 files changed, 44 insertions(+), 17 deletions(-) create mode 100644 ui/arduino/media/code.svg diff --git a/backend/menu.js b/backend/menu.js index e7ee2d9..e706a41 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -2,6 +2,7 @@ const { app, Menu } = require('electron') const path = require('path') const openAboutWindow = require('about-window').default const shortcuts = require('./shortcuts.js') +const { type } = require('os') module.exports = function registerMenu(win, state = {}) { const isMac = process.platform === 'darwin' @@ -99,6 +100,27 @@ module.exports = function registerMenu(win, state = {}) { }, { label: 'View', + submenu: [ + { + label: 'Editor', + accelerator: shortcuts.menu.EDITOR_VIEW, + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.EDITOR_VIEW,) + }, + { + label: 'Files', + accelerator: shortcuts.menu.FILES_VIEW, + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.FILES_VIEW) + }, + { type: 'separator' }, + { role: 'resetZoom' }, + { role: 'zoomIn' }, + { role: 'zoomOut' }, + { type: 'separator' }, + { role: 'togglefullscreen' }, + ] + }, + { + label: 'Window', submenu: [ { label: 'Reload', @@ -116,16 +138,6 @@ module.exports = function registerMenu(win, state = {}) { }, { role: 'toggleDevTools'}, { type: 'separator' }, - { role: 'resetZoom' }, - { role: 'zoomIn' }, - { role: 'zoomOut' }, - { type: 'separator' }, - { role: 'togglefullscreen' }, - ] - }, - { - label: 'Window', - submenu: [ { role: 'minimize' }, { role: 'zoom' }, ...(isMac ? [ diff --git a/backend/shortcuts.js b/backend/shortcuts.js index 93026a2..b496200 100644 --- a/backend/shortcuts.js +++ b/backend/shortcuts.js @@ -8,6 +8,8 @@ module.exports = { STOP: 'CommandOrControl+H', RESET: 'CommandOrControl+Shift+R', CLEAR_TERMINAL: 'CommandOrControl+L', + EDITOR_VIEW: 'CommandOrControl+Alt+1', + FILES_VIEW: 'CommandOrControl+Alt+2', ESC: 'Escape' }, menu: { @@ -19,5 +21,7 @@ module.exports = { STOP: 'CmdOrCtrl+H', RESET: 'CmdOrCtrl+Shift+R', CLEAR_TERMINAL: 'CmdOrCtrl+L', + EDITOR_VIEW: 'CmdOrCtrl+Alt+1', + FILES_VIEW: 'CmdOrCtrl+Alt+2' } } diff --git a/ui/arduino/media/code.svg b/ui/arduino/media/code.svg new file mode 100644 index 0000000..3b4303f --- /dev/null +++ b/ui/arduino/media/code.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/arduino/store.js b/ui/arduino/store.js index 93ed152..fddea1a 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1444,6 +1444,14 @@ async function store(state, emitter) { if (state.view != 'editor') return emitter.emit('save') } + if (key === shortcuts.EDITOR_VIEW) { + if (state.view != 'file-manager') return + emitter.emit('change-view', 'editor') + } + if (key === shortcuts.FILES_VIEW) { + if (state.view != 'editor') return + emitter.emit('change-view', 'file-manager') + } if (key === shortcuts.ESC) { if (state.isConnectionDialogOpen) { emitter.emit('close-connection-dialog') diff --git a/ui/arduino/views/components/toolbar.js b/ui/arduino/views/components/toolbar.js index b63e243..0e3d497 100644 --- a/ui/arduino/views/components/toolbar.js +++ b/ui/arduino/views/components/toolbar.js @@ -24,7 +24,7 @@ function Toolbar(state, emit) { ${Button({ icon: 'run.svg', - tooltip: `Run (${metaKeyString}+r)`, + tooltip: `Run (${metaKeyString}+R)`, disabled: !_canExecute, onClick: (e) => { if (e.altKey) { @@ -36,13 +36,13 @@ function Toolbar(state, emit) { })} ${Button({ icon: 'stop.svg', - tooltip: `Stop (${metaKeyString}+h)`, + tooltip: `Stop (${metaKeyString}+H)`, disabled: !_canExecute, onClick: () => emit('stop') })} ${Button({ icon: 'reboot.svg', - tooltip: `Reset (${metaKeyString}+Shift+r)`, + tooltip: `Reset (${metaKeyString}+Shift+R)`, disabled: !_canExecute, onClick: () => emit('reset') })} @@ -51,7 +51,7 @@ function Toolbar(state, emit) { ${Button({ icon: 'save.svg', - tooltip: `Save (${metaKeyString}+s)`, + tooltip: `Save (${metaKeyString}+S)`, disabled: !_canSave, onClick: () => emit('save') })} @@ -59,14 +59,14 @@ function Toolbar(state, emit) {
${Button({ - icon: 'editor.svg', - tooltip: 'Editor and REPL', + icon: 'code.svg', + tooltip: `Editor (${metaKeyString}+Alt+1)`, active: state.view === 'editor', onClick: () => emit('change-view', 'editor') })} ${Button({ icon: 'files.svg', - tooltip: 'File Manager', + tooltip: `Files (${metaKeyString}+Alt+2)`, active: state.view === 'file-manager', onClick: () => emit('change-view', 'file-manager') })} From bd3cc3b0e9d248493222e4614ec43afc2e484b45 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Fri, 13 Dec 2024 09:19:55 +0100 Subject: [PATCH 19/22] Moved 'Clear Terminal' to 'View' Signed-off-by: ubi de feo --- backend/menu.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/menu.js b/backend/menu.js index e706a41..337571a 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -89,13 +89,7 @@ module.exports = function registerMenu(win, state = {}) { enabled: state.isConnected && state.view === 'editor', click: () => win.webContents.send('shortcut-cmd', shortcuts.global.RESET) }, - { type: 'separator' }, - { - label: 'Clear terminal', - accelerator: shortcuts.menu.CLEAR_TERMINAL, - enabled: state.isConnected && state.view === 'editor', - click: () => win.webContents.send('shortcut-cmd', shortcuts.global.CLEAR_TERMINAL) - } + { type: 'separator' } ] }, { @@ -111,6 +105,12 @@ module.exports = function registerMenu(win, state = {}) { accelerator: shortcuts.menu.FILES_VIEW, click: () => win.webContents.send('shortcut-cmd', shortcuts.global.FILES_VIEW) }, + { + label: 'Clear terminal', + accelerator: shortcuts.menu.CLEAR_TERMINAL, + enabled: state.isConnected && state.view === 'editor', + click: () => win.webContents.send('shortcut-cmd', shortcuts.global.CLEAR_TERMINAL) + }, { type: 'separator' }, { role: 'resetZoom' }, { role: 'zoomIn' }, From 923166149883f4de34f23e10bb4c4d84a9509c36 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Fri, 13 Dec 2024 11:40:54 +0100 Subject: [PATCH 20/22] Removed comments with dev notes. Signed-off-by: ubi de feo --- backend/menu.js | 1 - index.js | 47 ----------------------------------------------- preload.js | 13 +------------ 3 files changed, 1 insertion(+), 60 deletions(-) diff --git a/backend/menu.js b/backend/menu.js index 337571a..2d406f7 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -173,7 +173,6 @@ module.exports = function registerMenu(win, state = {}) { openAboutWindow({ icon_path: path.resolve(__dirname, '../ui/arduino/media/about_image.png'), css_path: path.resolve(__dirname, '../ui/arduino/views/about.css'), - // about_page_dir: path.resolve(__dirname, '../ui/arduino/views/'), copyright: '© Arduino SA 2022', package_json_dir: path.resolve(__dirname, '..'), bug_report_url: "https://github.com/arduino/lab-micropython-editor/issues", diff --git a/index.js b/index.js index b11d662..aa5d989 100644 --- a/index.js +++ b/index.js @@ -92,53 +92,6 @@ function registerShortcuts() { shortcutAction(shortcut) }); }) - // shortcuts.forEach(element => { - // globalShortcut.register(element, () => { - - // shortcutAction(element) - // }); - // }); - // globalShortcut.register(shortcuts.RUN, () => { - // console.log('Running Program') - // shortcutAction(shortcuts.RUN) - // }) - // globalShortcut.register('CommandOrControl+Alt+R', () => { - // console.log('Running Code Selection') - // shortcutAction('meta_alt_r') - // }) - // globalShortcut.register('CommandOrControl+H', () => { - // console.log('Stopping Program (Halt)') - // shortcutAction('meta_h') - // }) - // globalShortcut.register('CommandOrControl+S', () => { - // console.log('Saving File') - // shortcutAction('meta_s') - // }) - - // globalShortcut.register('CommandOrControl+Shift+R', () => { - // console.log('Resetting Board') - // shortcutAction('meta_shift_r') - // }) - // globalShortcut.register(shortcuts.CONNECT, () => { - // console.log('Connect to Board') - // shortcutAction(shortcuts.CONNECT) - // }) - // globalShortcut.register(shortcuts.DISCONNECT, () => { - // console.log('Disconnect from Board') - // shortcutAction(shortcuts.DISCONNECT) - // }), - // globalShortcut.register('CommandOrControl+K', () => { - // console.log('Clear Terminal') - // shortcutAction('K') - // }), - // // Future: Toggle REPL Panel - // // globalShortcut.register('CommandOrControl+T', () => { - // // console.log('Toggle Terminal') - // // shortcutAction('T') - // // }), - // globalShortcut.register('Escape', () => { - // shortcutAction('ESC') - // }) } app.on('ready', () => { diff --git a/preload.js b/preload.js index bf78552..dd4f28f 100644 --- a/preload.js +++ b/preload.js @@ -4,7 +4,7 @@ const path = require('path') const shortcuts = require('./backend/shortcuts.js').global const MicroPython = require('micropython.js') const { emit, platform } = require('process') -// const { platform } = requireprocess.platform + const board = new MicroPython() board.chunk_size = 192 board.chunk_sleep = 200 @@ -159,18 +159,7 @@ const Window = { }, onKeyboardShortcut: (callback, key) => { ipcRenderer.on('shortcut-cmd', (event, k) => { - - - // Only trigger callback if terminal is not focused AND we're in editor view - // This has been deemed unnecessary since there are no real conflicts with the terminal - // The REPL shortcuts Ctrl+a|b|c|d are not used as application shortcuts and will - // only be triggered when the user has focused the REPL - // The code is left here for reference - // const activeElement = document.activeElement; - // const isTerminalFocused = activeElement.classList.contains('xterm-helper-textarea'); - // if (!isTerminalFocused) { callback(k); - // } }) }, From 9759ed752e82f4b308377c5d15d1e95664a57592 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Fri, 13 Dec 2024 12:38:24 +0100 Subject: [PATCH 21/22] Replaced Win/Linux Ctrl+Alt+R ignored shortcut with Ctrl+Alt+S Signed-off-by: ubi de feo --- backend/menu.js | 4 ++-- backend/shortcuts.js | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/menu.js b/backend/menu.js index 2d406f7..eb7810e 100644 --- a/backend/menu.js +++ b/backend/menu.js @@ -73,9 +73,9 @@ module.exports = function registerMenu(win, state = {}) { }, { label: 'Run selection', - accelerator: shortcuts.menu.RUN_SELECTION, + accelerator: isMac ? shortcuts.menu.RUN_SELECTION : shortcuts.menu.RUN_SELECTION_WL, enabled: state.isConnected && state.view === 'editor', - click: () => win.webContents.send('shortcut-cmd', shortcuts.global.RUN_SELECTION) + click: () => win.webContents.send('shortcut-cmd', (isMac ? shortcuts.global.RUN_SELECTION : shortcuts.global.RUN_SELECTION_WL)) }, { label: 'Stop', diff --git a/backend/shortcuts.js b/backend/shortcuts.js index b496200..e6b7159 100644 --- a/backend/shortcuts.js +++ b/backend/shortcuts.js @@ -5,6 +5,7 @@ module.exports = { SAVE: 'CommandOrControl+S', RUN: 'CommandOrControl+R', RUN_SELECTION: 'CommandOrControl+Alt+R', + RUN_SELECTION_WL: 'CommandOrControl+Alt+S', STOP: 'CommandOrControl+H', RESET: 'CommandOrControl+Shift+R', CLEAR_TERMINAL: 'CommandOrControl+L', @@ -18,6 +19,7 @@ module.exports = { SAVE: 'CmdOrCtrl+S', RUN: 'CmdOrCtrl+R', RUN_SELECTION: 'CmdOrCtrl+Alt+R', + RUN_SELECTION_WL: 'CmdOrCtrl+Alt+S', STOP: 'CmdOrCtrl+H', RESET: 'CmdOrCtrl+Shift+R', CLEAR_TERMINAL: 'CmdOrCtrl+L', From 6432226e5b70f5abf6370402e9de81c028e0eca1 Mon Sep 17 00:00:00 2001 From: ubi de feo Date: Fri, 13 Dec 2024 12:44:06 +0100 Subject: [PATCH 22/22] Amended shortcut handling in store.js Signed-off-by: ubi de feo --- ui/arduino/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/arduino/store.js b/ui/arduino/store.js index fddea1a..f2bd1b0 100644 --- a/ui/arduino/store.js +++ b/ui/arduino/store.js @@ -1432,7 +1432,7 @@ async function store(state, emitter) { if (state.view != 'editor') return runCode() } - if (key === shortcuts.RUN_SELECTION) { + if (key === shortcuts.RUN_SELECTION || key === shortcuts.RUN_SELECTION_WL) { if (state.view != 'editor') return runCodeSelection() }