Add rotation custom cursor icon for the transform cage
This commit is contained in:
parent
782f528279
commit
3f98d1c896
|
|
@ -34,6 +34,7 @@ pub enum MouseCursorIcon {
|
||||||
EWResize,
|
EWResize,
|
||||||
NESWResize,
|
NESWResize,
|
||||||
NWSEResize,
|
NWSEResize,
|
||||||
|
Rotate,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
|
|
||||||
|
|
@ -1037,19 +1037,19 @@ fn node_section_node_graph_frame(node_graph_frame: &NodeGraphFrameLayer) -> Layo
|
||||||
layout: vec![
|
layout: vec![
|
||||||
LayoutGroup::Row {
|
LayoutGroup::Row {
|
||||||
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
||||||
value: "Temporary layer that applies a greyscale to the layers below it.".into(),
|
value: "Temporary layer that applies a grayscale to the layers below it.".into(),
|
||||||
..TextLabel::default()
|
..TextLabel::default()
|
||||||
}))],
|
}))],
|
||||||
},
|
},
|
||||||
LayoutGroup::Row {
|
LayoutGroup::Row {
|
||||||
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
widgets: vec![WidgetHolder::new(Widget::TextLabel(TextLabel {
|
||||||
value: "Powered by the node graph :)".into(),
|
value: "Powered by the node graph! :)".into(),
|
||||||
..TextLabel::default()
|
..TextLabel::default()
|
||||||
}))],
|
}))],
|
||||||
},
|
},
|
||||||
LayoutGroup::Row {
|
LayoutGroup::Row {
|
||||||
widgets: vec![WidgetHolder::new(Widget::TextButton(TextButton {
|
widgets: vec![WidgetHolder::new(Widget::TextButton(TextButton {
|
||||||
label: "Open Node Graph UI (todo)".into(),
|
label: "Open Node Graph UI (coming soon)".into(),
|
||||||
tooltip: "Open the node graph associated with this layer".into(),
|
tooltip: "Open the node graph associated with this layer".into(),
|
||||||
on_update: WidgetCallback::new(|_| DialogMessage::RequestComingSoonDialog { issue: Some(800) }.into()),
|
on_update: WidgetCallback::new(|_| DialogMessage::RequestComingSoonDialog { issue: Some(800) }.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
||||||
|
|
@ -333,7 +333,7 @@ impl BoundingBoxOverlays {
|
||||||
_ => MouseCursorIcon::Default,
|
_ => MouseCursorIcon::Default,
|
||||||
}
|
}
|
||||||
} else if rotate && self.check_rotate(input.mouse.position) {
|
} else if rotate && self.check_rotate(input.mouse.position) {
|
||||||
MouseCursorIcon::Grabbing
|
MouseCursorIcon::Rotate
|
||||||
} else {
|
} else {
|
||||||
MouseCursorIcon::Default
|
MouseCursorIcon::Default
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ export default defineComponent({
|
||||||
// CSS properties
|
// CSS properties
|
||||||
canvasSvgWidth: undefined as number | undefined,
|
canvasSvgWidth: undefined as number | undefined,
|
||||||
canvasSvgHeight: undefined as number | undefined,
|
canvasSvgHeight: undefined as number | undefined,
|
||||||
canvasCursor: "default" as MouseCursorIcon,
|
canvasCursor: "default",
|
||||||
|
|
||||||
// Scrollbars
|
// Scrollbars
|
||||||
scrollbarPos,
|
scrollbarPos,
|
||||||
|
|
@ -451,7 +451,30 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
// Update mouse cursor icon
|
// Update mouse cursor icon
|
||||||
updateMouseCursor(cursor: MouseCursorIcon) {
|
updateMouseCursor(cursor: MouseCursorIcon) {
|
||||||
this.canvasCursor = cursor;
|
let cursorString: string = cursor;
|
||||||
|
|
||||||
|
// This isn't very clean but it's good enough for now until we need more icons, then we can build something more robust (consider blob URLs)
|
||||||
|
if (cursor === "custom-rotate") {
|
||||||
|
const svg = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20">
|
||||||
|
<path transform="translate(2 2)" fill="black" stroke="black" stroke-width="2px" d="
|
||||||
|
M8,15.2C4,15.2,0.8,12,0.8,8C0.8,4,4,0.8,8,0.8c2,0,3.9,0.8,5.3,2.3l-1,1C11.2,2.9,9.6,2.2,8,2.2C4.8,2.2,2.2,4.8,2.2,8s2.6,5.8,5.8,5.8s5.8-2.6,5.8-5.8h1.4C15.2,12,12,15.2,8,15.2z
|
||||||
|
" />
|
||||||
|
<polygon transform="translate(2 2)" fill="black" stroke="black" stroke-width="2px" points="12.6,0 15.5,5 9.7,5" />
|
||||||
|
<path transform="translate(2 2)" fill="white" d="
|
||||||
|
M8,15.2C4,15.2,0.8,12,0.8,8C0.8,4,4,0.8,8,0.8c2,0,3.9,0.8,5.3,2.3l-1,1C11.2,2.9,9.6,2.2,8,2.2C4.8,2.2,2.2,4.8,2.2,8s2.6,5.8,5.8,5.8s5.8-2.6,5.8-5.8h1.4C15.2,12,12,15.2,8,15.2z
|
||||||
|
" />
|
||||||
|
<polygon transform="translate(2 2)" fill="white" points="12.6,0 15.5,5 9.7,5" />
|
||||||
|
</svg>
|
||||||
|
`
|
||||||
|
.split("\n")
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.join("");
|
||||||
|
|
||||||
|
cursorString = `url('data:image/svg+xml;utf8,${svg}') 8 8, alias`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.canvasCursor = cursorString;
|
||||||
},
|
},
|
||||||
// Text entry
|
// Text entry
|
||||||
triggerTextCommit() {
|
triggerTextCommit() {
|
||||||
|
|
|
||||||
|
|
@ -410,6 +410,7 @@ export class UpdateEyedropperSamplingState extends JsMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mouseCursorIconCSSNames = {
|
const mouseCursorIconCSSNames = {
|
||||||
|
Default: "default",
|
||||||
None: "none",
|
None: "none",
|
||||||
ZoomIn: "zoom-in",
|
ZoomIn: "zoom-in",
|
||||||
ZoomOut: "zoom-out",
|
ZoomOut: "zoom-out",
|
||||||
|
|
@ -421,12 +422,13 @@ const mouseCursorIconCSSNames = {
|
||||||
EWResize: "ew-resize",
|
EWResize: "ew-resize",
|
||||||
NESWResize: "nesw-resize",
|
NESWResize: "nesw-resize",
|
||||||
NWSEResize: "nwse-resize",
|
NWSEResize: "nwse-resize",
|
||||||
|
Rotate: "custom-rotate",
|
||||||
} as const;
|
} as const;
|
||||||
export type MouseCursor = keyof typeof mouseCursorIconCSSNames;
|
export type MouseCursor = keyof typeof mouseCursorIconCSSNames;
|
||||||
export type MouseCursorIcon = typeof mouseCursorIconCSSNames[MouseCursor];
|
export type MouseCursorIcon = typeof mouseCursorIconCSSNames[MouseCursor];
|
||||||
|
|
||||||
export class UpdateMouseCursor extends JsMessage {
|
export class UpdateMouseCursor extends JsMessage {
|
||||||
@Transform(({ value }: { value: MouseCursor }) => mouseCursorIconCSSNames[value] || "default")
|
@Transform(({ value }: { value: MouseCursor }) => mouseCursorIconCSSNames[value] || "alias")
|
||||||
readonly cursor!: MouseCursorIcon;
|
readonly cursor!: MouseCursorIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -314,17 +314,17 @@ mod protograph_testing {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn greyscale_colour() {
|
fn grayscale_color() {
|
||||||
let stack = FixedSizeStack::new(256);
|
let stack = FixedSizeStack::new(256);
|
||||||
let val_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(Color::from_rgb8(10, 20, 30))));
|
let val_protonode = ProtoNode::value(ConstructionArgs::Value(Box::new(Color::from_rgb8(10, 20, 30))));
|
||||||
push_node(val_protonode, &stack);
|
push_node(val_protonode, &stack);
|
||||||
|
|
||||||
let greyscale_protonode = ProtoNode {
|
let grayscale_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::Nodes(vec![]),
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
input: ProtoNodeInput::Node(0),
|
input: ProtoNodeInput::Node(0),
|
||||||
identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]),
|
identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]),
|
||||||
};
|
};
|
||||||
push_node(greyscale_protonode, &stack);
|
push_node(grayscale_protonode, &stack);
|
||||||
|
|
||||||
let result = unsafe { stack.get()[1].eval(Box::new(())) };
|
let result = unsafe { stack.get()[1].eval(Box::new(())) };
|
||||||
let val = *dyn_any::downcast::<Color>(result).unwrap();
|
let val = *dyn_any::downcast::<Color>(result).unwrap();
|
||||||
|
|
@ -347,7 +347,7 @@ mod protograph_testing {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn greyscale_map_image() {
|
fn grayscale_map_image() {
|
||||||
let stack = FixedSizeStack::new(256);
|
let stack = FixedSizeStack::new(256);
|
||||||
let image_protonode = ProtoNode {
|
let image_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::Nodes(vec![]),
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
|
|
@ -356,12 +356,12 @@ mod protograph_testing {
|
||||||
};
|
};
|
||||||
push_node(image_protonode, &stack);
|
push_node(image_protonode, &stack);
|
||||||
|
|
||||||
let greyscale_protonode = ProtoNode {
|
let grayscale_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::Nodes(vec![]),
|
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||||
input: ProtoNodeInput::None,
|
input: ProtoNodeInput::None,
|
||||||
identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]),
|
identifier: NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]),
|
||||||
};
|
};
|
||||||
push_node(greyscale_protonode, &stack);
|
push_node(grayscale_protonode, &stack);
|
||||||
|
|
||||||
let image_map_protonode = ProtoNode {
|
let image_map_protonode = ProtoNode {
|
||||||
construction_args: ConstructionArgs::Nodes(vec![1]),
|
construction_args: ConstructionArgs::Nodes(vec![1]),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue