diff --git a/modules/bus/index.js b/modules/bus/index.js index 5f9244a5..eb5e5b6d 100644 --- a/modules/bus/index.js +++ b/modules/bus/index.js @@ -70,6 +70,10 @@ export default class Bus { this.dispatch(token, Object.assign({}, this.state[token], partialState)); } + getState(fqn) { + return this.state[createToken(fqn)]; + } + dispatch(key, data) { if (this.lock.has(key)) { console.warn('recursive dispatch'); diff --git a/modules/ui/components/AdjustableAbs.jsx b/modules/ui/components/AdjustableAbs.jsx index bf878b5f..115f422e 100644 --- a/modules/ui/components/AdjustableAbs.jsx +++ b/modules/ui/components/AdjustableAbs.jsx @@ -39,9 +39,12 @@ export default class AdjustableAbs extends React.Component { } render() { - let {left, top, right, bottom, children, style, zIndex, ...props} = this.props; + let {left, top, right, bottom, children, style, zIndex, visible, ...props} = this.props; return
this.el = el} - style={{position: 'absolute', left, top, right, bottom, zIndex, ...style}} {...props}> + style={{ + display: visible ? 'block' : 'none', + position: 'absolute', left, top, right, bottom, zIndex, + ...style}} {...props}> {children}
; } @@ -49,6 +52,7 @@ export default class AdjustableAbs extends React.Component { AdjustableAbs.defaultProps = { zIndex: 100, + visible: true }; diff --git a/modules/ui/components/Menu.jsx b/modules/ui/components/Menu.jsx index 1e0043b1..ec233ccc 100644 --- a/modules/ui/components/Menu.jsx +++ b/modules/ui/components/Menu.jsx @@ -5,13 +5,9 @@ import ls from './Menu.less'; import AuxWidget from "./AuxWidget"; import cx from 'classnames'; -export default function Menu({children, visible, x, y, orientationUp, style, ...props}) { +export default function Menu({children, x, y, orientationUp, ...props}) { return ; } -export function ToolbarButton({children, disabled}) { - return
+export function ToolbarButton({children, disabled, ...props}) { + return
{children}
; } diff --git a/web/app/cad/actions/actionButtonBehavior.js b/web/app/cad/actions/actionButtonBehavior.js new file mode 100644 index 00000000..9b7d3e29 --- /dev/null +++ b/web/app/cad/actions/actionButtonBehavior.js @@ -0,0 +1,12 @@ + +import {TOKENS as ACTION_TOKENS} from "./actionSystemPlugin"; + +export function mapActionBehavior(actionId) { + let actionRunToken = ACTION_TOKENS.actionRun(actionId); + + return dispatch => ({ + onClick: data => dispatch(actionRunToken, data), + onMouseEnter: ({pageX, pageY}) => dispatch(ACTION_TOKENS.SHOW_HINT_FOR, [actionId, pageX, pageY]), + onMouseLeave: () => dispatch(ACTION_TOKENS.SHOW_HINT_FOR, null) + }); +} \ No newline at end of file diff --git a/web/app/cad/actions/actionSystemPlugin.js b/web/app/cad/actions/actionSystemPlugin.js index bea2637d..52ed23c3 100644 --- a/web/app/cad/actions/actionSystemPlugin.js +++ b/web/app/cad/actions/actionSystemPlugin.js @@ -40,7 +40,8 @@ export function activate(context) { } bus.subscribe(TOKENS.actionRun(action.id), (data) => action.invoke(context, data)); } - + + bus.enableState(TOKENS.HINT, null); function registerAction(action) { register(action); } @@ -48,16 +49,57 @@ export function activate(context) { function registerActions(actions) { actions.forEach(action => register(action)); } - + + synchActionHint(bus); + context.services.action = {run, registerAction, registerActions} } -export const TOKENS = { - ACTION_STATE_NS: 'action.state', - ACTION_APPEARANCE_NS: 'action.appearance', - ACTION_RUN_NS: 'action.run', + + +function synchActionHint(bus) { - actionState: (actionId) => createToken(TOKENS.ACTION_STATE_NS, actionId), - actionAppearance: (actionId) => createToken(TOKENS.ACTION_APPEARANCE_NS, actionId), - actionRun: (actionId) => createToken(TOKENS.ACTION_RUN_NS, actionId), + let lastRequest = null; + + // bus.subscribe(TOKENS.REQUEST_SHOW_HINT_FOR + bus.subscribe(TOKENS.SHOW_HINT_FOR, request => { + if (lastRequest !== null) { + if (request !== null) { + if (request[0] === lastRequest[0]) { + Object.assign(lastRequest, request); + return; + } + } + lastRequest.spoiled = true; + } + lastRequest = request; + if (request) { + setTimeout(() => { + if (!request.spoiled) { + let [actionId, x, y] = request; + let actionState = bus.getState(TOKENS.actionState(actionId)); + let actionAppearance = bus.getState(TOKENS.actionAppearance(actionId)); + if (actionState && actionAppearance) { + bus.dispatch(TOKENS.HINT, { + actionId, x: x + 10, y: y + 10, + info: actionAppearance.info, + hint: actionState.hint + }); + } + } + }, 500); + } else { + bus.dispatch(TOKENS.HINT, null); + } + }); +} + +export const ACTION_NS = 'action'; +export const TOKENS = { + actionState: (actionId) => createToken(ACTION_NS, 'state', actionId), + actionAppearance: (actionId) => createToken(ACTION_NS, 'appearance', actionId), + actionRun: (actionId) => createToken(ACTION_NS, 'run', actionId), + + SHOW_HINT_FOR: createToken(ACTION_NS, 'showHintFor'), + HINT: createToken(ACTION_NS, 'hint'), }; \ No newline at end of file diff --git a/web/app/cad/dom/actionInfo/ActionInfo.jsx b/web/app/cad/dom/actionInfo/ActionInfo.jsx new file mode 100644 index 00000000..ffb3cf77 --- /dev/null +++ b/web/app/cad/dom/actionInfo/ActionInfo.jsx @@ -0,0 +1,24 @@ +import React, {Fragment} from 'react'; +import ls from './ActionInfo.less'; + +import AuxWidget from '../../../../../modules/ui/components/AuxWidget'; +import connect from '../../../../../modules/ui/connect'; +import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin'; +import {TOKENS as KeyboardTokens} from "../../keyboard/keyboardPlugin"; + +function ActionInfo({actionId, x, y, info, hint, hotKey}) { + let visible = !!actionId; + + return + {visible && +
{hint}
+
{info}
+ {hotKey &&
hotkey: {hotKey}
} +
} +
; +} + +export default connect([ACTION_TOKENS.HINT, KeyboardTokens.KEYMAP], ActionInfo, undefined, + ([ hintInfo, keymap ]) => (Object.assign({hotKey: hintInfo && keymap[hintInfo.actionId]}, hintInfo)) ); + diff --git a/web/app/cad/dom/actionInfo/ActionInfo.less b/web/app/cad/dom/actionInfo/ActionInfo.less new file mode 100644 index 00000000..b86d86bc --- /dev/null +++ b/web/app/cad/dom/actionInfo/ActionInfo.less @@ -0,0 +1,3 @@ +.root { + display: flex; +} \ No newline at end of file diff --git a/web/app/cad/dom/actionInfo/actionInfoPlugin.js b/web/app/cad/dom/actionInfo/actionInfoPlugin.js new file mode 100644 index 00000000..49f611b4 --- /dev/null +++ b/web/app/cad/dom/actionInfo/actionInfoPlugin.js @@ -0,0 +1,4 @@ + +export function activate() { + +} \ No newline at end of file diff --git a/web/app/cad/dom/components/ActionInfo.jsx b/web/app/cad/dom/components/ActionInfo.jsx deleted file mode 100644 index 0095af65..00000000 --- a/web/app/cad/dom/components/ActionInfo.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - - - -export default function ActionInfo({children}) { - - return - {children} - ; -} - - diff --git a/web/app/cad/dom/components/ControlBar.jsx b/web/app/cad/dom/components/ControlBar.jsx index 0787b617..b7eefaba 100644 --- a/web/app/cad/dom/components/ControlBar.jsx +++ b/web/app/cad/dom/components/ControlBar.jsx @@ -15,9 +15,9 @@ export default function ControlBar({left, right}) {
} -export function ControlBarButton({onClick, onElement, disabled, children}) { +export function ControlBarButton({onElement, disabled, children, onClick, ...props}) { return + onClick={disabled || onClick} ref={onElement} {...props}> {children} } \ No newline at end of file diff --git a/web/app/cad/dom/components/MessageSink.jsx b/web/app/cad/dom/components/MessageSink.jsx deleted file mode 100644 index 324cdd0e..00000000 --- a/web/app/cad/dom/components/MessageSink.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -import AuxWidget from './../../../../../modules/ui/components/AuxWidget'; - -export default function MessageSink({children, ...props}) { - - return - {children} - ; -} - diff --git a/web/app/cad/dom/components/MessageSink.less b/web/app/cad/dom/components/MessageSink.less deleted file mode 100644 index e69de29b..00000000 diff --git a/web/app/cad/dom/components/PlugableControlBar.jsx b/web/app/cad/dom/components/PlugableControlBar.jsx index b64259a4..3a0550d0 100644 --- a/web/app/cad/dom/components/PlugableControlBar.jsx +++ b/web/app/cad/dom/components/PlugableControlBar.jsx @@ -5,6 +5,7 @@ import Fa from 'ui/components/Fa'; import {TOKENS as UI_TOKENS} from '../uiEntryPointsPlugin'; import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin'; import {toIdAndOverrides} from "../../actions/actionRef"; +import {mapActionBehavior} from "../../actions/actionButtonBehavior"; export default function PlugableControlBar() { @@ -14,11 +15,10 @@ export default function PlugableControlBar() { function ButtonGroup({actions}) { return actions.map(actionRef => { let [id, overrides] = toIdAndOverrides(actionRef); - let actionRunToken = ACTION_TOKENS.actionRun(id); let Comp = connect([ACTION_TOKENS.actionAppearance(id), ACTION_TOKENS.actionState(id)], ActionButton, {actionId: id}, ([appearance, state]) => Object.assign({}, appearance, state, overrides), - dispatch => ({runAction: (data) => dispatch(actionRunToken, data)}) + mapActionBehavior(id) ); return ; }); @@ -31,12 +31,16 @@ function isMenuAction(actionId) { class ActionButton extends React.Component { render() { - let {label, cssIcons, runAction, enabled, visible, actionId} = this.props; + let {label, cssIcons, enabled, visible, actionId, ...props} = this.props; if (!visible) { return null; } - const onClick = e => runAction(isMenuAction(actionId) ? getMenuData(this.el) : undefined); - return this.el = el}> + if (isMenuAction(actionId)) { + let onClick = props.onClick; + props.onClick = e => onClick(getMenuData(this.el)); + } + + return this.el = el} {...props} > {cssIcons && } {label} ; } diff --git a/web/app/cad/dom/components/UISystem.jsx b/web/app/cad/dom/components/UISystem.jsx index 92fa95cf..e6924dfd 100644 --- a/web/app/cad/dom/components/UISystem.jsx +++ b/web/app/cad/dom/components/UISystem.jsx @@ -4,15 +4,14 @@ import MenuHolder from "../menu/MenuHolder"; import {TOKENS as MENU_TOKENS} from '../menu/menuPlugin'; import WindowSystem from 'ui/WindowSystem'; -import MessageSink from './MessageSink'; - +import ActionInfo from "../actionInfo/ActionInfo"; export default class UISystem extends React.Component { render() { return
- + {this.props.children}
diff --git a/web/app/cad/dom/components/View3d.jsx b/web/app/cad/dom/components/View3d.jsx index a8348946..6499ee02 100644 --- a/web/app/cad/dom/components/View3d.jsx +++ b/web/app/cad/dom/components/View3d.jsx @@ -23,7 +23,6 @@ import NumberControl from "ui/components/controls/NumberControl"; import ButtonGroup from "ui/components/controls/ButtonGroup"; import Button from "ui/components/controls/Button"; import TextControl from './../../../../../modules/ui/components/controls/TextControl'; -import MessageSink from './MessageSink'; import UISystem from './UISystem';