Skip to content

Commit

Permalink
Add support for displaying current controller state
Browse files Browse the repository at this point in the history
  • Loading branch information
cheton committed Feb 24, 2017
1 parent 62818d4 commit 705de69
Show file tree
Hide file tree
Showing 21 changed files with 477 additions and 184 deletions.
51 changes: 51 additions & 0 deletions src/web/widgets/Grbl/ControllerState.jsx
@@ -0,0 +1,51 @@
import React, { Component, PropTypes } from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import Modal from '../../components/Modal';
import i18n from '../../lib/i18n';
import {
MODAL_CONTROLLER_STATE
} from './constants';
//import styles from './index.styl';

class ControllerState extends Component {
static propTypes = {
state: PropTypes.object,
actions: PropTypes.object
};

shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
render() {
const { state, actions } = this.props;
const { modal } = state;
const show = (modal.name === MODAL_CONTROLLER_STATE);
const maxHeight = Math.max(window.innerHeight / 2, 200);

return (
<Modal
onClose={actions.closeModal}
show={show}
size="lg"
>
<Modal.Header>
<Modal.Title>{i18n._('Controller State')}</Modal.Title>
</Modal.Header>
<Modal.Body style={{ maxHeight: maxHeight }}>
<pre><code>{JSON.stringify(state.controller.state, null, 2)}</code></pre>
</Modal.Body>
<Modal.Footer>
<button
type="button"
className="btn btn-default"
onClick={actions.closeModal}
>
{i18n._('Close')}
</button>
</Modal.Footer>
</Modal>
);
}
}

export default ControllerState;
2 changes: 2 additions & 0 deletions src/web/widgets/Grbl/Grbl.jsx
Expand Up @@ -6,6 +6,7 @@ import mapGCodeToText from '../../lib/gcode-text';
import i18n from '../../lib/i18n';
import Panel from '../../components/Panel';
import Toggler from '../../components/Toggler';
import ControllerState from './ControllerState';
import Toolbar from './Toolbar';
import Overrides from './Overrides';
import styles from './index.styl';
Expand Down Expand Up @@ -46,6 +47,7 @@ class Grbl extends Component {

return (
<div>
<ControllerState state={state} actions={actions} />
<Toolbar state={state} actions={actions} />
{!_.isEmpty(ov) &&
<Overrides state={state} actions={actions} />
Expand Down
112 changes: 45 additions & 67 deletions src/web/widgets/Grbl/Toolbar.jsx
@@ -1,9 +1,13 @@
import classNames from 'classnames';
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';
import {
MODAL_CONTROLLER_STATE
} from './constants';

class Toolbar extends Component {
static propTypes = {
Expand All @@ -15,7 +19,7 @@ class Toolbar extends Component {
return shallowCompare(this, nextProps, nextState);
}
render() {
const { state } = this.props;
const { state, actions } = this.props;
const { canClick } = state;

return (
Expand All @@ -24,67 +28,13 @@ class Toolbar extends Component {
<button
type="button"
className="btn btn-default"
title={i18n._('Feedhold (!)')}
onClick={() => controller.command('feedhold')}
disabled={!canClick}
>
!
</button>
<button
type="button"
className="btn btn-default"
title={i18n._('Cycle Start (~)')}
onClick={() => controller.command('cyclestart')}
disabled={!canClick}
>
~
</button>
</div>
<div className="btn-group btn-group-xs" style={{ marginLeft: 10 }}>
<button
type="button"
className="btn btn-default"
title={i18n._('Check G-code Mode ($C)')}
onClick={() => controller.command('check')}
disabled={!canClick}
>
$C
</button>
<button
type="button"
className="btn btn-default"
title={i18n._('Homing ($H)')}
onClick={() => controller.command('homing')}
disabled={!canClick}
>
$H
</button>
<button
type="button"
className="btn btn-default"
title={i18n._('Sleep ($SLP)')}
onClick={() => controller.command('sleep')}
disabled={!canClick}
>
$SLP
</button>
<button
type="button"
className="btn btn-default"
title={i18n._('Kill Alarm Lock ($X)')}
onClick={() => controller.command('unlock')}
disabled={!canClick}
>
$X
</button>
<button
type="button"
className="btn btn-default"
title={i18n._('Reset (^x)')}
onClick={() => controller.command('reset')}
disabled={!canClick}
onClick={() => {
actions.openModal(MODAL_CONTROLLER_STATE);
}}
>
^x
<i className={classNames(styles.icon, styles.iconStatusReport)} />
<span className="space space-sm" />
{i18n._('Current State')}
</button>
</div>
<div className="btn-group pull-right">
Expand All @@ -96,12 +46,40 @@ class Toolbar extends Component {
pullRight
disabled={!canClick}
>
<MenuItem onSelect={() => controller.writeln('$')} disabled={!canClick}>{i18n._('Help ($)')}</MenuItem>
<MenuItem onSelect={() => controller.writeln('$$')} disabled={!canClick}>{i18n._('Settings ($$)')}</MenuItem>
<MenuItem onSelect={() => controller.writeln('$#')} disabled={!canClick}>{i18n._('View G-code Parameters ($#)')}</MenuItem>
<MenuItem onSelect={() => controller.writeln('$G')} disabled={!canClick}>{i18n._('View G-code Parser State ($G)')}</MenuItem>
<MenuItem onSelect={() => controller.writeln('$I')} disabled={!canClick}>{i18n._('View Build Info ($I)')}</MenuItem>
<MenuItem onSelect={() => controller.writeln('$N')} disabled={!canClick}>{i18n._('View Startup Blocks ($N)')}</MenuItem>
<MenuItem onSelect={() => controller.write('?')} disabled={!canClick}>
{i18n._('Status Report (?)')}
</MenuItem>
<MenuItem onSelect={() => controller.writeln('$C')} disabled={!canClick}>
{i18n._('Check G-code Mode ($C)')}
</MenuItem>
<MenuItem onSelect={() => controller.command('homing')} disabled={!canClick}>
{i18n._('Homing ($H)')}
</MenuItem>
<MenuItem onSelect={() => controller.command('unlock')} disabled={!canClick}>
{i18n._('Kill Alarm Lock ($X)')}
</MenuItem>
<MenuItem onSelect={() => controller.command('sleep')} disabled={!canClick}>
{i18n._('Sleep ($SLP)')}
</MenuItem>
<MenuItem divider />
<MenuItem onSelect={() => controller.writeln('$')} disabled={!canClick}>
{i18n._('Help ($)')}
</MenuItem>
<MenuItem onSelect={() => controller.writeln('$$')} disabled={!canClick}>
{i18n._('Settings ($$)')}
</MenuItem>
<MenuItem onSelect={() => controller.writeln('$#')} disabled={!canClick}>
{i18n._('View G-code Parameters ($#)')}
</MenuItem>
<MenuItem onSelect={() => controller.writeln('$G')} disabled={!canClick}>
{i18n._('View G-code Parser State ($G)')}
</MenuItem>
<MenuItem onSelect={() => controller.writeln('$I')} disabled={!canClick}>
{i18n._('View Build Info ($I)')}
</MenuItem>
<MenuItem onSelect={() => controller.writeln('$N')} disabled={!canClick}>
{i18n._('View Startup Blocks ($N)')}
</MenuItem>
</DropdownButton>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions src/web/widgets/Grbl/constants.js
@@ -0,0 +1,6 @@
import constants from 'namespace-constants';

module.exports = constants('widgets/Grbl', [
'MODAL_NONE',
'MODAL_CONTROLLER_STATE'
]);
Binary file added src/web/widgets/Grbl/icon-status-report-16.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions src/web/widgets/Grbl/index.jsx
Expand Up @@ -10,6 +10,9 @@ import Grbl from './Grbl';
import {
GRBL
} from '../../constants';
import {
MODAL_NONE
} from './constants';
import styles from './index.styl';

class GrblWidget extends Component {
Expand All @@ -22,6 +25,47 @@ class GrblWidget extends Component {
};

actions = {
openModal: (name = MODAL_NONE, params = {}) => {
// Prevent body from scrolling when a modal is opened
const body = document.querySelector('body');
const bodyStyle = {
overflowY: body.style.overflowY
};
bodyStyle.overflowY = body.style.overflowY;
body.style.overflowY = 'hidden';

this.setState({
modal: {
name: name,
bodyStyle: bodyStyle,
params: params
}
});
},
closeModal: () => {
const body = document.querySelector('body');
if (this.state.modal.bodyStyle) {
body.style.overflowY = this.state.modal.bodyStyle.overflowY;
}

this.setState({
modal: {
name: MODAL_NONE,
params: {}
}
});
},
updateModalParams: (params = {}) => {
this.setState({
modal: {
...this.state.modal,
params: {
...this.state.modal.params,
...params
}
}
});
},
toggleQueueReports: () => {
const expanded = this.state.panel.queueReports.expanded;

Expand Down Expand Up @@ -118,6 +162,10 @@ class GrblWidget extends Component {
type: controller.type,
state: controller.state
},
modal: {
name: MODAL_NONE,
params: {}
},
panel: {
queueReports: {
expanded: store.get('widgets.grbl.panel.queueReports.expanded')
Expand Down
13 changes: 11 additions & 2 deletions src/web/widgets/Grbl/index.styl
Expand Up @@ -18,9 +18,18 @@

.toolbar {
margin-bottom: 10px;
}

.icon {
display: inline-block;

button {
min-width: 24px;
&.icon-status-report {
width: 16px;
height: 16px;
background-image: url("./icon-status-report-16.png");
background-repeat: no-repeat;
vertical-align: middle;
margin-bottom: 2px;
}
}

Expand Down
51 changes: 51 additions & 0 deletions src/web/widgets/Smoothie/ControllerState.jsx
@@ -0,0 +1,51 @@
import React, { Component, PropTypes } from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import Modal from '../../components/Modal';
import i18n from '../../lib/i18n';
import {
MODAL_CONTROLLER_STATE
} from './constants';
//import styles from './index.styl';

class ControllerState extends Component {
static propTypes = {
state: PropTypes.object,
actions: PropTypes.object
};

shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
render() {
const { state, actions } = this.props;
const { modal } = state;
const show = (modal.name === MODAL_CONTROLLER_STATE);
const maxHeight = Math.max(window.innerHeight / 2, 200);

return (
<Modal
onClose={actions.closeModal}
show={show}
size="lg"
>
<Modal.Header>
<Modal.Title>{i18n._('Controller State')}</Modal.Title>
</Modal.Header>
<Modal.Body style={{ maxHeight: maxHeight }}>
<pre><code>{JSON.stringify(state.controller.state, null, 2)}</code></pre>
</Modal.Body>
<Modal.Footer>
<button
type="button"
className="btn btn-default"
onClick={actions.closeModal}
>
{i18n._('Close')}
</button>
</Modal.Footer>
</Modal>
);
}
}

export default ControllerState;
2 changes: 2 additions & 0 deletions src/web/widgets/Smoothie/Smoothie.jsx
Expand Up @@ -5,6 +5,7 @@ import mapGCodeToText from '../../lib/gcode-text';
import i18n from '../../lib/i18n';
import Panel from '../../components/Panel';
import Toggler from '../../components/Toggler';
import ControllerState from './ControllerState';
import Toolbar from './Toolbar';
import Overrides from './Overrides';
import styles from './index.styl';
Expand Down Expand Up @@ -34,6 +35,7 @@ class Smoothie extends Component {

return (
<div>
<ControllerState state={state} actions={actions} />
<Toolbar state={state} actions={actions} />
{(ovF !== undefined || ovS !== undefined) &&
<Overrides state={state} actions={actions} />
Expand Down

0 comments on commit 705de69

Please sign in to comment.