Skip to content

Commit aef4045

Browse files
committed
#541 feat: Add first version of color picker
1 parent 5fbe78f commit aef4045

2 files changed

Lines changed: 89 additions & 60 deletions

File tree

webapp/components/general/ControlPanelTreeItem.js

Lines changed: 80 additions & 60 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

@@ -117,41 +116,66 @@ 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);
125-
126-
const handleColorSelection = (_color, event, nodeId) => {
127-
const newInstances = instances.filter((instance) => !(instance.instancePath.startsWith(nodeId)));
128-
newInstances.push({
129-
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-
},
136-
});
137-
dispatch(changeInstanceColor(newInstances));
138-
setColor(_color.rgb);
139-
event.stopPropagation();
140-
event.preventDefault();
121+
const defaultColor = {
122+
g: 0.50,
123+
b: 0.60,
124+
r: 1,
125+
a: 1,
126+
hex: "#FF7F99"
141127
};
142128

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-
});
129+
const getColor = (nodeId) => {
130+
const insts = instances.filter((instance) => instance.instancePath === nodeId);
131+
if (insts.length > 0 && "color" in insts[0]) {
132+
return insts[0].color
133+
}
134+
// we check if all children have the same color
135+
const children = instances.filter((instance) => instance.instancePath.startsWith(nodeId) && instance.instancePath !== nodeId);
136+
if (children.length === 0) {
137+
return defaultColor;
138+
}
139+
const color = children[0].color;
140+
if (children.every(x => x.color && x.color.hex === color.hex)) {
141+
return color
142+
}
143+
return { hex: "#989898" }
144+
}
149145

150-
const generateRandomColor = (event, nodeId) => {
151-
event.stopPropagation();
152-
event.preventDefault();
146+
const randomColor = () => {
147+
const [r, g, b] = [Math.random() * 255, Math.random() * 255, Math.random() * 255];
148+
return {
149+
r: parseFloat(r.toFixed(2)),
150+
g: parseFloat(g.toFixed(2)),
151+
b: parseFloat(b.toFixed(2)),
152+
a: 1,
153+
hex: "#" + (r >> 0).toString(16) + (g >> 0).toString(16) + (b >> 0).toString(16)
154+
}
155+
}
156+
157+
const translateColor = (_color) => {
158+
return {
159+
r: _color.r / 255,
160+
g: _color.g / 255,
161+
b: _color.b / 255,
162+
a: _color.a,
163+
hex: _color.hex
164+
}
165+
}
166+
167+
const handleColorChange = (event, nodeId, colorGenerator) => {
153168
const children = window.Instances.getInstance(nodeId).getChildren().map((instance) => instance.getInstancePath());
154-
// const newInstances = instances.filter((instance) => !(instance.instancePath.startsWith(nodeId)));
169+
if (children.length === 0) { // If we're on a leaf, we do a classical color change
170+
const newInstances = instances.filter((instance) => !(instance.instancePath.startsWith(nodeId)));
171+
newInstances.push({
172+
instancePath: nodeId,
173+
color: translateColor(colorGenerator())
174+
});
175+
dispatch(changeInstanceColor(newInstances));
176+
return
177+
}
178+
// Otherwise, we need to change to color of children also
155179
const newInstances = instances.filter((instance) => {
156180
let condition = true;
157181
children.forEach((child) => {
@@ -163,18 +187,16 @@ const ControlPanelTreeItem = (props) => {
163187
});
164188

165189
children.forEach((child) => {
166-
const randomColor = getRandomColor();
167190
newInstances.push({
168191
instancePath: child,
169-
color: {
170-
r: randomColor.r / 255,
171-
g: randomColor.g / 255,
172-
b: randomColor.b / 255,
173-
a: randomColor.a,
174-
},
192+
color: translateColor(colorGenerator()),
175193
});
176194
});
177195
dispatch(changeInstanceColor(newInstances));
196+
if (event) {
197+
event.stopPropagation();
198+
event.preventDefault();
199+
}
178200
};
179201

180202
const changeVisibility = (event, nodeId) => {
@@ -232,8 +254,8 @@ const ControlPanelTreeItem = (props) => {
232254
label={(
233255
<Grid
234256
container
235-
onMouseEnter={() => setTimeout(setIsHoveredOver(true), 10000)}
236-
onMouseLeave={() => setTimeout(setIsHoveredOver(false), 10000)}
257+
onMouseEnter={() => setIsHoveredOver(true)}
258+
onMouseLeave={() => { setIsHoveredOver(false); setShowColorPicker(false) }}
237259
display="flex"
238260
flexDirection="row"
239261
justifyContent="space-between"
@@ -257,38 +279,36 @@ const ControlPanelTreeItem = (props) => {
257279
<IconButton onClick={(event) => changeVisibility(event, nodeId)}>
258280
{ visibility ? <Visibility style={{ marginRight: '0.5rem' }} /> : <VisibilityOff style={{ marginRight: '0.5rem' }} /> }
259281
</IconButton>
260-
<IconButton onClick={(event) => {
261-
event.stopPropagation();
262-
event.preventDefault();
263-
setShowColorPicker(true);
264-
}}
265-
>
266-
<ColorLensIcon className={showColorPicker ? classes.activeColorPicker : ''} />
267-
</IconButton>
268-
<IconButton disabled={disableRandom} onClick={(event) => generateRandomColor(event, nodeId)}>
269-
<RandomColorLensIcon />
282+
<IconButton disabled={disableRandom} onClick={(event) => handleColorChange(event, nodeId, randomColor)}>
283+
<RandomColorLensIcon style={{ marginRight: '0.5rem' }} />
270284
</IconButton>
271-
{
272-
showColorPicker
285+
</>
286+
)
287+
: null}
288+
<IconButton onClick={(event) => {
289+
event.stopPropagation();
290+
event.preventDefault();
291+
setShowColorPicker(true)
292+
}}>
293+
<SquareIcon fillColor={getColor(nodeId).hex}/>
294+
295+
</IconButton>
296+
{showColorPicker && isHoveredOver
273297
? (
274298
<Box
275299
className={classes.colorPickerBox}
276-
onMouseLeave={() => setTimeout(setShowColorPicker(false), 30000)}
300+
onMouseLeave={() => setShowColorPicker(false)}
277301
>
278-
{/* <TriangleIcon className={classes.triangleIcon} /> */}
279302
<ChromePicker
280303
className={classes.colorPicker}
281-
color={color}
304+
color={getColor(nodeId).hex}
282305
onChangeComplete={(color, event) => {
283-
handleColorSelection(color, event, nodeId);
306+
handleColorChange(event, nodeId, () => {return {...color.rgb, hex: color.hex}});
284307
}}
285308
/>
286309
</Box>
287310
) : null
288-
}
289-
</>
290-
)
291-
: null}
311+
}
292312
</Grid>
293313
</Grid>
294314
)}

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)