diff --git a/src/kiri/app/menubar.js b/src/kiri/app/menubar.js index f4344030..d1a264ec 100644 --- a/src/kiri/app/menubar.js +++ b/src/kiri/app/menubar.js @@ -1,293 +1,221 @@ /** Copyright Stewart Allen -- All Rights Reserved */ -import { $ } from '../../moto/webui.js'; +import { $, h } from '../../moto/webui.js'; -const MENUBAR_HTML = ` - - -
- - -
-
-
- - -
-
-
- - -
-
- - - -
-
-
- - -
-
-
- -
-
-
-
- - -
-
-
- - -
-
- - -
-
- - -
-
-
- - -
-
-
-
- - -
-
-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
-
- - -
-
- - -
-
- - -
-
-
- - -
-
-
-
- - -
-
-
- - -
-
- - -
-
-
- -
-
- -
-
-
- - -
-
- - -
-
-
-
- -
- -
-
- -
-
- -
- -
- -
- -
- -
- -
- -
-
-
- -
-
-
-
- - - - - - - - - -
- -
-
-
-
-
- - - - -
-
-
- - -
-
- - -
-
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
-
- -
-
- -
-
-
- -
-
-
-
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- -
-
- -
-
-
-
- - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; +const { div, span, label, input, button, i, hr } = h; + +function icon(cls) { + return i({ class: cls }); +} + +function on(actions, id) { + return actions && typeof actions[id] === 'function' ? { onclick: actions[id] } : {}; +} + +function menuItem(actions, { id, lk, xlk, text, title, iconClass, className, children }) { + const attr = { + ...(id ? { id } : {}), + ...(title ? { title } : {}), + ...(className ? { class: className } : {}), + ...on(actions, id) + }; + const lblAttr = { + ...(lk ? { lk } : {}), + ...(xlk ? { xlk } : {}) + }; + return div(attr, [ + text !== undefined ? label({ ...lblAttr, _: text }) : undefined, + iconClass ? span([icon(iconClass)]) : undefined, + children + ].filter(v => v !== undefined)); +} + +function dropMenu(actions, side, items) { + return div({ class: `top-menu-drop top-menu-${side}` }, [ + div({ class: 'content' }, items) + ]); +} + +function topMenu(actions, { text, lk, iconClass, side = 'left', right = false, items }) { + return span({ class: right ? 'menu-right' : undefined }, [ + text !== undefined ? label({ ...(lk ? { lk } : {}), _: text }) : undefined, + iconClass ? icon(iconClass) : undefined, + dropMenu(actions, side, items) + ]); +} + +function toolbarToolNozzle() { + return span({ id: 'tool-nozzle' }, [ + i({ class: 'fas fa-location-pin', title: 'extruder' }), + div({ id: 'ft-nozzle', class: 'f-col pop' }) + ]); +} + +function toolbarToolRotate(actions) { + return span({ id: 'tool-rotate' }, [ + i({ class: 'fas fa-rotate-right', title: 'rotate selection' }), + div({ id: 'ft-rotate', class: 'grid pop' }, [ + div({ id: 'rot_x_lt', ...on(actions, 'rot_x_lt') }, icon('fas fa-chevron-left')), + label({ _: 'X' }), + div({ id: 'rot_x_gt', ...on(actions, 'rot_x_gt') }, icon('fas fa-chevron-right')), + input({ id: 'rot_x', class: 'value center', size: '6', value: '90' }), + div({ id: 'rot_y_lt', ...on(actions, 'rot_y_lt') }, icon('fas fa-chevron-left')), + label({ _: 'Y' }), + div({ id: 'rot_y_gt', ...on(actions, 'rot_y_gt') }, icon('fas fa-chevron-right')), + input({ id: 'rot_y', class: 'value center', size: '6', value: '90' }), + div({ id: 'rot_z_lt', ...on(actions, 'rot_z_lt') }, icon('fas fa-chevron-left')), + label({ _: 'Z' }), + div({ id: 'rot_z_gt', ...on(actions, 'rot_z_gt') }, icon('fas fa-chevron-right')), + input({ id: 'rot_z', class: 'value center', size: '6', value: '90' }), + div({ class: 'buttons f-row' }, [ + button({ id: 'unrotate', class: 'grow', lk: 'reset', _: 'reset', ...on(actions, 'unrotate') }) + ]) + ]) + ]); +} + +function toolbarToolScale(actions) { + return span({ id: 'tool-scale' }, [ + i({ class: 'fas fa-expand', title: 'scale or resize selection' }), + div({ id: 'ft-scale', class: 'grid pop' }, [ + div([label({ _: 'X' }), input({ id: 'lock_x', type: 'checkbox', _checked: true })]), + div([label({ _: 'Y' }), input({ id: 'lock_y', type: 'checkbox', _checked: true })]), + div([label({ _: 'Z' }), input({ id: 'lock_z', type: 'checkbox', _checked: true })]), + label({ id: 'lab-axis', lk: 'axis', _: 'axis', ...on(actions, 'lab-axis') }), + input({ id: 'size_x', size: '8', class: 'value' }), + input({ id: 'size_y', size: '8', class: 'value' }), + input({ id: 'size_z', size: '8', class: 'value' }), + label({ id: 'lab-size', lk: 'size', _: 'size' }), + input({ id: 'scale_x', size: '8', class: 'value', value: '1' }), + input({ id: 'scale_y', size: '8', class: 'value', value: '1' }), + input({ id: 'scale_z', size: '8', class: 'value', value: '1' }), + label({ id: 'lab-scale', lk: 'scale', _: 'scale', ...on(actions, 'lab-scale') }), + div({ class: 'buttons f-row' }, [ + button({ id: 'scale-reset', class: 'grow j-center', _: 'reset', ...on(actions, 'scale-reset') }) + ]) + ]) + ]); +} + +function content(actions) { + return [ + div({ class: 'menubar-appname', _: 'Kiri:Moto' }), + div({ class: 'menubar-separator' }), + div({ class: 'f-row top-menu grow' }, [ + topMenu(actions, { + text: 'files', lk: 'fe_menu', items: [ + menuItem(actions, { id: 'file-new', lk: 'new', text: 'new', iconClass: 'fas fa-file' }), + hr(), + menuItem(actions, { id: 'file-recent', lk: 'recent', text: 'recent', iconClass: 'fas fa-list' }), + menuItem(actions, { + id: 'file-import', lk: 'import', text: 'import', iconClass: 'fas fa-file-upload', children: + input({ id: 'load-file', type: 'file', name: 'loadme', style: 'display:none', accept: '.km,.kmz,.stl,.obj,.svg,.png,.jpg,.jpeg,.gcode,.nc' }) + }), + hr(), + menuItem(actions, { id: 'app-export', lk: 'export-ws', text: 'export work', iconClass: 'fas fa-download' }), + hr(), + menuItem(actions, { id: 'app-quit', lk: 'quit', text: 'quit', className: 'hide' }) + ] + }), + topMenu(actions, { + text: 'view', lk: 'vu_menu', items: [ + menuItem(actions, { id: 'view-fit', lk: 'contents', text: 'contents', iconClass: 'fas fa-arrows-to-circle' }), + menuItem(actions, { id: 'view-home', lk: 'home', text: 'home', iconClass: 'fas fa-home' }), + menuItem(actions, { id: 'view-top', lk: 'top', text: 'top', iconClass: 'fas fa-square' }), + hr(), + menuItem(actions, { id: 'app-xpnd', lk: 'fullscreen', text: 'fullscreen', iconClass: 'fas fa-maximize' }) + ] + }), + topMenu(actions, { + text: 'Align', lk: 'al_menu', items: [ + menuItem(actions, { id: 'context-setfocus', lk: 'focus', text: 'focal point', iconClass: 'fas fa-eye' }), + menuItem(actions, { id: 'context-layflat', lk: 'face-down', text: 'face down', iconClass: 'fas fa-home' }), + menuItem(actions, { id: 'context-lefty', lk: 'face-left', text: 'face left', iconClass: 'fas fa-maximize' }) + ] + }), + topMenu(actions, { + text: 'render', lk: 're_menu', items: [ + menuItem(actions, { id: 'render-solid', xlk: 'focus', text: 'solid', iconClass: 'fas fa-square' }), + menuItem(actions, { id: 'render-wire', xlk: 'face-down', text: 'wireframe', iconClass: 'fas fa-border-all' }), + menuItem(actions, { id: 'render-ghost', xlk: 'face-left', text: 'transparent', iconClass: 'fas fa-border-none' }), + hr(), + menuItem(actions, { id: 'render-edges', xlk: 'face-left', text: 'toggle edges', iconClass: 'fa-regular fa-square' }) + ] + }), + topMenu(actions, { + text: 'selection', lk: 'sx_menu', items: [ + menuItem(actions, { id: 'context-mirror', xlk: 'rc_mirr-left', text: 'mirror', iconClass: 'fas fa-arrows-left-right-to-line' }), + menuItem(actions, { id: 'context-duplicate', xlk: 'rc_dupl', text: 'duplicate', iconClass: 'fas fa-copy' }), + hr(), + menuItem(actions, { id: 'mesh-merge', xlk: 'rc_merg', text: 'merge meshes' }), + menuItem(actions, { id: 'mesh-split', xlk: 'rc_splt-down', text: 'isolate meshes' }), + hr(), + menuItem(actions, { id: 'mesh-export-obj', lk: 'export-obj', text: 'save as OBJ', iconClass: 'fas fa-dice-d20' }), + menuItem(actions, { id: 'mesh-export-stl', lk: 'export-stl', text: 'save as STL', iconClass: 'fas fa-dice-d20' }) + ] + }), + div({ class: 'menubar-separator' }), + div({ class: 'f-row top-menu' }, [ + toolbarToolNozzle(), + toolbarToolRotate(actions), + toolbarToolScale(actions) + ]), + div({ class: 'grow' }), + div({ class: 'menubar-mode', id: 'app-mode' }), + div({ class: 'menubar-separator' }), + topMenu(actions, { + text: 'mode', lk: 'mo_menu', side: 'right', right: true, items: [ + menuItem(actions, { id: 'mode-fdm', text: 'FDM', title: '3D Additive Printing Processes', iconClass: 'fas fa-layer-group' }), + menuItem(actions, { id: 'mode-cam', text: 'CNC', title: 'CNC Mills and Subtractive Processes', iconClass: 'fas fa-bore-hole' }), + menuItem(actions, { id: 'mode-sla', text: 'SLA', title: 'mSLA Resin Printing', iconClass: 'fas fa-cube' }), + hr(), + menuItem(actions, { id: 'mode-laser', text: 'Laser', title: 'Laser Cutting and Engraving', iconClass: 'fas fa-bolt' }), + menuItem(actions, { id: 'mode-wjet', text: 'Water', title: 'WaterJet Cutting', iconClass: 'fas fa-location-pin' }), + menuItem(actions, { id: 'mode-wedm', text: 'Wire', title: 'Wire EDM Cutting', iconClass: 'fas fa-ellipsis-vertical' }), + menuItem(actions, { id: 'mode-drag', text: 'Drag', title: 'Drag Knife Cutting', iconClass: 'fas fa-caret-left' }) + ] + }), + topMenu(actions, { + text: 'info', lk: 'info', side: 'right', right: true, items: [ + menuItem(actions, { id: 'app-help', lk: 'help', text: 'help' }), + menuItem(actions, { id: 'app-don8', lk: 'donate', text: 'donate' }), + hr(), + menuItem(actions, { children: label({ id: 'app-info', _: 'version' }) }) + ] + }), + topMenu(actions, { + text: 'setup', lk: 'su_menu', side: 'right', right: true, items: [ + menuItem(actions, { id: 'set-device', lk: 'machines', text: 'machines', iconClass: 'fas fa-cube' }), + menuItem(actions, { id: 'set-profs', lk: 'profs', text: 'profiles', iconClass: 'fas fa-sliders-h' }), + menuItem(actions, { id: 'set-tools', lk: 'tools', text: 'tools', iconClass: 'fas fa-tools' }), + menuItem(actions, { id: 'set-prefs', lk: 'prefs', text: 'prefs', iconClass: 'fa-solid fa-square-check' }), + hr(), + menuItem(actions, { id: 'install', lk: 'install', text: 'install' }), + menuItem(actions, { id: 'uninstall', lk: 'uninstall', text: 'uninstall', className: 'hide' }) + ] + }), + topMenu(actions, { + iconClass: 'fas fa-language', side: 'right', right: true, items: [ + menuItem(actions, { children: label({ id: 'lset-zh', _: '简体中文' }) }), + menuItem(actions, { children: label({ id: 'lset-da', _: 'dansk' }) }), + menuItem(actions, { children: label({ id: 'lset-de', _: 'deutsch' }) }), + menuItem(actions, { children: label({ id: 'lset-en', _: 'english' }) }), + menuItem(actions, { children: label({ id: 'lset-es', _: 'español' }) }), + menuItem(actions, { children: label({ id: 'lset-fr', _: 'français' }) }), + menuItem(actions, { children: label({ id: 'lset-pl', class: 'nocap', _: 'polski' }) }), + menuItem(actions, { children: label({ id: 'lset-pt', _: 'português' }) }) + ] + }) + ]) + ]; +} export const menubar = { - build() { + build(actions = {}) { const node = $('menubar'); if (!node) { return; } - node.innerHTML = MENUBAR_HTML; + h.bind(node, content(actions)); } }; diff --git a/src/kiri/app/toolbar.js b/src/kiri/app/toolbar.js index d29d2363..2f374301 100644 --- a/src/kiri/app/toolbar.js +++ b/src/kiri/app/toolbar.js @@ -3,8 +3,8 @@ import { menubar } from './menubar.js'; const toolbar = { - build() { - menubar.build(); + build(actions) { + menubar.build(actions); } };