Skip to content

Commit 045a78f

Browse files
authored
Merge pull request #610 from MetaCell/feature/541
Feature/541
2 parents 66666c2 + 3031067 commit 045a78f

2 files changed

Lines changed: 109 additions & 65 deletions

File tree

webapp/components/general/ControlPanelTreeItem.js

Lines changed: 100 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ import {
1717
} from '../../theme';
1818
import {
1919
RandomColorLensIcon,
20-
ColorLensIcon,
21-
TriangleIcon,
20+
SquareIcon,
2221
} from './NetPyNEIcons';
2322
import { changeInstanceColor } from '../../redux/actions/general';
2423

@@ -55,7 +54,7 @@ const useStyles = makeStyles((theme) => ({
5554
colorPickerBox: {
5655
position: 'absolute',
5756
top: '1.6rem',
58-
right: '2.7rem',
57+
right: '0',
5958
height: '3rem',
6059
},
6160
triangleIcon: {
@@ -65,7 +64,7 @@ const useStyles = makeStyles((theme) => ({
6564
colorPicker: {
6665
position: 'absolute',
6766
zIndex: 1000,
68-
right: 0,
67+
right: '0',
6968
backgroundColor: `${bgDarker} !important`,
7069
padding: '0.2rem',
7170
'& label': {
@@ -117,42 +116,79 @@ const ControlPanelTreeItem = (props) => {
117116
const dispatch = useDispatch();
118117
const [showColorPicker, setShowColorPicker] = React.useState(false);
119118
const [isHoveredOver, setIsHoveredOver] = React.useState(false);
120-
const [color, setColor] = React.useState({
121-
g: 0.50, b: 0.60, r: 1, a: 1,
122-
});
123119
const [visibility, setVisibility] = React.useState(true);
124120
const instances = useSelector((state) => state.general.instances);
121+
const defaultColor = {
122+
g: 0.50,
123+
b: 0.60,
124+
r: 1,
125+
a: 1,
126+
hex: "#FF7F99"
127+
};
125128

126-
const handleColorSelection = (_color, event, nodeId) => {
127-
const newInstances = instances.filter((instance) => !(instance.instancePath.startsWith(nodeId)));
128-
newInstances.push({
129+
const getColor = (nodeId) => {
130+
const insts = instances.filter((instance) => instance.instancePath === nodeId);
131+
const hasChildren = instances.some((instance) => instance.instancePath.startsWith(nodeId) && instance.instancePath !== nodeId);
132+
if (props.children.length === 0 && insts.length > 0 && "color" in insts[0]) {
133+
return insts[0].color
134+
}
135+
// we check if all children have the same color
136+
const children = instances.filter((instance) => instance.instancePath.startsWith(nodeId) && instance.instancePath !== nodeId);
137+
if (children.length === 0) {
138+
return defaultColor;
139+
}
140+
const color = children[0].color;
141+
if (children.every(x => x.color && x.color.hex === color.hex)) {
142+
return color
143+
}
144+
return { hex: "#989898" }
145+
}
146+
147+
const randomColor = () => {
148+
const [r, g, b] = [Math.random() * 255, Math.random() * 255, Math.random() * 255];
149+
return {
150+
r: parseFloat(r.toFixed(2)),
151+
g: parseFloat(g.toFixed(2)),
152+
b: parseFloat(b.toFixed(2)),
153+
a: 1,
154+
hex: "#" + (r >> 0).toString(16) + (g >> 0).toString(16) + (b >> 0).toString(16)
155+
}
156+
}
157+
158+
const translateColor = (_color) => {
159+
return {
160+
r: _color.r / 255,
161+
g: _color.g / 255,
162+
b: _color.b / 255,
163+
a: _color.a,
164+
hex: _color.hex
165+
}
166+
}
167+
168+
const collectAllChildren = (instance) => {
169+
const children = [...instance.getChildren()]
170+
children.forEach(child => children.push(...collectAllChildren(child)))
171+
return children
172+
}
173+
174+
const handleLeafColorChange = (event, nodeId, colorGenerator) => {
175+
const updateInstances = instances.filter((instance) => !instance.pathInstance.startsWith(nodeId));
176+
updateInstances.push({
129177
instancePath: nodeId,
130-
color: {
131-
r: _color.rgb.r / 255,
132-
g: _color.rgb.g / 255,
133-
b: _color.rgb.b / 255,
134-
a: _color.rgb.a,
135-
},
178+
color: translateColor(colorGenerator())
136179
});
137-
dispatch(changeInstanceColor(newInstances));
138-
setColor(_color.rgb);
139-
event.stopPropagation();
140-
event.preventDefault();
141-
};
142-
143-
const getRandomColor = () => ({
144-
r: parseFloat((Math.random() * 255).toFixed(2)),
145-
g: parseFloat((Math.random() * 255).toFixed(2)),
146-
b: parseFloat((Math.random() * 255).toFixed(2)),
147-
a: 1,
148-
});
180+
dispatch(changeInstanceColor(updateInstances));
181+
}
149182

150-
const generateRandomColor = (event, nodeId) => {
183+
const handleContainerColorChange = (event, nodeId, colorGenerator) => {
151184
event.stopPropagation();
152185
event.preventDefault();
153-
const children = window.Instances.getInstance(nodeId).getChildren().map((instance) => instance.getInstancePath());
154-
// const newInstances = instances.filter((instance) => !(instance.instancePath.startsWith(nodeId)));
155-
const newInstances = instances.filter((instance) => {
186+
187+
const childrenPaths = collectAllChildren(window.Instances.getInstance(nodeId))
188+
.filter((instance) => !instance.getChildren() || instance.getChildren().length === 0)
189+
.map((instance) => instance.getInstancePath());
190+
const children = childrenPaths.filter((path) => path.startsWith(nodeId));
191+
const updateInstances = instances.filter((instance) => {
156192
let condition = true;
157193
children.forEach((child) => {
158194
if (instance.instancePath.startsWith(child)) {
@@ -161,21 +197,22 @@ const ControlPanelTreeItem = (props) => {
161197
});
162198
return condition;
163199
});
164-
165200
children.forEach((child) => {
166-
const randomColor = getRandomColor();
167-
newInstances.push({
201+
updateInstances.push({
168202
instancePath: child,
169-
color: {
170-
r: randomColor.r / 255,
171-
g: randomColor.g / 255,
172-
b: randomColor.b / 255,
173-
a: randomColor.a,
174-
},
203+
color: translateColor(colorGenerator())
175204
});
176205
});
177-
dispatch(changeInstanceColor(newInstances));
178-
};
206+
dispatch(changeInstanceColor(updateInstances));
207+
}
208+
209+
const handleColorChange = (event, nodeId, colorGenerator) => {
210+
if (props.children.length === 0) {
211+
handleLeafColorChange(event, nodeId, colorGenerator);
212+
return
213+
}
214+
handleContainerColorChange(event, nodeId, colorGenerator);
215+
}
179216

180217
const changeVisibility = (event, nodeId) => {
181218
event.stopPropagation();
@@ -232,8 +269,8 @@ const ControlPanelTreeItem = (props) => {
232269
label={(
233270
<Grid
234271
container
235-
onMouseEnter={() => setTimeout(setIsHoveredOver(true), 10000)}
236-
onMouseLeave={() => setTimeout(setIsHoveredOver(false), 10000)}
272+
onMouseEnter={() => setIsHoveredOver(true)}
273+
onMouseLeave={() => { setIsHoveredOver(false); setShowColorPicker(false) }}
237274
display="flex"
238275
flexDirection="row"
239276
justifyContent="space-between"
@@ -257,38 +294,36 @@ const ControlPanelTreeItem = (props) => {
257294
<IconButton onClick={(event) => changeVisibility(event, nodeId)}>
258295
{ visibility ? <Visibility style={{ marginRight: '0.5rem' }} /> : <VisibilityOff style={{ marginRight: '0.5rem' }} /> }
259296
</IconButton>
260-
<IconButton onClick={(event) => {
261-
event.stopPropagation();
262-
event.preventDefault();
263-
setShowColorPicker(true);
264-
}}
265-
>
266-
<ColorLensIcon className={showColorPicker ? classes.activeColorPicker : ''} />
297+
<IconButton disabled={disableRandom} onClick={(event) => handleColorChange(event, nodeId, randomColor)}>
298+
<RandomColorLensIcon style={{ marginRight: '0.5rem' }} />
267299
</IconButton>
268-
<IconButton disabled={disableRandom} onClick={(event) => generateRandomColor(event, nodeId)}>
269-
<RandomColorLensIcon />
270-
</IconButton>
271-
{
272-
showColorPicker
300+
</>
301+
)
302+
: null}
303+
<IconButton onClick={(event) => {
304+
event.stopPropagation();
305+
event.preventDefault();
306+
setShowColorPicker(true)
307+
}}>
308+
<SquareIcon fillColor={getColor(nodeId).hex}/>
309+
310+
</IconButton>
311+
{showColorPicker && isHoveredOver
273312
? (
274313
<Box
275314
className={classes.colorPickerBox}
276-
onMouseLeave={() => setTimeout(setShowColorPicker(false), 30000)}
315+
onMouseLeave={() => setShowColorPicker(false)}
277316
>
278-
{/* <TriangleIcon className={classes.triangleIcon} /> */}
279317
<ChromePicker
280318
className={classes.colorPicker}
281-
color={color}
319+
color={getColor(nodeId).hex}
282320
onChangeComplete={(color, event) => {
283-
handleColorSelection(color, event, nodeId);
321+
handleColorChange(event, nodeId, () => {return {...color.rgb, hex: color.hex}});
284322
}}
285323
/>
286324
</Box>
287325
) : null
288-
}
289-
</>
290-
)
291-
: null}
326+
}
292327
</Grid>
293328
</Grid>
294329
)}

webapp/components/general/NetPyNEIcons.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,12 @@ export function TreeItemLineWithRadiusIcon (props) {
9191
</SvgIcon>
9292
);
9393
}
94+
95+
96+
export function SquareIcon (props) {
97+
return (
98+
<SvgIcon viewBox="0 0 24 24" {...props}>
99+
<rect width="20" height="20" fill={props.fillColor ? props.fillColor : "#FF7F99"} rx="5" />
100+
</SvgIcon>
101+
);
102+
}

0 commit comments

Comments
 (0)