Skip to content

Commit 02c1548

Browse files
authored
Merge branch 'master' into origin-graph-data
2 parents 90e8859 + fdb09e3 commit 02c1548

144 files changed

Lines changed: 4636 additions & 11243 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-dev-and-ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ jobs:
8484
mold -run cargo fmt --all -- --check
8585
8686
- name: 🦀 Build Rust code
87+
env:
88+
RUSTFLAGS: -Dwarnings
8789
run: |
8890
mold -run cargo build --all-features
8991

Cargo.lock

Lines changed: 18 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"proc-macros",
55
"frontend/wasm",
66
"frontend/src-tauri",
7+
"node-graph/gapplication-io",
78
"node-graph/gcore",
89
"node-graph/gstd",
910
"node-graph/graph-craft",
@@ -31,14 +32,18 @@ resolver = "2"
3132

3233
[workspace.dependencies]
3334
# Local dependencies
34-
dyn-any = { path = "libraries/dyn-any", features = ["derive", "glam", "reqwest"] }
35-
graphene-core = { path = "node-graph/gcore" }
36-
graph-craft = { path = "node-graph/graph-craft", features = ["serde"] }
37-
wgpu-executor = { path = "node-graph/wgpu-executor" }
38-
bezier-rs = { path = "libraries/bezier-rs", features = ["dyn-any"] }
39-
path-bool = { path = "libraries/path-bool", default-features = false }
35+
bezier-rs = { path = "libraries/bezier-rs", features = ["dyn-any", "serde"] }
36+
dyn-any = { path = "libraries/dyn-any", features = ["derive", "glam", "reqwest", "log-bad-types", "rc"] }
4037
math-parser = { path = "libraries/math-parser" }
38+
path-bool = { path = "libraries/path-bool" }
39+
graphene-application-io = { path = "node-graph/gapplication-io" }
40+
graphene-core = { path = "node-graph/gcore" }
41+
graph-craft = { path = "node-graph/graph-craft" }
42+
graphene-std = { path = "node-graph/gstd" }
43+
interpreted-executor = { path = "node-graph/interpreted-executor" }
4144
node-macro = { path = "node-graph/node-macro" }
45+
wgpu-executor = { path = "node-graph/wgpu-executor" }
46+
graphite-proc-macros = { path = "proc-macros" }
4247

4348
# Workspace dependencies
4449
rustc-hash = "2.0"
@@ -56,30 +61,51 @@ convert_case = "0.7"
5661
derivative = "2.2"
5762
thiserror = "2"
5863
anyhow = "1.0"
59-
proc-macro2 = "1"
64+
proc-macro2 = { version = "1", features = [ "span-locations" ] }
6065
quote = "1.0"
6166
axum = "0.8"
6267
chrono = "0.4"
6368
ron = "0.8"
6469
fastnoise-lite = "1.1"
65-
spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu.git" }
66-
wgpu = "23"
70+
wgpu = { version = "23", features = [
71+
# We don't have wgpu on multiple threads (yet) https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#wgpu-types-now-send-sync-on-wasm
72+
"fragile-send-sync-non-atomic-wasm",
73+
"spirv",
74+
"strict_asserts",
75+
] }
6776
once_cell = "1.13" # Remove when `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) is stabilized in Rust 1.80 and we bump our MSRV
6877
wasm-bindgen = "=0.2.100" # NOTICE: ensure this stays in sync with the `wasm-bindgen-cli` version in `website/content/volunteer/guide/project-setup/_index.md`. We pin this version because wasm-bindgen upgrades may break various things.
6978
wasm-bindgen-futures = "0.4"
7079
js-sys = "=0.3.77"
71-
web-sys = "=0.3.77"
80+
web-sys = { version = "=0.3.77", features = [
81+
"Document",
82+
"DomRect",
83+
"Element",
84+
"HtmlCanvasElement",
85+
"CanvasRenderingContext2d",
86+
"CanvasPattern",
87+
"OffscreenCanvas",
88+
"OffscreenCanvasRenderingContext2d",
89+
"TextMetrics",
90+
"Window",
91+
"IdleRequestOptions",
92+
"ImageData",
93+
"Navigator",
94+
"Gpu",
95+
"HtmlImageElement",
96+
"ImageBitmapRenderingContext",
97+
] }
7298
winit = "0.29"
7399
url = "2.5"
74-
tokio = { version = "1.29", features = ["fs", "io-std"] }
100+
tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt"] }
75101
vello = { git = "https://github.com/linebender/vello.git", rev = "3275ec8" } # TODO switch back to stable when a release is made
76102
resvg = "0.44"
77103
usvg = "0.44"
78-
rand = { version = "0.9", default-features = false }
104+
rand = { version = "0.9", default-features = false, features = ["std_rng"] }
79105
rand_chacha = "0.9"
80-
glam = { version = "0.29", default-features = false, features = ["serde"] }
106+
glam = { version = "0.29", default-features = false, features = ["serde", "scalar-math", "debug-glam-assert"] }
81107
base64 = "0.22"
82-
image = { version = "0.25", default-features = false, features = ["png"] }
108+
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp"] }
83109
rustybuzz = "0.20"
84110
pretty_assertions = "1.4.1"
85111
fern = { version = "0.7", features = ["colored"] }
@@ -94,11 +120,22 @@ specta = { version = "2.0.0-rc.22", features = [
94120
syn = { version = "2.0", default-features = false, features = [
95121
"full",
96122
"derive",
123+
"parsing",
124+
"printing",
125+
"visit-mut",
126+
"visit",
127+
"clone-impls",
128+
"extra-traits",
129+
"proc-macro",
97130
] }
98131
kurbo = { version = "0.11.0", features = ["serde"] }
99132
petgraph = { version = "0.7.1", default-features = false, features = [
100133
"graphmap",
101134
] }
135+
half = { version = "2.4.1", default-features = false, features = ["bytemuck", "serde"] }
136+
tinyvec = { version = "1" }
137+
criterion = { version = "0.5", features = ["html_reports"] }
138+
iai-callgrind = { version = "0.12.3" }
102139

103140
[profile.dev]
104141
opt-level = 1

editor/Cargo.toml

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@ ron = ["dep:ron"]
2525

2626
[dependencies]
2727
# Local dependencies
28-
graphite-proc-macros = { path = "../proc-macros" }
29-
graph-craft = { path = "../node-graph/graph-craft" }
30-
interpreted-executor = { path = "../node-graph/interpreted-executor", features = [
31-
"serde",
32-
] }
33-
graphene-std = { path = "../node-graph/gstd", features = ["serde"] }
28+
graphite-proc-macros = { workspace = true }
29+
graph-craft = { workspace = true }
30+
interpreted-executor = { workspace = true }
31+
graphene-std = { workspace = true }
3432

3533
# Workspace dependencies
3634
js-sys = { workspace = true }
@@ -41,31 +39,21 @@ serde = { workspace = true }
4139
serde_json = { workspace = true }
4240
bezier-rs = { workspace = true }
4341
futures = { workspace = true }
44-
glam = { workspace = true, features = ["serde", "debug-glam-assert"] }
42+
glam = { workspace = true }
43+
kurbo = { workspace = true }
4544
derivative = { workspace = true }
4645
specta = { workspace = true }
47-
image = { workspace = true, features = ["bmp", "png"] }
4846
dyn-any = { workspace = true }
4947
num_enum = { workspace = true }
5048
usvg = { workspace = true }
5149
once_cell = { workspace = true }
52-
web-sys = { workspace = true, features = [
53-
"Document",
54-
"DomRect",
55-
"Element",
56-
"HtmlCanvasElement",
57-
"CanvasRenderingContext2d",
58-
"CanvasPattern",
59-
"OffscreenCanvas",
60-
"OffscreenCanvasRenderingContext2d",
61-
"TextMetrics",
62-
] }
50+
web-sys = { workspace = true }
6351

6452
# Required dependencies
6553
spin = "0.9.8"
6654

6755
# Optional local dependencies
68-
wgpu-executor = { path = "../node-graph/wgpu-executor", optional = true }
56+
wgpu-executor = { workspace = true, optional = true }
6957

7058
# Optional workspace dependencies
7159
wasm-bindgen = { workspace = true, optional = true }
@@ -76,7 +64,7 @@ ron = { workspace = true, optional = true }
7664
# Workspace dependencies
7765
env_logger = { workspace = true }
7866
futures = { workspace = true }
79-
tokio = { workspace = true, features = ["rt", "macros"] }
67+
tokio = { workspace = true }
8068

8169
[lints.rust]
8270
# TODO: figure out why we check these features when they do not exist

editor/src/consts.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ pub const LINE_ROTATE_SNAP_ANGLE: f64 = 15.;
120120
pub const BRUSH_SIZE_CHANGE_KEYBOARD: f64 = 5.;
121121
pub const DEFAULT_BRUSH_SIZE: f64 = 20.;
122122

123+
// GIZMOS
124+
pub const POINT_RADIUS_HANDLE_SNAP_THRESHOLD: f64 = 8.;
125+
pub const POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD: f64 = 7.9;
126+
pub const NUMBER_OF_POINTS_HANDLE_SPOKE_EXTENSION: f64 = 1.2;
127+
pub const NUMBER_OF_POINTS_HANDLE_SPOKE_LENGTH: f64 = 10.;
128+
pub const GIZMO_HIDE_THRESHOLD: f64 = 20.;
129+
123130
// SCROLLBARS
124131
pub const SCROLLBAR_SPACING: f64 = 0.1;
125132
pub const ASYMPTOTIC_EFFECT: f64 = 0.5;

editor/src/messages/input_mapper/input_mappings.rs

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,40 @@ pub fn input_mappings() -> Mapping {
171171
entry!(KeyDown(MouseRight); action_dispatch=GradientToolMessage::Abort),
172172
entry!(KeyDown(Escape); action_dispatch=GradientToolMessage::Abort),
173173
//
174-
// RectangleToolMessage
175-
entry!(KeyDown(MouseLeft); action_dispatch=RectangleToolMessage::DragStart),
176-
entry!(KeyUp(MouseLeft); action_dispatch=RectangleToolMessage::DragStop),
177-
entry!(KeyDown(MouseRight); action_dispatch=RectangleToolMessage::Abort),
178-
entry!(KeyDown(Escape); action_dispatch=RectangleToolMessage::Abort),
179-
entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=RectangleToolMessage::PointerMove { center: Alt, lock_ratio: Shift }),
174+
// ShapeToolMessage
175+
entry!(KeyDown(MouseLeft); action_dispatch=ShapeToolMessage::DragStart),
176+
entry!(KeyUp(MouseLeft); action_dispatch=ShapeToolMessage::DragStop),
177+
entry!(KeyDown(MouseRight); action_dispatch=ShapeToolMessage::Abort),
178+
entry!(KeyDown(Escape); action_dispatch=ShapeToolMessage::Abort),
179+
entry!(KeyDown(BracketLeft); action_dispatch=ShapeToolMessage::DecreaseSides),
180+
entry!(KeyDown(BracketRight); action_dispatch=ShapeToolMessage::IncreaseSides),
181+
entry!(PointerMove; refresh_keys=[Alt, Shift, Control], action_dispatch=ShapeToolMessage::PointerMove([Alt, Shift, Control, Shift])),
182+
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
183+
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
184+
entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
185+
entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
186+
entry!(KeyDown(ArrowDown); modifiers=[Shift, ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
187+
entry!(KeyDown(ArrowDown); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
188+
entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowUp], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
189+
entry!(KeyDown(ArrowLeft); modifiers=[Shift, ArrowDown], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
190+
entry!(KeyDown(ArrowLeft); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }),
191+
entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowUp], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
192+
entry!(KeyDown(ArrowRight); modifiers=[Shift, ArrowDown], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
193+
entry!(KeyDown(ArrowRight); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }),
194+
entry!(KeyDown(ArrowUp); modifiers=[ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
195+
entry!(KeyDown(ArrowUp); modifiers=[ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
196+
entry!(KeyDown(ArrowUp); action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
197+
entry!(KeyDown(ArrowDown); modifiers=[ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
198+
entry!(KeyDown(ArrowDown); modifiers=[ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
199+
entry!(KeyDown(ArrowDown); action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
200+
entry!(KeyDown(ArrowLeft); modifiers=[ArrowUp], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
201+
entry!(KeyDown(ArrowLeft); modifiers=[ArrowDown], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
202+
entry!(KeyDown(ArrowLeft); action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }),
203+
entry!(KeyDown(ArrowRight); modifiers=[ArrowUp], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: -NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
204+
entry!(KeyDown(ArrowRight); modifiers=[ArrowDown], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
205+
entry!(KeyDown(ArrowRight); action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: NUDGE_AMOUNT, delta_y: 0., resize: Alt, resize_opposite_corner: Control }),
206+
entry!(KeyDown(ArrowUp); action_dispatch=ShapeToolMessage::IncreaseSides),
207+
entry!(KeyDown(ArrowDown); action_dispatch=ShapeToolMessage::DecreaseSides),
180208
//
181209
// ImaginateToolMessage
182210
// entry!(KeyDown(MouseLeft); action_dispatch=ImaginateToolMessage::DragStart),
@@ -185,27 +213,6 @@ pub fn input_mappings() -> Mapping {
185213
// entry!(KeyDown(Escape); action_dispatch=ImaginateToolMessage::Abort),
186214
// entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=ImaginateToolMessage::Resize { center: Alt, lock_ratio: Shift }),
187215
//
188-
// EllipseToolMessage
189-
entry!(KeyDown(MouseLeft); action_dispatch=EllipseToolMessage::DragStart),
190-
entry!(KeyUp(MouseLeft); action_dispatch=EllipseToolMessage::DragStop),
191-
entry!(KeyDown(MouseRight); action_dispatch=EllipseToolMessage::Abort),
192-
entry!(KeyDown(Escape); action_dispatch=EllipseToolMessage::Abort),
193-
entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=EllipseToolMessage::PointerMove { center: Alt, lock_ratio: Shift }),
194-
//
195-
// PolygonToolMessage
196-
entry!(KeyDown(MouseLeft); action_dispatch=PolygonToolMessage::DragStart),
197-
entry!(KeyUp(MouseLeft); action_dispatch=PolygonToolMessage::DragStop),
198-
entry!(KeyDown(MouseRight); action_dispatch=PolygonToolMessage::Abort),
199-
entry!(KeyDown(Escape); action_dispatch=PolygonToolMessage::Abort),
200-
entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=PolygonToolMessage::PointerMove { center: Alt, lock_ratio: Shift }),
201-
//
202-
// LineToolMessage
203-
entry!(KeyDown(MouseLeft); action_dispatch=LineToolMessage::DragStart),
204-
entry!(KeyUp(MouseLeft); action_dispatch=LineToolMessage::DragStop),
205-
entry!(KeyDown(MouseRight); action_dispatch=LineToolMessage::Abort),
206-
entry!(KeyDown(Escape); action_dispatch=LineToolMessage::Abort),
207-
entry!(PointerMove; refresh_keys=[Control, Alt, Shift], action_dispatch=LineToolMessage::PointerMove { center: Alt, lock_angle: Control, snap_angle: Shift }),
208-
//
209216
// PathToolMessage
210217
entry!(KeyDown(Delete); modifiers=[Accel], action_dispatch=PathToolMessage::DeleteAndBreakPath),
211218
entry!(KeyDown(Backspace); modifiers=[Accel], action_dispatch=PathToolMessage::DeleteAndBreakPath),
@@ -308,10 +315,10 @@ pub fn input_mappings() -> Mapping {
308315
entry!(KeyDown(KeyA); action_dispatch=ToolMessage::ActivateToolPath),
309316
entry!(KeyDown(KeyP); action_dispatch=ToolMessage::ActivateToolPen),
310317
entry!(KeyDown(KeyN); action_dispatch=ToolMessage::ActivateToolFreehand),
311-
entry!(KeyDown(KeyL); action_dispatch=ToolMessage::ActivateToolLine),
312-
entry!(KeyDown(KeyM); action_dispatch=ToolMessage::ActivateToolRectangle),
313-
entry!(KeyDown(KeyE); action_dispatch=ToolMessage::ActivateToolEllipse),
314-
entry!(KeyDown(KeyY); action_dispatch=ToolMessage::ActivateToolPolygon),
318+
entry!(KeyDown(KeyL); action_dispatch=ToolMessage::ActivateToolShapeLine),
319+
entry!(KeyDown(KeyM); action_dispatch=ToolMessage::ActivateToolShapeRectangle),
320+
entry!(KeyDown(KeyE); action_dispatch=ToolMessage::ActivateToolShapeEllipse),
321+
entry!(KeyDown(KeyY); action_dispatch=ToolMessage::ActivateToolShape),
315322
entry!(KeyDown(KeyB); action_dispatch=ToolMessage::ActivateToolBrush),
316323
entry!(KeyDown(KeyX); modifiers=[Accel, Shift], action_dispatch=ToolMessage::ResetColors),
317324
entry!(KeyDown(KeyX); modifiers=[Shift], action_dispatch=ToolMessage::SwapColors),

editor/src/messages/layout/layout_message_handler.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ impl LayoutMessageHandler {
121121
};
122122

123123
(|| {
124-
let update_value = value.as_object().expect("ColorInput update was not of type: object");
124+
let Some(update_value) = value.as_object() else {
125+
warn!("ColorInput update was not of type: object");
126+
return Message::NoOp;
127+
};
125128

126129
// None
127130
let is_none = update_value.get("none").and_then(|x| x.as_bool());
@@ -154,7 +157,8 @@ impl LayoutMessageHandler {
154157
return (color_button.on_update.callback)(color_button);
155158
}
156159

157-
panic!("ColorInput update was not able to be parsed with color data: {color_button:?}");
160+
warn!("ColorInput update was not able to be parsed with color data: {color_button:?}");
161+
Message::NoOp
158162
})()
159163
}
160164
};

0 commit comments

Comments
 (0)