Skip to content

Commit 1494341

Browse files
committed
Add ParameterExposeButton component
1 parent 87446c6 commit 1494341

File tree

10 files changed

+160
-9
lines changed

10 files changed

+160
-9
lines changed

editor/src/messages/layout/layout_message_handler.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage
154154
let callback_message = (optional_input.on_update.callback)(optional_input);
155155
responses.push_back(callback_message);
156156
}
157+
Widget::ParameterExposeButton(parameter_expose_button) => {
158+
let callback_message = (parameter_expose_button.on_update.callback)(parameter_expose_button);
159+
responses.push_back(callback_message);
160+
}
157161
Widget::PivotAssist(pivot_assist) => {
158162
let update_value = value.as_str().expect("RadioInput update was not of type: u64");
159163
pivot_assist.position = update_value.into();

editor/src/messages/layout/utility_types/layout_widget.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ impl Layout {
6767
Widget::LayerReferenceInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
6868
Widget::NumberInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
6969
Widget::OptionalInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
70+
Widget::ParameterExposeButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
7071
Widget::PopoverButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
7172
Widget::TextButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
7273
Widget::IconLabel(_)
@@ -294,6 +295,7 @@ pub enum Widget {
294295
LayerReferenceInput(LayerReferenceInput),
295296
NumberInput(NumberInput),
296297
OptionalInput(OptionalInput),
298+
ParameterExposeButton(ParameterExposeButton),
297299
PivotAssist(PivotAssist),
298300
PopoverButton(PopoverButton),
299301
RadioInput(RadioInput),

editor/src/messages/layout/utility_types/widgets/button_widgets.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
21
use crate::messages::layout::utility_types::layout_widget::WidgetCallback;
2+
use crate::messages::{input_mapper::utility_types::misc::ActionKeys, portfolio::document::node_graph::FrontendGraphDataType};
33

44
use derivative::*;
55
use serde::{Deserialize, Serialize};
@@ -45,6 +45,26 @@ pub struct PopoverButton {
4545
pub tooltip_shortcut: Option<ActionKeys>,
4646
}
4747

48+
#[derive(Clone, Serialize, Deserialize, Derivative, Default)]
49+
#[derivative(Debug, PartialEq)]
50+
#[serde(rename_all(serialize = "camelCase", deserialize = "camelCase"))]
51+
pub struct ParameterExposeButton {
52+
pub exposed: bool,
53+
54+
#[serde(rename = "dataType")]
55+
pub data_type: FrontendGraphDataType,
56+
57+
pub tooltip: String,
58+
59+
#[serde(skip)]
60+
pub tooltip_shortcut: Option<ActionKeys>,
61+
62+
// Callbacks
63+
#[serde(skip)]
64+
#[derivative(Debug = "ignore", PartialEq = "ignore")]
65+
pub on_update: WidgetCallback<ParameterExposeButton>,
66+
}
67+
4868
#[derive(Clone, Serialize, Deserialize, Derivative, Default)]
4969
#[derivative(Debug, PartialEq)]
5070
#[serde(rename_all(serialize = "camelCase", deserialize = "camelCase"))]

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use graphene::layers::nodegraph_layer::NodeGraphFrameLayer;
88
mod document_node_types;
99
mod node_properties;
1010

11-
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
11+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
1212
pub enum FrontendGraphDataType {
13+
#[default]
1314
#[serde(rename = "general")]
1415
General,
1516
#[serde(rename = "raster")]

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
use crate::messages::layout::utility_types::layout_widget::{LayoutGroup, Widget, WidgetCallback, WidgetHolder};
2+
use crate::messages::layout::utility_types::widgets::button_widgets::ParameterExposeButton;
23
use crate::messages::layout::utility_types::widgets::input_widgets::{NumberInput, NumberInputMode};
34
use crate::messages::layout::utility_types::widgets::label_widgets::{Separator, SeparatorDirection, SeparatorType, TextLabel};
45
use crate::messages::prelude::NodeGraphMessage;
56

67
use graph_craft::document::value::TaggedValue;
78
use graph_craft::document::{DocumentNode, NodeId, NodeInput};
89

10+
use super::FrontendGraphDataType;
11+
912
pub fn hue_shift_image_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
1013
vec![LayoutGroup::Row {
1114
widgets: vec![
15+
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
16+
exposed: true,
17+
data_type: FrontendGraphDataType::Number,
18+
tooltip: "Expose input parameter in node graph".into(),
19+
..Default::default()
20+
})),
21+
WidgetHolder::new(Widget::Separator(Separator {
22+
separator_type: SeparatorType::Unrelated,
23+
direction: SeparatorDirection::Horizontal,
24+
})),
1225
WidgetHolder::new(Widget::TextLabel(TextLabel {
1326
value: "Shift Degrees".into(),
1427
..Default::default()
@@ -20,8 +33,8 @@ pub fn hue_shift_image_properties(document_node: &DocumentNode, node_id: NodeId)
2033
WidgetHolder::new(Widget::NumberInput(NumberInput {
2134
value: Some({
2235
let NodeInput::Value {tagged_value: TaggedValue::F32(x), ..} = document_node.inputs[1] else {
23-
panic!("Hue rotate should be f32")
24-
};
36+
panic!("Hue rotate should be f32")
37+
};
2538
x as f64
2639
}),
2740
unit: "°".into(),
@@ -45,6 +58,16 @@ pub fn hue_shift_image_properties(document_node: &DocumentNode, node_id: NodeId)
4558
pub fn brighten_image_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
4659
vec![LayoutGroup::Row {
4760
widgets: vec![
61+
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
62+
exposed: true,
63+
data_type: FrontendGraphDataType::Number,
64+
tooltip: "Expose input parameter in node graph".into(),
65+
..Default::default()
66+
})),
67+
WidgetHolder::new(Widget::Separator(Separator {
68+
separator_type: SeparatorType::Unrelated,
69+
direction: SeparatorDirection::Horizontal,
70+
})),
4871
WidgetHolder::new(Widget::TextLabel(TextLabel {
4972
value: "Brighten Amount".into(),
5073
..Default::default()
@@ -56,8 +79,8 @@ pub fn brighten_image_properties(document_node: &DocumentNode, node_id: NodeId)
5679
WidgetHolder::new(Widget::NumberInput(NumberInput {
5780
value: Some({
5881
let NodeInput::Value {tagged_value: TaggedValue::F32(x), ..} = document_node.inputs[1] else {
59-
panic!("Brighten amount should be f32")
60-
};
82+
panic!("Brighten amount should be f32")
83+
};
6184
x as f64
6285
}),
6386
mode: NumberInputMode::Range,
@@ -80,6 +103,16 @@ pub fn brighten_image_properties(document_node: &DocumentNode, node_id: NodeId)
80103
pub fn add_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
81104
let operand = |name: &str, index| LayoutGroup::Row {
82105
widgets: vec![
106+
WidgetHolder::new(Widget::ParameterExposeButton(ParameterExposeButton {
107+
exposed: true,
108+
data_type: FrontendGraphDataType::Number,
109+
tooltip: "Expose input parameter in node graph".into(),
110+
..Default::default()
111+
})),
112+
WidgetHolder::new(Widget::Separator(Separator {
113+
separator_type: SeparatorType::Unrelated,
114+
direction: SeparatorDirection::Horizontal,
115+
})),
83116
WidgetHolder::new(Widget::TextLabel(TextLabel {
84117
value: name.into(),
85118
..Default::default()
@@ -91,8 +124,8 @@ pub fn add_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<Layo
91124
WidgetHolder::new(Widget::NumberInput(NumberInput {
92125
value: Some({
93126
let NodeInput::Value {tagged_value: TaggedValue::F32(x), ..} = document_node.inputs[index] else {
94-
panic!("Add input should be f32")
95-
};
127+
panic!("Add input should be f32")
128+
};
96129

97130
x as f64
98131
}),

frontend/src/components/widgets/WidgetRow.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
@changeFont="(value: unknown) => updateLayout(component.widgetId, value)"
2727
:sharpRightCorners="nextIsSuffix"
2828
/>
29+
<ParameterExposeButton v-if="component.props.kind === 'ParameterExposeButton'" v-bind="component.props" :action="() => updateLayout(component.widgetId, undefined)" />
2930
<IconButton v-if="component.props.kind === 'IconButton'" v-bind="component.props" :action="() => updateLayout(component.widgetId, undefined)" :sharpRightCorners="nextIsSuffix" />
3031
<IconLabel v-if="component.props.kind === 'IconLabel'" v-bind="component.props" />
3132
<LayerReferenceInput v-if="component.props.kind === 'LayerReferenceInput'" v-bind="component.props" @update:value="(value: BigUint64Array) => updateLayout(component.widgetId, value)" />
@@ -104,6 +105,7 @@ import { isWidgetColumn, isWidgetRow, type WidgetColumn, type WidgetRow } from "
104105

105106
import PivotAssist from "@/components/widgets/assists/PivotAssist.vue";
106107
import IconButton from "@/components/widgets/buttons/IconButton.vue";
108+
import ParameterExposeButton from "@/components/widgets/buttons/ParameterExposeButton.vue";
107109
import PopoverButton from "@/components/widgets/buttons/PopoverButton.vue";
108110
import TextButton from "@/components/widgets/buttons/TextButton.vue";
109111
import CheckboxInput from "@/components/widgets/inputs/CheckboxInput.vue";
@@ -175,6 +177,7 @@ export default defineComponent({
175177
LayerReferenceInput,
176178
NumberInput,
177179
OptionalInput,
180+
ParameterExposeButton,
178181
PivotAssist,
179182
PopoverButton,
180183
RadioInput,
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<template>
2+
<LayoutRow class="parameter-expose-button">
3+
<button :class="{ exposed }" :style="{ '--data-type-color': dataTypeColor }" @click="(e: MouseEvent) => action(e)" :title="tooltip" :tabindex="0"></button>
4+
</LayoutRow>
5+
</template>
6+
7+
<style lang="scss">
8+
.parameter-expose-button {
9+
display: flex;
10+
align-items: center;
11+
flex: 0 0 auto;
12+
13+
button {
14+
flex: 0 0 auto;
15+
width: 8px;
16+
height: 8px;
17+
margin: 0;
18+
padding: 0;
19+
border: none;
20+
border-radius: 50%;
21+
22+
&:not(.exposed) {
23+
background: none;
24+
border: 1px solid var(--data-type-color);
25+
26+
&:hover {
27+
background: var(--color-6-lowergray);
28+
}
29+
}
30+
31+
&.exposed {
32+
background: var(--data-type-color);
33+
34+
&:hover {
35+
border: 1px solid var(--color-f-white);
36+
}
37+
}
38+
}
39+
}
40+
</style>
41+
42+
<script lang="ts">
43+
import { defineComponent, type PropType } from "vue";
44+
45+
import LayoutRow from "@/components/layout/LayoutRow.vue";
46+
47+
export default defineComponent({
48+
props: {
49+
exposed: { type: Boolean as PropType<boolean>, required: true },
50+
dataType: { type: String as PropType<string>, required: true },
51+
tooltip: { type: String as PropType<string | undefined>, required: false },
52+
53+
// Callbacks
54+
action: { type: Function as PropType<(e?: MouseEvent) => void>, required: true },
55+
},
56+
computed: {
57+
dataTypeColor(): string {
58+
// TODO: Move this function somewhere where it can be reused by other components
59+
const colorsMap = {
60+
general: "var(--color-data-general)",
61+
vector: "var(--color-data-vector)",
62+
raster: "var(--color-data-raster)",
63+
mask: "var(--color-data-mask)",
64+
number: "var(--color-data-number)",
65+
color: "var(--color-data-color)",
66+
} as const;
67+
68+
return colorsMap[this.dataType as keyof typeof colorsMap] || colorsMap.general;
69+
},
70+
},
71+
components: { LayoutRow },
72+
});
73+
</script>

frontend/src/components/widgets/groups/WidgetSection.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@
100100
text-align: right;
101101
}
102102

103+
> .parameter-expose-button ~ .text-label:first-of-type {
104+
text-align: left;
105+
}
106+
103107
> .text-button {
104108
flex-grow: 1;
105109
}

frontend/src/components/widgets/inputs/LayerReferenceInput.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@
5858
text-align: center;
5959
6060
&.missing {
61-
color: var(--color-data-unused1);
61+
// TODO: Define this as a permanent color palette choice
62+
color: #d6536e;
6263
}
6364
6465
&.layer-name {

frontend/src/wasm-communication/messages.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,15 @@ export class TextAreaInput extends WidgetProps {
10121012
tooltip!: string | undefined;
10131013
}
10141014

1015+
export class ParameterExposeButton extends WidgetProps {
1016+
exposed!: boolean;
1017+
1018+
dataType!: string;
1019+
1020+
@Transform(({ value }: { value: string }) => value || undefined)
1021+
tooltip!: string | undefined;
1022+
}
1023+
10151024
export class TextButton extends WidgetProps {
10161025
label!: string;
10171026

@@ -1105,6 +1114,7 @@ const widgetSubTypes = [
11051114
{ value: SwatchPairInput, name: "SwatchPairInput" },
11061115
{ value: TextAreaInput, name: "TextAreaInput" },
11071116
{ value: TextButton, name: "TextButton" },
1117+
{ value: ParameterExposeButton, name: "ParameterExposeButton" },
11081118
{ value: TextInput, name: "TextInput" },
11091119
{ value: TextLabel, name: "TextLabel" },
11101120
{ value: PivotAssist, name: "PivotAssist" },

0 commit comments

Comments
 (0)