Commit 627c0ef6 authored by Dorian Goepp's avatar Dorian Goepp

We are getting closer to a wokring proposal

parent e339ca55
......@@ -14,8 +14,8 @@ import { RosMood, DemoMood } from './Mood'
import DemoString from './String'
// get the default configuration for the layout
import {flexlayout_json as json} from './demo-1-config'
// import {flexlayout_json as json} from './devel-config'
// import {flexlayout_json as json} from './demo-1-config'
import {flexlayout_json as json} from './devel-config'
// CSS common to the whole app
import './Common.css'
......@@ -132,10 +132,16 @@ class Board extends React.Component {
const tab = this.getSelectedNode(); // retrieve the selected tab
const config = tab.getConfig(); // get the configuration of this tab
if (!("displayMode" in config) || (config.displayMode !== modeName)) {
if (!this.isMaximized()) { // Maximize the tabset
this._model.doAction(Actions.maximizeToggle(this.getId()));
}
config.displayMode = modeName;
this._model.doAction(
FlexLayout.Actions.updateNodeAttributes(tab.getId(), {config: config}));
} else {
if (this.isMaximized()) { // Return the tabset to its original size
this._model.doAction(Actions.maximizeToggle(this.getId()));
}
delete config.displayMode;
this._model.doAction(
FlexLayout.Actions.updateNodeAttributes(tab.getId(), {config: config}));
......
......@@ -8,14 +8,16 @@ class HorizontalGauge extends Component {
const value = ('value' in this.props && this.props.value) ? this.props.value : 0;
// Define the dimensions of the gaug
const margin = { left:10, top: 10, right: 10, bottom: 10}
, width = this.props.size.width - margin.left - margin.right
, height = 20;
const margin = { left:10, top: 10, right: 10, bottom: 10},
width = this.props.size.width - margin.left - margin.right,
height = 20;
const viewbox = "0 0 " + (width + margin.left + margin.right) +" "+ (height + margin.top + margin.bottom);
const min = this.props.min || 0,
max = this.props.max || 1;
// Scale to map from values in [0, 1] to values in [0, width] (callable)
const xScale = scaleLinear()
.domain([0, 1])
.domain([min, max])
.range([0, width])
.clamp(true);
......@@ -33,18 +35,6 @@ class HorizontalGauge extends Component {
</g>
</svg>;
const config = this.props.node.getConfig()
if (config && 'displayMode' in config) {
if (config.displayMode === "readme") {
return <p className="about">This gauge represent a <b>measure</b> ranging from 0 to 1.</p>;
} else if (config.displayMode === "settings") {
return <div>
<p>config panel</p>
</div>;
}
}
return <div>{svg}</div>;
}
}
......
import React, {Component} from 'react'
import RosLib from 'roslib';
import RosLib from 'roslib'
import {get} from 'lodash/object'
import HorizontalGauge from './index'
......@@ -8,20 +9,37 @@ class RosHGauge extends Component {
super(props)
this.state = {datum: null}
this.topic = "/predictions/interaction_involvement"
this.type = "april_messages/head_orientation_prediction"
}
static get modes() {
return {
readme: <p className="about">This gauge represent a <b>measure</b> ranging from 0 to 1.</p>,
settingsSchema: {
title: "Horizontal Gauge",
type: "object",
required: ["topic", "field", "min", "max"],
properties: {
topic: {type: "string", title: "ROS topic (absolute name)",
default: "/predictions/interaction_involvement"},
field: {type: "string", title: "the field to be read from the message",
default: "prediction_of_head_orientation.list[0].values[1]"},
min: {type: "number", title: "Lower end of the data range", default: 0},
max: {type: "number", title: "Upper end of the data range", default: 1},
}
},
};
}
componentDidMount() {
if ('ros' in this.props && this.props.ros) {
const config = this.props.node.getConfig();
this.listener = new RosLib.Topic({
ros : this.props.ros,
name: this.topic,
messageType: this.type
name: config.topic,
});
this.listener.subscribe(function(message) {
this.setState({datum: message.prediction_of_head_orientation.list[0].values[1]});
this.setState({datum: get(message, config.field)});
}.bind(this));
}else {
console.warn('RosHGauge expects to be passed a valid Ros object as property, got ', this.props.ros);
......@@ -35,7 +53,13 @@ class RosHGauge extends Component {
}
render() {
return <HorizontalGauge value={this.state.datum} {...this.props}/>
const config = this.props.node.getConfig();
return <HorizontalGauge
value={this.state.datum}
min={config.min}
max={config.max}
{...this.props}/>;
}
}
......
import React from 'react'
import HorizontalGauge from './HozirontalGauge'
import RosHGauge from './RosHGauge'
import {Modal} from '../utils/modeHandler'
export default HorizontalGauge;
export {RosHGauge};
\ No newline at end of file
function modal(props){
return <Modal component={RosHGauge} {...props}/>;
}
export {modal as RosHGauge};
\ No newline at end of file
......@@ -96,9 +96,6 @@ export const flexlayout_json = {
{
"type": "tab",
"component": "mood",
"config": {
"hasReadme": true
},
},
]
},
......@@ -124,10 +121,7 @@ export const flexlayout_json = {
"children": [
{
"type": "tab",
"component": "demo-video",
"config": {
"hasReadme": true
}
"component": "video",
}
]
}
......
import React from 'react';
import React, {Component} from 'react';
import Form from 'react-jsonschema-form';
import { merge } from 'lodash/object';
......@@ -72,19 +72,14 @@ export class modeHandler {
}
}
noop(value) {
return value;
}
/**
* Return either the value of the normal parameter, in normal mode, or the content for the `readme` and `settings`
* modes.
*
* The display mode is defined by the 'displayMode' attribute of the component's configuraiton.
* The display mode is defined by the 'displayMode' attribute of the component's configuration.
* @param {Jsx} normal The content to return in the normal mode (neither settings nor readme)
*/
modalDisplay(normal) {
// return normal;
const config = this.configGetter();
if (config && 'displayMode' in config) {
if (config.configurable && config.displayMode === "settings") {
......@@ -115,4 +110,113 @@ export class modeHandler {
return config;
}
}
export class Modal extends Component {
constructor(props) {
super(props);
this.modes = this.props.component.modes;
this.configGetter = this.props.node.getConfig.bind(this.props.node);
this.configSetter = this.props.updateConfig;
// get the current config; if it does not exist yet, create it
let config = this.configGetter() || {};
merge(config, this.announceCapabilities(config));
if (config.configurable) {
merge(config, this.defaultConfigFromSchema(config));
}
this.configSetter(config);
}
/**
* Search for the 'settingsSchema' and 'readme' properties of the managed component. A corresponding field in the
* configuration is set accordingly. This is used to display or not the UI buttons to show the Readme or the
* configuration for of a component.
* @param {Object} config current configuration of the object
* @return the new configuration object (possibly unmodified)
*/
announceCapabilities(config) {
if (this.modes.settingsSchema) {
config.configurable = true;
}
else {
config.configurable = false;
}
if (this.modes.readme) {
config.hasReadme = true;
}
else {
config.hasReadme = false;
}
return config;
}
/**
* Search for properties in a JSON Schema. If they are here, use the default value of each JsonSchema property for
* the configuration. This means that if a property is already defined in the configuration, it will not be
* altered.
* @param {Object} config current configuration of the object
* @return the new configuration object (possibly unmodified)
*/
defaultConfigFromSchema(config) {
const schema = this.modes.settingsSchema;
if (!schema) {
return config;
}
else if (!('properties' in schema)) {
console.warn("no properties in the schema");
return config;
}
else {
for (let [key, value] of Object.entries(schema.properties)) {
if (!(key in config)) {
let message = "The key '" + key + "' is missing in the configuration.";
if ('default' in value) {
config[key] = value.default;
message += " Using default value '" + value.default + "'.";
}
console.debug(message);
}
}
return config;
}
}
/**
* Render either the value of the normal parameter, in normal mode, or the content for the `readme` and `settings`
* modes. The display mode is defined by the 'displayMode' attribute of the component's configuration.
*/
render() {
const config = this.configGetter();
if (config && 'displayMode' in config) {
if (config.configurable && config.displayMode === "settings") {
return (
<Form
schema={this.modes.settingsSchema}
onSubmit={this.handleSettingsChange.bind(this)}
formData={config} />);
}
if (config.hasReadme && config.displayMode === "readme") {
return this.modes.readme;
}
}
return React.createElement(this.props.component, this.props, null);
}
/**
* Given a new configuration object (from the form), update the configuration of the component (in FlexLayout).
*
* The update is done through Lodash's merge function.
* @param {Object} value update for the configuration of the component (we take the field formData)
* @return Also return the updated configuration.
*/
handleSettingsChange({ formData }) {
let config = this.configGetter();
merge(config, formData);
this.configSetter(config);
return config;
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment