diff --git a/src/web/lib/combokeys.js b/src/web/lib/combokeys.js index 2d79b4707..dc296487f 100644 --- a/src/web/lib/combokeys.js +++ b/src/web/lib/combokeys.js @@ -6,6 +6,7 @@ import { preventDefault } from './dom-events'; const AXIS_X = 'x'; const AXIS_Y = 'y'; const AXIS_Z = 'z'; +const AXIS_A = 'a'; const FORWARD = 1; const BACKWARD = -1; const OVERSHOOT_FACTOR = 10; // 10x @@ -286,6 +287,66 @@ const commandKeys = [ }, preventDefault: false }, + { // Jog A+ + keys: ']', + cmd: 'JOG', + payload: { + axis: AXIS_A, + direction: FORWARD, + factor: 1 + }, + preventDefault: false + }, + { // Jog A+ (undershoot) + keys: 'alt+]', + cmd: 'JOG', + payload: { + axis: AXIS_A, + direction: FORWARD, + factor: UNDERSHOOT_FACTOR + }, + preventDefault: false + }, + { // Jog A+ (overshoot) + keys: 'shift+]', + cmd: 'JOG', + payload: { + axis: AXIS_A, + direction: FORWARD, + factor: OVERSHOOT_FACTOR + }, + preventDefault: false + }, + { // Jog A- + keys: '[', + cmd: 'JOG', + payload: { + axis: AXIS_A, + direction: BACKWARD, + factor: 1 + }, + preventDefault: false + }, + { // Jog A- (undershoot) + keys: 'alt+[', + cmd: 'JOG', + payload: { + axis: AXIS_A, + direction: BACKWARD, + factor: UNDERSHOOT_FACTOR + }, + preventDefault: false + }, + { // Jog A- (overshoot) + keys: 'shift+[', + cmd: 'JOG', + payload: { + axis: AXIS_A, + direction: BACKWARD, + factor: OVERSHOOT_FACTOR + }, + preventDefault: false + }, { // Shuttle Zone -7 keys: ['ctrl', 'alt', 'shift', '7'].join('+'), cmd: 'SHUTTLE', diff --git a/src/web/store/index.js b/src/web/store/index.js index 1e2409ac6..05d013015 100644 --- a/src/web/store/index.js +++ b/src/web/store/index.js @@ -51,6 +51,8 @@ export const defaultState = { selectedDistance: '1', customDistance: 10 }, + wzero: 'G0 X0 Y0 Z0', // Go To Work Zero + mzero: 'G53 G0 X0 Y0 Z0', // Go To Machine Zero shuttle: { feedrateMin: 500, feedrateMax: 2000, diff --git a/src/web/styles/bootstrap-override.styl b/src/web/styles/bootstrap-override.styl index 9e226449f..ca21ef746 100644 --- a/src/web/styles/bootstrap-override.styl +++ b/src/web/styles/bootstrap-override.styl @@ -15,6 +15,11 @@ label { text-decoration: none; } +// Tooltip +.tooltip-inner { + max-width: 240px; +} + // font-size .btn, .dropdown-header, diff --git a/src/web/widgets/Axes/Axes.jsx b/src/web/widgets/Axes/Axes.jsx index c5fb7c177..252cecbaa 100644 --- a/src/web/widgets/Axes/Axes.jsx +++ b/src/web/widgets/Axes/Axes.jsx @@ -1,29 +1,21 @@ import PropTypes from 'prop-types'; import React from 'react'; -import Settings from './Settings'; -import Toolbar from './Toolbar'; import DisplayPanel from './DisplayPanel'; import ControlPanel from './ControlPanel'; -import { - MODAL_SETTINGS -} from './constants'; const Axes = (props) => { - const { state, actions } = props; + const { config, state, actions } = props; return (
- {state.modal.name === MODAL_SETTINGS && - - } - - - + +
); }; Axes.propTypes = { + config: PropTypes.object, state: PropTypes.object, actions: PropTypes.object }; diff --git a/src/web/widgets/Axes/AxesSettings.jsx b/src/web/widgets/Axes/AxesSettings.jsx deleted file mode 100644 index 9e9b6ba2c..000000000 --- a/src/web/widgets/Axes/AxesSettings.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import _ from 'lodash'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import i18n from '../../lib/i18n'; -import { - DEFAULT_AXES -} from './constants'; - -class AxesSettings extends Component { - static propTypes = { - axes: PropTypes.array - }; - static defaultProps = { - axes: DEFAULT_AXES - }; - - state = this.getInitialState(); - - getInitialState() { - const { axes } = this.props; - - return { axes }; - } - componentWillReceiveProps(nextProps) { - const { axes } = nextProps; - - this.setState({ axes }); - } - render() { - const axes = _(this.state.axes) - .union(DEFAULT_AXES) - .uniq() - .value(); - - return ( -
- -
-
- -
-
- -
-
- -
-
- -
-
-
- ); - } -} - -export default AxesSettings; diff --git a/src/web/widgets/Axes/ControlPanel.jsx b/src/web/widgets/Axes/ControlPanel.jsx index 3bd34c978..410340159 100644 --- a/src/web/widgets/Axes/ControlPanel.jsx +++ b/src/web/widgets/Axes/ControlPanel.jsx @@ -1,35 +1,21 @@ -import React, { Component, PropTypes } from 'react'; -import shallowCompare from 'react-addons-shallow-compare'; -import JogPad from './JogPad'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; +import Keypad from './Keypad'; import JogDistance from './JogDistance'; -import MotionButtonGroup from './MotionButtonGroup'; import styles from './index.styl'; -class ControlPanel extends Component { +class ControlPanel extends PureComponent { static propTypes = { + config: PropTypes.object, state: PropTypes.object, actions: PropTypes.object }; - shouldComponentUpdate(nextProps, nextState) { - return shallowCompare(this, nextProps, nextState); - } render() { return (
-
-
- -
-
- -
-
-
-
- -
-
+ +
); } diff --git a/src/web/widgets/Axes/DisplayPanel.jsx b/src/web/widgets/Axes/DisplayPanel.jsx index 6486014d0..cf4e41262 100644 --- a/src/web/widgets/Axes/DisplayPanel.jsx +++ b/src/web/widgets/Axes/DisplayPanel.jsx @@ -1,12 +1,13 @@ import classNames from 'classnames'; import includes from 'lodash/includes'; -import React, { Component, PropTypes } from 'react'; -import shallowCompare from 'react-addons-shallow-compare'; -import { DropdownButton, MenuItem } from 'react-bootstrap'; -import { in2mm } from '../../lib/units'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; import Anchor from '../../components/Anchor'; -import i18n from '../../lib/i18n'; +import Dropdown, { MenuItem } from '../../components/Dropdown'; import controller from '../../lib/controller'; +import ensureArray from '../../lib/ensure-array'; +import i18n from '../../lib/i18n'; +import { in2mm } from '../../lib/units'; import PositionInput from './PositionInput'; import { IMPERIAL_UNITS, @@ -14,8 +15,9 @@ import { } from '../../constants'; import styles from './index.styl'; -class DisplayPanel extends Component { +class DisplayPanel extends PureComponent { static propTypes = { + config: PropTypes.object, state: PropTypes.object, actions: PropTypes.object }; @@ -27,15 +29,11 @@ class DisplayPanel extends Component { showAPositionInput: false }; - shouldComponentUpdate(nextProps, nextState) { - return shallowCompare(this, nextProps, nextState); - } - handleSelect(eventKey) { - const data = eventKey; - if (data) { - controller.command('gcode', data); - } - } + handleSelect = (eventKey) => { + const commands = ensureArray(eventKey); + commands.forEach(command => controller.command('gcode', command)); + }; + render() { const { state, actions } = this.props; const { units, canClick, axes, machinePosition, workPosition } = state; @@ -61,7 +59,119 @@ class DisplayPanel extends Component { {i18n._('Axis')} {i18n._('Machine Position')} {i18n._('Work Position')} - {i18n._('Action')} + + + + + + + {i18n._('Temporary Offsets (G92)')} + + {i18n._('Zero Out Temporary Offsets (G92 X0 Y0 Z0)')} + + + {i18n._('Un-Zero Out Temporary Offsets (G92.1 X0 Y0 Z0)')} + + + {wcs === 'G54' && + {i18n._('Work Coordinate System (G54)')} + } + {wcs === 'G55' && + {i18n._('Work Coordinate System (G55)')} + } + {wcs === 'G56' && + {i18n._('Work Coordinate System (G56)')} + } + {wcs === 'G57' && + {i18n._('Work Coordinate System (G57)')} + } + {wcs === 'G58' && + {i18n._('Work Coordinate System (G58)')} + } + {wcs === 'G59' && + {i18n._('Work Coordinate System (G59)')} + } + + {i18n._('Go To Work Zero (G0 X0 Y0 Z0)')} + + {wcs === 'G54' && + + {i18n._('Zero Out Work Offsets (G10 L20 P1 X0 Y0 Z0)')} + + } + {wcs === 'G55' && + + {i18n._('Zero Out Work Offsets (G10 L20 P2 X0 Y0 Z0)')} + + } + {wcs === 'G56' && + + {i18n._('Zero Out Work Offsets (G10 L20 P3 X0 Y0 Z0)')} + + } + {wcs === 'G57' && + + {i18n._('Zero Out Work Offsets (G10 L20 P4 X0 Y0 Z0)')} + + } + {wcs === 'G58' && + + {i18n._('Zero Out Work Offsets (G10 L20 P5 X0 Y0 Z0)')} + + } + {wcs === 'G59' && + + {i18n._('Zero Out Work Offsets (G10 L20 P6 X0 Y0 Z0)')} + + } + + {i18n._('Machine Coordinate System (G53)')} + + {i18n._('Go To Machine Zero (G53 G0 X0 Y0 Z0)')} + + + + @@ -112,119 +222,118 @@ class DisplayPanel extends Component { } - - {wcs === 'G54' && - {i18n._('Work Coordinate System (G54)')} - } - {wcs === 'G55' && - {i18n._('Work Coordinate System (G55)')} - } - {wcs === 'G56' && - {i18n._('Work Coordinate System (G56)')} - } - {wcs === 'G57' && - {i18n._('Work Coordinate System (G57)')} - } - {wcs === 'G58' && - {i18n._('Work Coordinate System (G58)')} - } - {wcs === 'G59' && - {i18n._('Work Coordinate System (G59)')} - } - - {i18n._('Go To Work Zero On X Axis (G0 X0)')} - - {wcs === 'G54' && - - {i18n._('Zero Out Work X Axis (G10 L20 P1 X0)')} - - } - {wcs === 'G55' && - - {i18n._('Zero Out Work X Axis (G10 L20 P2 X0)')} - - } - {wcs === 'G56' && - - {i18n._('Zero Out Work X Axis (G10 L20 P3 X0)')} - - } - {wcs === 'G57' && - - {i18n._('Zero Out Work X Axis (G10 L20 P4 X0)')} - - } - {wcs === 'G58' && - - {i18n._('Zero Out Work X Axis (G10 L20 P5 X0)')} - - } - {wcs === 'G59' && - - {i18n._('Zero Out Work X Axis (G10 L20 P6 X0)')} - - } - - {i18n._('Machine Coordinate System (G53)')} - - {i18n._('Go To Machine Zero On X Axis (G53 G0 X0)')} - - - {i18n._('Temporary Offsets (G92)')} - - {i18n._('Zero Out Temporary X Axis (G92 X0)')} - - - {i18n._('Un-Zero Out Temporary X Axis (G92.1 X0)')} - - + + + + + {wcs === 'G54' && + {i18n._('Work Coordinate System (G54)')} + } + {wcs === 'G55' && + {i18n._('Work Coordinate System (G55)')} + } + {wcs === 'G56' && + {i18n._('Work Coordinate System (G56)')} + } + {wcs === 'G57' && + {i18n._('Work Coordinate System (G57)')} + } + {wcs === 'G58' && + {i18n._('Work Coordinate System (G58)')} + } + {wcs === 'G59' && + {i18n._('Work Coordinate System (G59)')} + } + + {i18n._('Go To Work Zero On X Axis (G0 X0)')} + + {wcs === 'G54' && + + {i18n._('Zero Out Work X Axis (G10 L20 P1 X0)')} + + } + {wcs === 'G55' && + + {i18n._('Zero Out Work X Axis (G10 L20 P2 X0)')} + + } + {wcs === 'G56' && + + {i18n._('Zero Out Work X Axis (G10 L20 P3 X0)')} + + } + {wcs === 'G57' && + + {i18n._('Zero Out Work X Axis (G10 L20 P4 X0)')} + + } + {wcs === 'G58' && + + {i18n._('Zero Out Work X Axis (G10 L20 P5 X0)')} + + } + {wcs === 'G59' && + + {i18n._('Zero Out Work X Axis (G10 L20 P6 X0)')} + + } + + {i18n._('Machine Coordinate System (G53)')} + + {i18n._('Go To Machine Zero On X Axis (G53 G0 X0)')} + + + {i18n._('Temporary Offsets (G92)')} + + {i18n._('Zero Out Temporary X Axis (G92 X0)')} + + + {i18n._('Un-Zero Out Temporary X Axis (G92.1 X0)')} + + + } @@ -275,119 +384,118 @@ class DisplayPanel extends Component { } - - {wcs === 'G54' && - {i18n._('Work Coordinate System (G54)')} - } - {wcs === 'G55' && - {i18n._('Work Coordinate System (G55)')} - } - {wcs === 'G56' && - {i18n._('Work Coordinate System (G56)')} - } - {wcs === 'G57' && - {i18n._('Work Coordinate System (G57)')} - } - {wcs === 'G58' && - {i18n._('Work Coordinate System (G58)')} - } - {wcs === 'G59' && - {i18n._('Work Coordinate System (G59)')} - } - - {i18n._('Go To Work Zero On Y Axis (G0 Y0)')} - - {wcs === 'G54' && - - {i18n._('Zero Out Work Y Axis (G10 L20 P1 Y0)')} - - } - {wcs === 'G55' && - - {i18n._('Zero Out Work Y Axis (G10 L20 P2 Y0)')} - - } - {wcs === 'G56' && - - {i18n._('Zero Out Work Y Axis (G10 L20 P3 Y0)')} - - } - {wcs === 'G57' && - - {i18n._('Zero Out Work Y Axis (G10 L20 P4 Y0)')} - - } - {wcs === 'G58' && - - {i18n._('Zero Out Work Y Axis (G10 L20 P5 Y0)')} - - } - {wcs === 'G59' && - - {i18n._('Zero Out Work Y Axis (G10 L20 P6 Y0)')} - - } - - {i18n._('Machine Coordinate System (G53)')} - - {i18n._('Go To Machine Zero On Y Axis (G53 G0 Y0)')} - - - {i18n._('Temporary Offsets (G92)')} - - {i18n._('Zero Out Temporary Y Axis (G92 Y0)')} - - - {i18n._('Un-Zero Out Temporary Y Axis (G92.1 Y0)')} - - + + + + + {wcs === 'G54' && + {i18n._('Work Coordinate System (G54)')} + } + {wcs === 'G55' && + {i18n._('Work Coordinate System (G55)')} + } + {wcs === 'G56' && + {i18n._('Work Coordinate System (G56)')} + } + {wcs === 'G57' && + {i18n._('Work Coordinate System (G57)')} + } + {wcs === 'G58' && + {i18n._('Work Coordinate System (G58)')} + } + {wcs === 'G59' && + {i18n._('Work Coordinate System (G59)')} + } + + {i18n._('Go To Work Zero On Y Axis (G0 Y0)')} + + {wcs === 'G54' && + + {i18n._('Zero Out Work Y Axis (G10 L20 P1 Y0)')} + + } + {wcs === 'G55' && + + {i18n._('Zero Out Work Y Axis (G10 L20 P2 Y0)')} + + } + {wcs === 'G56' && + + {i18n._('Zero Out Work Y Axis (G10 L20 P3 Y0)')} + + } + {wcs === 'G57' && + + {i18n._('Zero Out Work Y Axis (G10 L20 P4 Y0)')} + + } + {wcs === 'G58' && + + {i18n._('Zero Out Work Y Axis (G10 L20 P5 Y0)')} + + } + {wcs === 'G59' && + + {i18n._('Zero Out Work Y Axis (G10 L20 P6 Y0)')} + + } + + {i18n._('Machine Coordinate System (G53)')} + + {i18n._('Go To Machine Zero On Y Axis (G53 G0 Y0)')} + + + {i18n._('Temporary Offsets (G92)')} + + {i18n._('Zero Out Temporary Y Axis (G92 Y0)')} + + + {i18n._('Un-Zero Out Temporary Y Axis (G92.1 Y0)')} + + + } @@ -440,145 +548,124 @@ class DisplayPanel extends Component { } - - {wcs === 'G54' && - {i18n._('Work Coordinate System (G54)')} - } - {wcs === 'G55' && - {i18n._('Work Coordinate System (G55)')} - } - {wcs === 'G56' && - {i18n._('Work Coordinate System (G56)')} - } - {wcs === 'G57' && - {i18n._('Work Coordinate System (G57)')} - } - {wcs === 'G58' && - {i18n._('Work Coordinate System (G58)')} - } - {wcs === 'G59' && - {i18n._('Work Coordinate System (G59)')} - } - - {i18n._('Go To Work Zero On Z Axis (G0 Z0)')} - - {wcs === 'G54' && - - {i18n._('Zero Out Work Z Axis (G10 L20 P1 Z0)')} - - } - {wcs === 'G55' && - - {i18n._('Zero Out Work Z Axis (G10 L20 P2 Z0)')} - - } - {wcs === 'G56' && - - {i18n._('Zero Out Work Z Axis (G10 L20 P3 Z0)')} - - } - {wcs === 'G57' && - - {i18n._('Zero Out Work Z Axis (G10 L20 P4 Z0)')} - - } - {wcs === 'G58' && - - {i18n._('Zero Out Work Z Axis (G10 L20 P5 Z0)')} - - } - {wcs === 'G59' && - - {i18n._('Zero Out Work Z Axis (G10 L20 P6 Z0)')} - - } - - {i18n._('Machine Coordinate System (G53)')} - - {i18n._('Go To Machine Zero On Z Axis (G53 G0 Z0)')} - - - {i18n._('Temporary Offsets (G92)')} - - {i18n._('Zero Out Temporary Z Axis (G92 Z0)')} - - - {i18n._('Un-Zero Out Temporary Z Axis (G92.1 Z0)')} - - + + + + + {wcs === 'G54' && + {i18n._('Work Coordinate System (G54)')} + } + {wcs === 'G55' && + {i18n._('Work Coordinate System (G55)')} + } + {wcs === 'G56' && + {i18n._('Work Coordinate System (G56)')} + } + {wcs === 'G57' && + {i18n._('Work Coordinate System (G57)')} + } + {wcs === 'G58' && + {i18n._('Work Coordinate System (G58)')} + } + {wcs === 'G59' && + {i18n._('Work Coordinate System (G59)')} + } + + {i18n._('Go To Work Zero On Z Axis (G0 Z0)')} + + {wcs === 'G54' && + + {i18n._('Zero Out Work Z Axis (G10 L20 P1 Z0)')} + + } + {wcs === 'G55' && + + {i18n._('Zero Out Work Z Axis (G10 L20 P2 Z0)')} + + } + {wcs === 'G56' && + + {i18n._('Zero Out Work Z Axis (G10 L20 P3 Z0)')} + + } + {wcs === 'G57' && + + {i18n._('Zero Out Work Z Axis (G10 L20 P4 Z0)')} + + } + {wcs === 'G58' && + + {i18n._('Zero Out Work Z Axis (G10 L20 P5 Z0)')} + + } + {wcs === 'G59' && + + {i18n._('Zero Out Work Z Axis (G10 L20 P6 Z0)')} + + } + + {i18n._('Machine Coordinate System (G53)')} + + {i18n._('Go To Machine Zero On Z Axis (G53 G0 Z0)')} + + + {i18n._('Temporary Offsets (G92)')} + + {i18n._('Zero Out Temporary Z Axis (G92 Z0)')} + + + {i18n._('Un-Zero Out Temporary Z Axis (G92.1 Z0)')} + + + } {includes(axes, 'a') && - -
A
- { - const distance = actions.getJogDistance(); - actions.jog({ A: -distance }); - }} - > - - - { - const distance = actions.getJogDistance(); - actions.jog({ A: distance }); - }} - > - - - + A {machinePosition.a.split('.')[0]} . @@ -623,119 +710,118 @@ class DisplayPanel extends Component { } - - {wcs === 'G54' && - {i18n._('Work Coordinate System (G54)')} - } - {wcs === 'G55' && - {i18n._('Work Coordinate System (G55)')} - } - {wcs === 'G56' && - {i18n._('Work Coordinate System (G56)')} - } - {wcs === 'G57' && - {i18n._('Work Coordinate System (G57)')} - } - {wcs === 'G58' && - {i18n._('Work Coordinate System (G58)')} - } - {wcs === 'G59' && - {i18n._('Work Coordinate System (G59)')} - } - - {i18n._('Go To Work Zero On A Axis (G0 A0)')} - - {wcs === 'G54' && - - {i18n._('Zero Out Work A Axis (G10 L20 P1 A0)')} - - } - {wcs === 'G55' && - - {i18n._('Zero Out Work A Axis (G10 L20 P2 A0)')} - - } - {wcs === 'G56' && - - {i18n._('Zero Out Work A Axis (G10 L20 P3 A0)')} - - } - {wcs === 'G57' && - - {i18n._('Zero Out Work A Axis (G10 L20 P4 A0)')} - - } - {wcs === 'G58' && - - {i18n._('Zero Out Work A Axis (G10 L20 P5 A0)')} - - } - {wcs === 'G59' && - - {i18n._('Zero Out Work A Axis (G10 L20 P6 A0)')} - - } - - {i18n._('Machine Coordinate System (G53)')} - - {i18n._('Go To Machine Zero On A Axis (G53 G0 A0)')} - - - {i18n._('Temporary Offsets (G92)')} - - {i18n._('Zero Out Temporary A Axis (G92 A0)')} - - - {i18n._('Un-Zero Out Temporary A Axis (G92.1 A0)')} - - + + + + + {wcs === 'G54' && + {i18n._('Work Coordinate System (G54)')} + } + {wcs === 'G55' && + {i18n._('Work Coordinate System (G55)')} + } + {wcs === 'G56' && + {i18n._('Work Coordinate System (G56)')} + } + {wcs === 'G57' && + {i18n._('Work Coordinate System (G57)')} + } + {wcs === 'G58' && + {i18n._('Work Coordinate System (G58)')} + } + {wcs === 'G59' && + {i18n._('Work Coordinate System (G59)')} + } + + {i18n._('Go To Work Zero On A Axis (G0 A0)')} + + {wcs === 'G54' && + + {i18n._('Zero Out Work A Axis (G10 L20 P1 A0)')} + + } + {wcs === 'G55' && + + {i18n._('Zero Out Work A Axis (G10 L20 P2 A0)')} + + } + {wcs === 'G56' && + + {i18n._('Zero Out Work A Axis (G10 L20 P3 A0)')} + + } + {wcs === 'G57' && + + {i18n._('Zero Out Work A Axis (G10 L20 P4 A0)')} + + } + {wcs === 'G58' && + + {i18n._('Zero Out Work A Axis (G10 L20 P5 A0)')} + + } + {wcs === 'G59' && + + {i18n._('Zero Out Work A Axis (G10 L20 P6 A0)')} + + } + + {i18n._('Machine Coordinate System (G53)')} + + {i18n._('Go To Machine Zero On A Axis (G53 G0 A0)')} + + + {i18n._('Temporary Offsets (G92)')} + + {i18n._('Zero Out Temporary A Axis (G92 A0)')} + + + {i18n._('Un-Zero Out Temporary A Axis (G92.1 A0)')} + + + } diff --git a/src/web/widgets/Axes/JogDistance.jsx b/src/web/widgets/Axes/JogDistance.jsx index 6ed0dedc0..5a1590171 100644 --- a/src/web/widgets/Axes/JogDistance.jsx +++ b/src/web/widgets/Axes/JogDistance.jsx @@ -1,7 +1,7 @@ import _ from 'lodash'; import classNames from 'classnames'; -import React, { Component, PropTypes } from 'react'; -import shallowCompare from 'react-addons-shallow-compare'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; import i18n from '../../lib/i18n'; import RepeatButton from '../../components/RepeatButton'; import { @@ -11,15 +11,12 @@ import { } from './constants'; import styles from './index.styl'; -class JogDistance extends Component { +class JogDistance extends PureComponent { static propTypes = { state: PropTypes.object, actions: PropTypes.object }; - shouldComponentUpdate(nextProps, nextState) { - return shallowCompare(this, nextProps, nextState); - } render() { const { state, actions } = this.props; const { units, selectedDistance, customDistance } = state; @@ -54,7 +51,7 @@ class JogDistance extends Component { }; return ( -
+
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- - ); - } -} - -export default JogPad; diff --git a/src/web/widgets/Axes/Keypad.jsx b/src/web/widgets/Axes/Keypad.jsx new file mode 100644 index 000000000..be88d004f --- /dev/null +++ b/src/web/widgets/Axes/Keypad.jsx @@ -0,0 +1,434 @@ +import includes from 'lodash/includes'; +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; +import { Button } from '../../components/Buttons'; +import Dropdown, { MenuItem } from '../../components/Dropdown'; +import controller from '../../lib/controller'; +import ensureArray from '../../lib/ensure-array'; +import i18n from '../../lib/i18n'; +import styles from './index.styl'; + +class Keypad extends PureComponent { + static propTypes = { + config: PropTypes.objct, + state: PropTypes.object, + actions: PropTypes.object + }; + + handleSelect = (eventKey) => { + const commands = ensureArray(eventKey); + commands.forEach(command => controller.command('gcode', command)); + }; + + render() { + const { config, state, actions } = this.props; + const { canClick, axes, keypadJogging, selectedAxis } = state; + const canClickX = canClick && includes(axes, 'x'); + const canClickY = canClick && includes(axes, 'y'); + const canClickXY = canClickX && canClickY; + const canClickZ = canClick && includes(axes, 'z'); + const canClickA = canClick && includes(axes, 'a'); + const highlightX = canClickX && (keypadJogging || selectedAxis === 'x'); + const highlightY = canClickY && (keypadJogging || selectedAxis === 'y'); + const highlightZ = canClickZ && (keypadJogging || selectedAxis === 'z'); + const highlightA = canClickA && (keypadJogging || selectedAxis === 'a'); + + return ( +
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ + + + + + + + + {i18n._('Predefined Position')} + + + {i18n._('Go To Predefined Position 1 (G28)')} + + + {i18n._('Go To Predefined Position 2 (G30)')} + + + {i18n._('Set Predefined Position 1 (G28.1)')} + + + {i18n._('Set Predefined Position 2 (G30.1)')} + + + +
+
+
+
+
+ ); + } +} + +export default Keypad; diff --git a/src/web/widgets/Axes/KeypadOverlay.jsx b/src/web/widgets/Axes/KeypadOverlay.jsx new file mode 100644 index 000000000..c28f2720c --- /dev/null +++ b/src/web/widgets/Axes/KeypadOverlay.jsx @@ -0,0 +1,148 @@ +import React from 'react'; +import { Tooltip, OverlayTrigger } from 'react-bootstrap'; +import i18n from '../../lib/i18n'; + +const keypadTooltip = () => { + const styles = { + tooltip: { + fontFamily: 'Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif', + padding: 5 + }, + container: { + padding: 5 + }, + axisDirection: { + marginRight: 10 + }, + divider: { + borderTop: '1px solid #ccc', + marginTop: 5, + paddingTop: 5 + }, + kbd: { + border: '1px solid #aaa', + padding: '1px 4px', + fontFamily: 'sans-serif', + whiteSpace: 'nowrap' + }, + icon: { + minWidth: 10, + textAlign: 'center' + } + }; + + return ( + +
+
+
+ X+ + + + + + {i18n._('Right')} +
+
+ X- + + + + + {i18n._('Left')} +
+
+ Y+ + + + + + {i18n._('Up')} +
+
+ Y- + + + + + {i18n._('Down')} +
+
+ Z+ + + + + + {i18n._('Page Up')} +
+
+ Z- + + + + + {i18n._('Page Down')} +
+
+ A+ + + {' ] '} + + + {i18n._('Right Square Bracket')} +
+
+ A- + + {' [ '} + + + {i18n._('Left Square Bracket')} +
+
+
+
+
+
+
+
+
+
{i18n._('0.1x Move')}
+
+ {i18n._('Alt')} +
+
+
+
{i18n._('10x Move')}
+
+ {i18n._('⇧ Shift')} +
+
+
+
+
+
+ + ); +}; + +export default (props) => { + const { show, children } = { ...props }; + + if (!show) { + return children; + } + + return ( + + {children} + + ); +}; diff --git a/src/web/widgets/Axes/MotionButtonGroup.jsx b/src/web/widgets/Axes/MotionButtonGroup.jsx deleted file mode 100644 index 92279c5fe..000000000 --- a/src/web/widgets/Axes/MotionButtonGroup.jsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { Component, PropTypes } from 'react'; -import shallowCompare from 'react-addons-shallow-compare'; -import { DropdownButton, MenuItem } from 'react-bootstrap'; -import i18n from '../../lib/i18n'; -import controller from '../../lib/controller'; -import styles from './index.styl'; - -class MotionButtonGroup extends Component { - static propTypes = { - state: PropTypes.object, - actions: PropTypes.object - }; - - shouldComponentUpdate(nextProps, nextState) { - return shallowCompare(this, nextProps, nextState); - } - handleSelect(eventKey) { - const data = eventKey; - if (data) { - controller.command('gcode', data); - } - } - render() { - const { state } = this.props; - const { canClick } = state; - - return ( -
-
-
- - - {i18n._('Go To Predefined Position 1 (G28)')} - - - {i18n._('Go To Predefined Position 2 (G30)')} - - - - {i18n._('Set Predefined Position 1 (G28.1)')} - - - {i18n._('Set Predefined Position 2 (G30.1)')} - - -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
- ); - } -} - -export default MotionButtonGroup; diff --git a/src/web/widgets/Axes/PositionInput.jsx b/src/web/widgets/Axes/PositionInput.jsx index 5e9f77897..661aca0b9 100644 --- a/src/web/widgets/Axes/PositionInput.jsx +++ b/src/web/widgets/Axes/PositionInput.jsx @@ -1,6 +1,7 @@ -import React, { Component, PropTypes } from 'react'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; -class PositionInput extends Component { +class PositionInput extends PureComponent { static propTypes = { defaultValue: PropTypes.string, onOK: PropTypes.func.isRequired, diff --git a/src/web/widgets/Axes/Settings.jsx b/src/web/widgets/Axes/Settings.jsx deleted file mode 100644 index 564d769ff..000000000 --- a/src/web/widgets/Axes/Settings.jsx +++ /dev/null @@ -1,77 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import Modal from '../../components/Modal'; -import i18n from '../../lib/i18n'; -import AxesSettings from './AxesSettings'; -import ShuttleSettings from './ShuttleSettings'; - -class Settings extends Component { - static propTypes = { - state: PropTypes.object, - actions: PropTypes.object - }; - - saveChanges() { - const { actions } = this.props; - const { axes } = this.axesSettings.state; - const { feedrateMin, feedrateMax, hertz, overshoot } = this.shuttleSettings.state; - - actions.saveConfig({ - axes, - feedrateMin, - feedrateMax, - hertz, - overshoot - }); - } - render() { - const { state, actions } = this.props; - const { axes, feedrateMin, feedrateMax, hertz, overshoot } = state.modal.params; - - return ( - - - {i18n._('Axes Settings')} - - - { - this.axesSettings = node; - }} - axes={axes} - /> - { - this.shuttleSettings = node; - }} - feedrateMin={feedrateMin} - feedrateMax={feedrateMax} - hertz={hertz} - overshoot={overshoot} - /> - - - - - - - ); - } -} - -export default Settings; diff --git a/src/web/widgets/Axes/Settings/General.jsx b/src/web/widgets/Axes/Settings/General.jsx new file mode 100644 index 000000000..c268f8907 --- /dev/null +++ b/src/web/widgets/Axes/Settings/General.jsx @@ -0,0 +1,150 @@ +import get from 'lodash/get'; +import includes from 'lodash/includes'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; +import i18n from '../../../lib/i18n'; +import Validation from '../../../lib/react-validation'; + +class General extends PureComponent { + static propTypes = { + show: PropTypes.bool, + axes: PropTypes.array.isRequired, + wzero: PropTypes.string.isRequired, + mzero: PropTypes.string.isRequired + }; + static defaultProps = { + show: false + }; + + fields = { + axisX: null, + axisY: null, + axisZ: null, + axisA: null, + wzero: null, + mzero: null + }; + + get value() { + const axes = []; + this.fields.axisX.checked && axes.push('x'); + this.fields.axisY.checked && axes.push('y'); + this.fields.axisZ.checked && axes.push('z'); + this.fields.axisA.checked && axes.push('a'); + + return { + axes: axes, + wzero: get(this.fields.wzero, 'state.value'), + mzero: get(this.fields.mzero, 'state.value') + }; + } + render() { + const { show, axes, wzero, mzero } = this.props; + + return ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ { + this.form = node; + }} + onSubmit={(event) => { + event.preventDefault(); + }} + > + +
+ + { + this.fields.wzero = node; + }} + className="form-control" + rows="2" + name="wzero" + value={wzero} + placeholder="G0 X0 Y0 Z0" + validations={['required']} + /> +
+
+ + { + this.fields.mzero = node; + }} + className="form-control" + rows="2" + name="mzero" + value={mzero} + placeholder="G53 G0 X0 Y0 Z0" + validations={['required']} + /> +
+
+
+
+ ); + } +} + +export default General; diff --git a/src/web/widgets/Axes/Settings/ShuttleXpress.jsx b/src/web/widgets/Axes/Settings/ShuttleXpress.jsx new file mode 100644 index 000000000..16150d19c --- /dev/null +++ b/src/web/widgets/Axes/Settings/ShuttleXpress.jsx @@ -0,0 +1,110 @@ +import Slider from 'rc-slider'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; +import i18n from '../../../lib/i18n'; + +const FEEDRATE_RANGE = [100, 2500]; +const FEEDRATE_STEP = 50; +const OVERSHOOT_RANGE = [1, 1.5]; +const OVERSHOOT_STEP = 0.01; + +class ShuttleXpress extends PureComponent { + static propTypes = { + show: PropTypes.bool, + feedrateMin: PropTypes.number, + feedrateMax: PropTypes.number, + hertz: PropTypes.number, + overshoot: PropTypes.number + }; + static defaultProps = { + show: false + }; + + state = this.getInitialState(); + + getInitialState() { + const { + feedrateMin, + feedrateMax, + hertz, + overshoot + } = this.props; + + return { feedrateMin, feedrateMax, hertz, overshoot }; + } + componentWillReceiveProps(nextProps) { + const { + feedrateMin, + feedrateMax, + hertz, + overshoot + } = nextProps; + + this.setState({ feedrateMin, feedrateMax, hertz, overshoot }); + } + onFeedrateSliderChange(value) { + const [min, max] = value; + this.setState({ + feedrateMin: min, + feedrateMax: max + }); + } + onHertzChange(event) { + const { value } = event.target; + const hertz = Number(value); + this.setState({ hertz }); + } + onOvershootSliderChange(value) { + const overshoot = value; + this.setState({ overshoot }); + } + render() { + const { show } = this.props; + const { feedrateMin, feedrateMax, hertz, overshoot } = this.state; + + return ( +
+
+

+ {i18n._('Feed Rate Range: {{min}} - {{max}} mm/min', { min: feedrateMin, max: feedrateMax })} +

+ +
+
+ + +
+
+

{i18n._('Distance Overshoot: {{overshoot}}x', { overshoot: overshoot })}

+ +
+
+ ); + } +} + +export default ShuttleXpress; diff --git a/src/web/widgets/Axes/Settings/index.jsx b/src/web/widgets/Axes/Settings/index.jsx new file mode 100644 index 000000000..3078cfea7 --- /dev/null +++ b/src/web/widgets/Axes/Settings/index.jsx @@ -0,0 +1,147 @@ +import noop from 'lodash/noop'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; +import Modal from '../../../components/Modal'; +import { Nav, NavItem } from '../../../components/Navs'; +import ensureArray from '../../../lib/ensure-array'; +import i18n from '../../../lib/i18n'; +import General from './General'; +import ShuttleXpress from './ShuttleXpress'; +import { + DEFAULT_AXES +} from '../constants'; + +class Settings extends PureComponent { + static propTypes = { + config: PropTypes.object.isRequired, + onSave: PropTypes.func, + onCancel: PropTypes.func + }; + static defaultProps = { + onSave: noop, + onCancel: noop + }; + + config = this.props.config; + node = { + general: null, + shuttleXpress: null + }; + state = { + activeKey: 'general' + }; + + load = () => { + return { + // General + general: { + axes: this.config.get('axes', DEFAULT_AXES), + wzero: this.config.get('wzero'), + mzero: this.config.get('mzero') + }, + // ShuttleXpress + shuttleXpress: { + feedrateMin: this.config.get('shuttle.feedrateMin'), + feedrateMax: this.config.get('shuttle.feedrateMax'), + hertz: this.config.get('shuttle.hertz'), + overshoot: this.config.get('shuttle.overshoot') + } + }; + }; + save = () => { + // General + const { axes = DEFAULT_AXES, wzero, mzero } = this.node.general.value; + this.config.replace('axes', ensureArray(axes)); + this.config.set('wzero', wzero); + this.config.set('mzero', mzero); + + // ShuttleXpress + const { feedrateMin, feedrateMax, hertz, overshoot } = this.node.shuttleXpress.state; + this.config.set('shuttle.feedrateMin', feedrateMin); + this.config.set('shuttle.feedrateMax', feedrateMax); + this.config.set('shuttle.hertz', hertz); + this.config.set('shuttle.overshoot', overshoot); + }; + + render() { + const { general, shuttleXpress } = this.load(); + + return ( + + + {i18n._('Axes Settings')} + + + +
+ { + this.node.general = node; + }} + show={this.state.activeKey === 'general'} + axes={general.axes} + wzero={general.wzero} + mzero={general.mzero} + /> + { + this.node.shuttleXpress = node; + }} + show={this.state.activeKey === 'shuttleXpress'} + feedrateMin={shuttleXpress.feedrateMin} + feedrateMax={shuttleXpress.feedrateMax} + hertz={shuttleXpress.hertz} + overshoot={shuttleXpress.overshoot} + /> +
+
+ + + + +
+ ); + } +} + +export default Settings; diff --git a/src/web/widgets/Axes/ShuttleSettings.jsx b/src/web/widgets/Axes/ShuttleSettings.jsx deleted file mode 100644 index 605514960..000000000 --- a/src/web/widgets/Axes/ShuttleSettings.jsx +++ /dev/null @@ -1,112 +0,0 @@ -import Slider from 'rc-slider'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import i18n from '../../lib/i18n'; - -const FEEDRATE_RANGE = [100, 2500]; -const FEEDRATE_STEP = 50; -const OVERSHOOT_RANGE = [1, 1.5]; -const OVERSHOOT_STEP = 0.01; - -class ShuttleSettings extends Component { - static propTypes = { - feedrateMin: PropTypes.number, - feedrateMax: PropTypes.number, - hertz: PropTypes.number, - overshoot: PropTypes.number - }; - - state = this.getInitialState(); - - getInitialState() { - const { - feedrateMin, - feedrateMax, - hertz, - overshoot - } = this.props; - - return { feedrateMin, feedrateMax, hertz, overshoot }; - } - componentWillReceiveProps(nextProps) { - const { - feedrateMin, - feedrateMax, - hertz, - overshoot - } = nextProps; - - this.setState({ feedrateMin, feedrateMax, hertz, overshoot }); - } - onFeedrateSliderChange(value) { - const [min, max] = value; - this.setState({ - feedrateMin: min, - feedrateMax: max - }); - } - onHertzChange(event) { - const { value } = event.target; - const hertz = Number(value); - this.setState({ hertz }); - } - onOvershootSliderChange(value) { - const overshoot = value; - this.setState({ overshoot }); - } - render() { - const { feedrateMin, feedrateMax, hertz, overshoot } = this.state; - - return ( -
-
-

{i18n._('Shuttle Settings')}

-
-
-
-

- {i18n._('Feed Rate Range: {{min}} - {{max}} mm/min', { min: feedrateMin, max: feedrateMax })} -

- -
-
- - -
-
-

- {i18n._('Distance Overshoot: {{overshoot}}x', { overshoot: overshoot })} -

- -
-
-
- ); - } -} - -export default ShuttleSettings; diff --git a/src/web/widgets/Axes/index.jsx b/src/web/widgets/Axes/index.jsx index 2775e1b37..a93fdcfde 100644 --- a/src/web/widgets/Axes/index.jsx +++ b/src/web/widgets/Axes/index.jsx @@ -3,8 +3,8 @@ import includes from 'lodash/includes'; import map from 'lodash/map'; import mapValues from 'lodash/mapValues'; import classNames from 'classnames'; -import React, { Component, PropTypes } from 'react'; -import shallowCompare from 'react-addons-shallow-compare'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; import Widget from '../../components/Widget'; import combokeys from '../../lib/combokeys'; import controller from '../../lib/controller'; @@ -13,6 +13,8 @@ import i18n from '../../lib/i18n'; import { in2mm, mm2in } from '../../lib/units'; import WidgetConfig from '../WidgetConfig'; import Axes from './Axes'; +import KeypadOverlay from './KeypadOverlay'; +import Settings from './Settings'; import ShuttleControl from './ShuttleControl'; import { // Units @@ -79,7 +81,7 @@ const normalizeToRange = (n, min, max) => { return n; }; -class AxesWidget extends Component { +class AxesWidget extends PureComponent { static propTypes = { widgetId: PropTypes.string.isRequired, onFork: PropTypes.func.isRequired, @@ -128,33 +130,6 @@ class AxesWidget extends Component { } }); }, - loadConfig: () => { - return { - axes: this.config.get('axes'), - feedrateMin: this.config.get('shuttle.feedrateMin'), - feedrateMax: this.config.get('shuttle.feedrateMax'), - hertz: this.config.get('shuttle.hertz'), - overshoot: this.config.get('shuttle.overshoot') - }; - }, - saveConfig: (data) => { - const { - axes, - feedrateMin, - feedrateMax, - hertz, - overshoot - } = { ...data }; - - this.config.replace('axes', axes); // array - this.config.set('shuttle.feedrateMin', feedrateMin); - this.config.set('shuttle.feedrateMax', feedrateMax); - this.config.set('shuttle.hertz', hertz); - this.config.set('shuttle.overshoot', overshoot); - - // Update axes - this.setState({ axes: axes }); - }, getJogDistance: () => { const { units } = this.state; const selectedDistance = this.config.get('jog.selectedDistance'); @@ -466,9 +441,6 @@ class AxesWidget extends Component { this.removeControllerEvents(); this.removeShuttleControlEvents(); } - shouldComponentUpdate(nextProps, nextState) { - return shallowCompare(this, nextProps, nextState); - } componentDidUpdate(prevProps, prevState) { const { units, @@ -618,6 +590,7 @@ class AxesWidget extends Component { const { minimized, isFullscreen } = this.state; const { units, machinePosition, workPosition } = this.state; const isForkedWidget = widgetId.match(/\w+:[\w\-]+/); + const config = this.config; const state = { ...this.state, // Determine if the motion button is clickable @@ -649,11 +622,22 @@ class AxesWidget extends Component { } + + + + + { - const data = actions.loadConfig(); - actions.openModal(MODAL_SETTINGS, data); + actions.openModal(MODAL_SETTINGS); }} > @@ -715,7 +699,18 @@ class AxesWidget extends Component { { [styles.hidden]: minimized } )} > - + {state.modal.name === MODAL_SETTINGS && + { + const axes = config.get('axes', DEFAULT_AXES); + this.setState({ axes: axes }); + actions.closeModal(); + }} + onCancel={actions.closeModal} + /> + } + ); diff --git a/src/web/widgets/Axes/index.styl b/src/web/widgets/Axes/index.styl index e68152166..3e88a9c48 100644 --- a/src/web/widgets/Axes/index.styl +++ b/src/web/widgets/Axes/index.styl @@ -13,6 +13,7 @@ .row-space { margin-bottom: 5px; + margin-right: -5px; } .col-space { margin-right: 5px; @@ -111,8 +112,25 @@ } .action { width: 1%; - padding: 0 4px; + padding: 0; text-align: center; + + button.action-dropdown { + width: auto; + border-radius: 0; + + > * { + color: #666; + } + + &:hover { + background-color: #e6e6e6; + + > * { + color: #333; + } + } + } } } @@ -120,65 +138,54 @@ margin: 0; } -.jog-pad { - button[class^="jog-"], - button[class*=" jog-"] { +.keypad { + button.btn-keypad { font-size: 16px; padding: 0; - min-width: 35px; width: 100%; line-height: 30px; text-align: center; vertical-align: middle; - box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); + &:active, &.active { box-shadow: 0 0 2px rgba(0, 0, 0, 0.1); transform: translate(1px, 1px); } - } - - .jog-direction-highlight { - button[class^="jog-"], - button[class*=" jog-"] { - background-color: rgba(240, 240, 240, .8); - box-shadow: 1px 1px 2px rgba(0, 0, 0, .2); - border-color: rgba(0, 0, 0, .3); - &:hover { - background-color: rgba(0, 0, 0, .2); - } - - &:active, - &.active { - box-shadow: 0 0 2px rgba(0, 0, 0, .2); - transform: translate(1px, 1px); - } + .keypad-text + .keypad-subscript > * { + font-size: 60%; } - .jog-text { - font-weight: 500; + :global { + i.fa, + span.fa { + color: #333; + } } } -} -.motion-controls { - :global { - .btn, - .btn-group { - width: 100%; + button.btn-keypad.highlight { + background-color: rgba(240, 240, 240, .8); + background-image: none; + box-shadow: 1px 1px 2px rgba(0, 0, 0, .2); + border-color: rgba(0, 0, 0, .4); + + &:hover, + &.hover { + background-color: rgba(0, 0, 0, .1); } - } - button { - width: 100%; - line-height: 30px; - padding: 0 5px; + &:active, + &.active { + box-shadow: 0 0 2px rgba(0, 0, 0, .2); + transform: translate(1px, 1px); + } } } -.jog-distance-control { +.jog-distance { :global { .input-group { .input-group-btn:not(:first-child):not(:last-child) {