Replace text-only tooltips with custom richly styled tooltips (#3436)

* Replace the title attribute with custom FloatingMenu tooltips

* Separate tooltip labels and descriptions into two styled blocks

* Move keyboard shortcut tooltips to a separate section at the bottom

* Update shortcut key styling in tooltips and hints bar

* Fix .to_string()
This commit is contained in:
Keavon Chambers
2025-11-30 13:32:58 -08:00
committed by GitHub
parent 94e5c8fc05
commit e8ebcc2c21
94 changed files with 1323 additions and 580 deletions
@@ -97,13 +97,13 @@ impl DataPanelMessageHandler {
widgets.extend([
if is_layer {
IconLabel::new("Layer").tooltip("Name of the selected layer").widget_holder()
IconLabel::new("Layer").tooltip_description("Name of the selected layer.").widget_holder()
} else {
IconLabel::new("Node").tooltip("Name of the selected node").widget_holder()
IconLabel::new("Node").tooltip_description("Name of the selected node.").widget_holder()
},
Separator::new(SeparatorType::Related).widget_holder(),
TextInput::new(network_interface.display_name(&node_id, &[]))
.tooltip(if is_layer { "Name of the selected layer" } else { "Name of the selected node" })
.tooltip_description(if is_layer { "Name of the selected layer." } else { "Name of the selected node." })
.on_update(move |text_input| {
NodeGraphMessage::SetDisplayName {
node_id,
@@ -2211,21 +2211,21 @@ impl DocumentMessageHandler {
let mut widgets = vec![
IconButton::new("PlaybackToStart", 24)
.tooltip("Restart Animation")
.tooltip_shortcut(action_keys!(AnimationMessageDiscriminant::RestartAnimation))
.tooltip_label("Restart Animation")
.shortcut_keys(action_keys!(AnimationMessageDiscriminant::RestartAnimation))
.on_update(|_| AnimationMessage::RestartAnimation.into())
.disabled(time == Duration::ZERO)
.widget_holder(),
IconButton::new(if animation_is_playing { "PlaybackPause" } else { "PlaybackPlay" }, 24)
.tooltip(if animation_is_playing { "Pause Animation" } else { "Play Animation" })
.tooltip_shortcut(action_keys!(AnimationMessageDiscriminant::ToggleLivePreview))
.tooltip_label(if animation_is_playing { "Pause Animation" } else { "Play Animation" })
.shortcut_keys(action_keys!(AnimationMessageDiscriminant::ToggleLivePreview))
.on_update(|_| AnimationMessage::ToggleLivePreview.into())
.widget_holder(),
Separator::new(SeparatorType::Unrelated).widget_holder(),
CheckboxInput::new(self.overlays_visibility_settings.all)
.icon("Overlays")
.tooltip("Overlays")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleOverlaysVisibility))
.tooltip_label("Overlays")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::ToggleOverlaysVisibility))
.on_update(|optional_input: &CheckboxInput| {
DocumentMessage::SetOverlaysVisibility {
visible: optional_input.checked,
@@ -2473,8 +2473,8 @@ impl DocumentMessageHandler {
Separator::new(SeparatorType::Related).widget_holder(),
CheckboxInput::new(snapping_state.snapping_enabled)
.icon("Snapping")
.tooltip("Snapping")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleSnapping))
.tooltip_label("Snapping")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::ToggleSnapping))
.on_update(move |optional_input: &CheckboxInput| {
DocumentMessage::SetSnapping {
closure: Some(|snapping_state| &mut snapping_state.snapping_enabled),
@@ -2494,7 +2494,7 @@ impl DocumentMessageHandler {
},
]
.into_iter()
.chain(SNAP_FUNCTIONS_FOR_BOUNDING_BOXES.into_iter().map(|(name, closure, tooltip)| LayoutGroup::Row {
.chain(SNAP_FUNCTIONS_FOR_BOUNDING_BOXES.into_iter().map(|(name, closure, description)| LayoutGroup::Row {
widgets: {
let checkbox_id = CheckboxId::new();
vec![
@@ -2506,17 +2506,18 @@ impl DocumentMessageHandler {
}
.into()
})
.tooltip(tooltip)
.tooltip_label(name)
.tooltip_description(description)
.for_label(checkbox_id)
.widget_holder(),
TextLabel::new(name).tooltip(tooltip).for_checkbox(checkbox_id).widget_holder(),
TextLabel::new(name).tooltip_label(name).tooltip_description(description).for_checkbox(checkbox_id).widget_holder(),
]
},
}))
.chain([LayoutGroup::Row {
widgets: vec![TextLabel::new(SnappingOptions::Paths.to_string()).widget_holder()],
}])
.chain(SNAP_FUNCTIONS_FOR_PATHS.into_iter().map(|(name, closure, tooltip)| LayoutGroup::Row {
.chain(SNAP_FUNCTIONS_FOR_PATHS.into_iter().map(|(name, closure, description)| LayoutGroup::Row {
widgets: {
let checkbox_id = CheckboxId::new();
vec![
@@ -2528,10 +2529,11 @@ impl DocumentMessageHandler {
}
.into()
})
.tooltip(tooltip)
.tooltip_label(name)
.tooltip_description(description)
.for_label(checkbox_id)
.widget_holder(),
TextLabel::new(name).tooltip(tooltip).for_checkbox(checkbox_id).widget_holder(),
TextLabel::new(name).tooltip_label(name).tooltip_description(description).for_checkbox(checkbox_id).widget_holder(),
]
},
}))
@@ -2541,8 +2543,8 @@ impl DocumentMessageHandler {
Separator::new(SeparatorType::Related).widget_holder(),
CheckboxInput::new(self.snapping_state.grid_snapping)
.icon("Grid")
.tooltip("Grid")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleGridVisibility))
.tooltip_label("Grid")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::ToggleGridVisibility))
.on_update(|optional_input: &CheckboxInput| DocumentMessage::GridVisibility { visible: optional_input.checked }.into())
.widget_holder(),
PopoverButton::new()
@@ -2553,19 +2555,19 @@ impl DocumentMessageHandler {
RadioInput::new(vec![
RadioEntryData::new("Normal")
.icon("RenderModeNormal")
.tooltip("Render Mode: Normal")
.tooltip_label("Render Mode: Normal")
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Normal }.into()),
RadioEntryData::new("Outline")
.icon("RenderModeOutline")
.tooltip("Render Mode: Outline")
.tooltip_label("Render Mode: Outline")
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Outline }.into()),
// RadioEntryData::new("PixelPreview")
// .icon("RenderModePixels")
// .tooltip("Render Mode: Pixel Preview")
// .tooltip_label("Render Mode: Pixel Preview")
// .on_update(|_| DialogMessage::RequestComingSoonDialog { issue: Some(320) }.into()),
// RadioEntryData::new("SvgPreview")
// .icon("RenderModeSvg")
// .tooltip("Render Mode: SVG Preview")
// .tooltip_label("Render Mode: SVG Preview")
// .on_update(|_| DialogMessage::RequestComingSoonDialog { issue: Some(1845) }.into()),
])
.selected_index(Some(self.render_mode as u32))
@@ -2607,7 +2609,7 @@ impl DocumentMessageHandler {
}
.into()
})
.tooltip("Canvas Tilt")
.tooltip_label("Canvas Tilt")
.on_update(|number_input: &NumberInput| {
NavigationMessage::CanvasTiltSet {
angle_radians: number_input.value.unwrap().to_radians(),
@@ -2623,8 +2625,8 @@ impl DocumentMessageHandler {
TextButton::new("Node Graph")
.icon(Some((if self.graph_view_overlay_open { "GraphViewOpen" } else { "GraphViewClosed" }).into()))
.hover_icon(Some((if self.graph_view_overlay_open { "GraphViewClosed" } else { "GraphViewOpen" }).into()))
.tooltip(if self.graph_view_overlay_open { "Hide Node Graph" } else { "Show Node Graph" })
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle))
.tooltip_label(if self.graph_view_overlay_open { "Hide Node Graph" } else { "Show Node Graph" })
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle))
.on_update(move |_| DocumentMessage::GraphViewOverlayToggle.into())
.widget_holder(),
]);
@@ -2723,7 +2725,7 @@ impl DocumentMessageHandler {
.disabled(disabled)
.draw_icon(false)
.max_width(100)
.tooltip("Blend Mode")
.tooltip_label("Blend Mode")
.widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
NumberInput::new(opacity)
@@ -2745,7 +2747,7 @@ impl DocumentMessageHandler {
})
.on_commit(|_| DocumentMessage::AddTransaction.into())
.max_width(100)
.tooltip("Opacity")
.tooltip_label("Opacity")
.widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
NumberInput::new(fill)
@@ -2767,7 +2769,7 @@ impl DocumentMessageHandler {
})
.on_commit(|_| DocumentMessage::AddTransaction.into())
.max_width(100)
.tooltip("Fill")
.tooltip_label("Fill")
.widget_holder(),
];
let layers_panel_control_bar_left = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]);
@@ -2775,15 +2777,15 @@ impl DocumentMessageHandler {
let widgets = vec![
IconButton::new(if selection_all_locked { "PadlockLocked" } else { "PadlockUnlocked" }, 24)
.hover_icon(Some((if selection_all_locked { "PadlockUnlocked" } else { "PadlockLocked" }).into()))
.tooltip(if selection_all_locked { "Unlock Selected" } else { "Lock Selected" })
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleSelectedLocked))
.tooltip_label(if selection_all_locked { "Unlock Selected" } else { "Lock Selected" })
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::ToggleSelectedLocked))
.on_update(|_| NodeGraphMessage::ToggleSelectedLocked.into())
.disabled(!has_selection)
.widget_holder(),
IconButton::new(if selection_all_visible { "EyeVisible" } else { "EyeHidden" }, 24)
.hover_icon(Some((if selection_all_visible { "EyeHide" } else { "EyeShow" }).into()))
.tooltip(if selection_all_visible { "Hide Selected" } else { "Show Selected" })
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ToggleSelectedVisibility))
.tooltip_label(if selection_all_visible { "Hide Selected" } else { "Show Selected" })
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::ToggleSelectedVisibility))
.on_update(|_| DocumentMessage::ToggleSelectedVisibility.into())
.disabled(!has_selection)
.widget_holder(),
@@ -2816,7 +2818,7 @@ impl DocumentMessageHandler {
PopoverButton::new()
.icon(Some("Node".to_string()))
.menu_direction(Some(MenuDirection::Top))
.tooltip("Add an operation to the end of this layer's chain of nodes")
.tooltip_description("Add an operation to the end of this layer's chain of nodes.")
.disabled(!has_selection || has_multiple_selection)
.popover_layout({
// Showing only compatible types for the layer based on the output type of the node upstream from its horizontal input
@@ -2847,8 +2849,8 @@ impl DocumentMessageHandler {
.widget_holder(),
Separator::new(SeparatorType::Unrelated).widget_holder(),
IconButton::new("Folder", 24)
.tooltip("Group Selected")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GroupSelectedLayers))
.tooltip_label("Group Selected")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::GroupSelectedLayers))
.on_update(|_| {
let group_folder_type = GroupFolderType::Layer;
DocumentMessage::GroupSelectedLayers { group_folder_type }.into()
@@ -2856,13 +2858,13 @@ impl DocumentMessageHandler {
.disabled(!has_selection)
.widget_holder(),
IconButton::new("NewLayer", 24)
.tooltip("New Layer")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder))
.tooltip_label("New Layer")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder))
.on_update(|_| DocumentMessage::CreateEmptyFolder.into())
.widget_holder(),
IconButton::new("Trash", 24)
.tooltip("Delete Selected")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::DeleteSelectedLayers))
.tooltip_label("Delete Selected")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::DeleteSelectedLayers))
.on_update(|_| DocumentMessage::DeleteSelectedLayers.into())
.disabled(!has_selection)
.widget_holder(),
@@ -3145,18 +3147,18 @@ impl<'a> ClickXRayIter<'a> {
pub fn navigation_controls(ptz: &PTZ, navigation_handler: &NavigationMessageHandler, node_graph: bool) -> Vec<WidgetHolder> {
let mut list = vec![
IconButton::new("ZoomIn", 24)
.tooltip("Zoom In")
.tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::CanvasZoomIncrease))
.tooltip_label("Zoom In")
.shortcut_keys(action_keys!(NavigationMessageDiscriminant::CanvasZoomIncrease))
.on_update(|_| NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }.into())
.widget_holder(),
IconButton::new("ZoomOut", 24)
.tooltip("Zoom Out")
.tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::CanvasZoomDecrease))
.tooltip_label("Zoom Out")
.shortcut_keys(action_keys!(NavigationMessageDiscriminant::CanvasZoomDecrease))
.on_update(|_| NavigationMessage::CanvasZoomDecrease { center_on_mouse: false }.into())
.widget_holder(),
IconButton::new("ZoomReset", 24)
.tooltip("Reset Tilt and Zoom to 100%")
.tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::CanvasTiltResetAndZoomTo100Percent))
.tooltip_label("Reset Tilt and Zoom to 100%")
.shortcut_keys(action_keys!(NavigationMessageDiscriminant::CanvasTiltResetAndZoomTo100Percent))
.on_update(|_| NavigationMessage::CanvasTiltResetAndZoomTo100Percent.into())
.disabled(ptz.tilt().abs() < 1e-4 && (ptz.zoom() - 1.).abs() < 1e-4)
.widget_holder(),
@@ -3164,8 +3166,9 @@ pub fn navigation_controls(ptz: &PTZ, navigation_handler: &NavigationMessageHand
if ptz.flip && !node_graph {
list.push(
IconButton::new("Reverse", 24)
.tooltip("Flip the canvas back to its standard orientation")
.tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::CanvasFlip))
.tooltip_label("Unflip Canvas")
.tooltip_description("Flip the canvas back to its standard orientation.")
.shortcut_keys(action_keys!(NavigationMessageDiscriminant::CanvasFlip))
.on_update(|_| NavigationMessage::CanvasFlip.into())
.widget_holder(),
);
@@ -3176,7 +3179,7 @@ pub fn navigation_controls(ptz: &PTZ, navigation_handler: &NavigationMessageHand
.unit("%")
.min(0.000001)
.max(1000000.)
.tooltip(if node_graph { "Node Graph Zoom" } else { "Canvas Zoom" })
.tooltip_label(if node_graph { "Node Graph Zoom" } else { "Canvas Zoom" })
.on_update(|number_input: &NumberInput| {
NavigationMessage::CanvasZoomSet {
zoom_factor: number_input.value.unwrap() / 100.,
@@ -137,7 +137,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
},
},
description: Cow::Borrowed("A default node network you can use to create your own custom nodes."),
description: Cow::Borrowed("An empty node network you can use to create your own custom nodes."),
properties: None,
},
DocumentNodeDefinition {
@@ -156,7 +156,10 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
},
},
description: Cow::Borrowed("TODO"),
description: Cow::Borrowed(
"Improves rendering performance if used in rare circumstances where automatic caching is not yet advanced enough to handle the situation.
Stores the last evaluated data that flowed through this node, and immediately returns that data on subsequent renders if the context has not changed.",
),
properties: None,
},
DocumentNodeDefinition {
@@ -1153,7 +1156,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
},
},
description: Cow::Borrowed("Generates different noise patterns."),
description: Cow::Borrowed("Generates customizable procedural noise patterns."),
properties: None,
},
DocumentNodeDefinition {
@@ -1335,7 +1338,9 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
},
description: Cow::Borrowed(
"Decomposes the X and Y components of a vec2.\n\nThe inverse of this node is \"Vec2 Value\", which can have either or both its X and Y parameters exposed as graph inputs.",
"Decomposes the X and Y components of a vec2.\n\
\n\
The inverse of this node is \"Vec2 Value\", which can have either or both its X and Y parameters exposed as graph inputs.",
),
properties: None,
},
@@ -2008,10 +2013,10 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
}),
input_metadata: vec![
("Content", "The shape to be resampled and converted into a polyline.").into(),
("Spacing", node_properties::SAMPLE_POLYLINE_TOOLTIP_SPACING).into(),
("Spacing", node_properties::SAMPLE_POLYLINE_DESCRIPTION_SPACING).into(),
InputMetadata::with_name_description_override(
"Separation",
node_properties::SAMPLE_POLYLINE_TOOLTIP_SEPARATION,
node_properties::SAMPLE_POLYLINE_DESCRIPTION_SEPARATION,
WidgetOverride::Number(NumberInputSettings {
min: Some(0.),
unit: Some(" px".to_string()),
@@ -2020,7 +2025,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
),
InputMetadata::with_name_description_override(
"Quantity",
node_properties::SAMPLE_POLYLINE_TOOLTIP_QUANTITY,
node_properties::SAMPLE_POLYLINE_DESCRIPTION_QUANTITY,
WidgetOverride::Number(NumberInputSettings {
min: Some(2.),
is_integer: true,
@@ -2029,7 +2034,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
),
InputMetadata::with_name_description_override(
"Start Offset",
node_properties::SAMPLE_POLYLINE_TOOLTIP_START_OFFSET,
node_properties::SAMPLE_POLYLINE_DESCRIPTION_START_OFFSET,
WidgetOverride::Number(NumberInputSettings {
min: Some(0.),
unit: Some(" px".to_string()),
@@ -2038,14 +2043,14 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
),
InputMetadata::with_name_description_override(
"Stop Offset",
node_properties::SAMPLE_POLYLINE_TOOLTIP_STOP_OFFSET,
node_properties::SAMPLE_POLYLINE_DESCRIPTION_STOP_OFFSET,
WidgetOverride::Number(NumberInputSettings {
min: Some(0.),
unit: Some(" px".to_string()),
..Default::default()
}),
),
("Adaptive Spacing", node_properties::SAMPLE_POLYLINE_TOOLTIP_ADAPTIVE_SPACING).into(),
("Adaptive Spacing", node_properties::SAMPLE_POLYLINE_DESCRIPTION_ADAPTIVE_SPACING).into(),
],
output_names: vec!["Vector".to_string()],
..Default::default()
@@ -1,6 +1,7 @@
use super::utility_types::{BoxSelection, ContextMenuInformation, DragStart, FrontendNode};
use super::{document_node_definitions, node_properties};
use crate::consts::GRID_SIZE;
use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup;
use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::document_message_handler::navigation_controls;
@@ -2105,7 +2106,9 @@ impl NodeGraphMessageHandler {
let mut widgets = vec![
PopoverButton::new()
.icon(Some("Node".to_string()))
.tooltip("New Node (Right Click)")
.tooltip_label("New Node")
.tooltip_description("To add a node at the pointer location, perform the shortcut in an open area of the graph.")
.tooltip_shortcut(Key::MouseRight.to_string())
.popover_layout({
// Showing only compatible types
let compatible_type = match (selection_includes_layers, has_multiple_selection, selected_layer) {
@@ -2150,8 +2153,8 @@ impl NodeGraphMessageHandler {
Separator::new(SeparatorType::Unrelated).widget_holder(),
//
IconButton::new("Folder", 24)
.tooltip("Group Selected")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GroupSelectedLayers))
.tooltip_label("Group Selected")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::GroupSelectedLayers))
.on_update(|_| {
let group_folder_type = GroupFolderType::Layer;
DocumentMessage::GroupSelectedLayers { group_folder_type }.into()
@@ -2159,13 +2162,13 @@ impl NodeGraphMessageHandler {
.disabled(!has_selection)
.widget_holder(),
IconButton::new("NewLayer", 24)
.tooltip("New Layer")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder))
.tooltip_label("New Layer")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder))
.on_update(|_| DocumentMessage::CreateEmptyFolder.into())
.widget_holder(),
IconButton::new("Trash", 24)
.tooltip("Delete Selected")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::DeleteSelectedLayers))
.tooltip_label("Delete Selected")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::DeleteSelectedLayers))
.on_update(|_| DocumentMessage::DeleteSelectedLayers.into())
.disabled(!has_selection)
.widget_holder(),
@@ -2174,15 +2177,15 @@ impl NodeGraphMessageHandler {
//
IconButton::new(if selection_all_locked { "PadlockLocked" } else { "PadlockUnlocked" }, 24)
.hover_icon(Some((if selection_all_locked { "PadlockUnlocked" } else { "PadlockLocked" }).into()))
.tooltip(if selection_all_locked { "Unlock Selected" } else { "Lock Selected" })
.tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedLocked))
.tooltip_label(if selection_all_locked { "Unlock Selected" } else { "Lock Selected" })
.shortcut_keys(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedLocked))
.on_update(|_| NodeGraphMessage::ToggleSelectedLocked.into())
.disabled(!has_selection || !selection_includes_layers)
.widget_holder(),
IconButton::new(if selection_all_visible { "EyeVisible" } else { "EyeHidden" }, 24)
.hover_icon(Some((if selection_all_visible { "EyeHide" } else { "EyeShow" }).into()))
.tooltip(if selection_all_visible { "Hide Selected" } else { "Show Selected" })
.tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedVisibility))
.tooltip_label(if selection_all_visible { "Hide Selected" } else { "Show Selected" })
.shortcut_keys(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedVisibility))
.on_update(|_| NodeGraphMessage::ToggleSelectedVisibility.into())
.disabled(!has_selection)
.widget_holder(),
@@ -2208,7 +2211,7 @@ impl NodeGraphMessageHandler {
if let Some(node_id) = previewing {
let button = TextButton::new("End Preview")
.icon(Some("FrameAll".to_string()))
.tooltip("Restore preview to the graph output")
.tooltip_description("Restore preview to the graph output.")
.on_update(move |_| NodeGraphMessage::TogglePreview { node_id }.into())
.widget_holder();
widgets.extend([Separator::new(SeparatorType::Unrelated).widget_holder(), button]);
@@ -2220,7 +2223,9 @@ impl NodeGraphMessageHandler {
if selection_is_not_already_the_output && no_other_selections {
let button = TextButton::new("Preview")
.icon(Some("FrameAll".to_string()))
.tooltip("Preview selected node/layer (Shortcut: Alt-click node/layer)")
.tooltip_label("Preview")
.tooltip_description("Temporarily set the graph output to the selected node or layer. Perform the shortcut on a node or layer for quick access.")
.tooltip_shortcut(KeysGroup(vec![Key::Alt, Key::MouseLeft]).to_string())
.on_update(move |_| NodeGraphMessage::TogglePreview { node_id }.into())
.widget_holder();
widgets.extend([Separator::new(SeparatorType::Unrelated).widget_holder(), button]);
@@ -2262,7 +2267,7 @@ impl NodeGraphMessageHandler {
.percentage()
.display_decimal_places(0)
.label("Fade Artwork")
.tooltip("Opacity of the graph background that covers the artwork")
.tooltip_description("Opacity of the graph background that covers the artwork.")
.on_update(move |number_input: &NumberInput| {
DocumentMessage::SetGraphFadeArtwork {
percentage: number_input.value.unwrap_or(graph_fade_artwork_percentage),
@@ -2278,8 +2283,8 @@ impl NodeGraphMessageHandler {
TextButton::new("Node Graph")
.icon(Some("GraphViewOpen".into()))
.hover_icon(Some("GraphViewClosed".into()))
.tooltip("Hide Node Graph")
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle))
.tooltip_label("Hide Node Graph")
.shortcut_keys(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle))
.on_update(move |_| DocumentMessage::GraphViewOverlayToggle.into())
.widget_holder(),
]);
@@ -2329,10 +2334,10 @@ impl NodeGraphMessageHandler {
properties.push(LayoutGroup::Row {
widgets: vec![
Separator::new(SeparatorType::Related).widget_holder(),
IconLabel::new("Node").tooltip("Name of the selected node").widget_holder(),
IconLabel::new("Node").tooltip_description("Name of the selected node.").widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
TextInput::new(context.network_interface.display_name(&node_id, context.selection_network_path))
.tooltip("Name of the selected node")
.tooltip_description("Name of the selected node.")
.on_update(move |text_input| {
NodeGraphMessage::SetDisplayName {
node_id,
@@ -2357,10 +2362,10 @@ impl NodeGraphMessageHandler {
let mut properties = vec![LayoutGroup::Row {
widgets: vec![
Separator::new(SeparatorType::Related).widget_holder(),
IconLabel::new("File").tooltip("Name of the current document").widget_holder(),
IconLabel::new("File").tooltip_description("Name of the current document.").widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
TextInput::new(context.document_name)
.tooltip("Name of the current document")
.tooltip_description("Name of the current document.")
.on_update(|text_input| DocumentMessage::RenameDocument { new_name: text_input.value.clone() }.into())
.widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
@@ -2404,10 +2409,10 @@ impl NodeGraphMessageHandler {
let mut layer_properties = vec![LayoutGroup::Row {
widgets: vec![
Separator::new(SeparatorType::Related).widget_holder(),
IconLabel::new("Layer").tooltip("Name of the selected layer").widget_holder(),
IconLabel::new("Layer").tooltip_description("Name of the selected layer.").widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
TextInput::new(context.network_interface.display_name(&layer, context.selection_network_path))
.tooltip("Name of the selected layer")
.tooltip_description("Name of the selected layer.")
.on_update(move |text_input| {
NodeGraphMessage::SetDisplayName {
node_id: layer,
@@ -2420,7 +2425,7 @@ impl NodeGraphMessageHandler {
Separator::new(SeparatorType::Related).widget_holder(),
PopoverButton::new()
.icon(Some("Node".to_string()))
.tooltip("Add an operation to the end of this layer's chain of nodes")
.tooltip_description("Add an operation to the end of this layer's chain of nodes.")
.popover_layout({
let compatible_type = context
.network_interface
@@ -2680,7 +2685,6 @@ impl NodeGraphMessageHandler {
let data = LayerPanelEntry {
id: node_id,
alias: network_interface.display_name(&node_id, &[]),
tooltip: if cfg!(debug_assertions) { format!("Layer ID: {node_id}") } else { "".into() },
in_selected_network: selection_network_path.is_empty(),
children_allowed,
children_present: layer.has_children(network_interface.document_metadata()),
@@ -50,10 +50,10 @@ pub fn expose_widget(node_id: NodeId, index: usize, data_type: FrontendGraphData
ParameterExposeButton::new()
.exposed(exposed)
.data_type(data_type)
.tooltip(if exposed {
"Stop exposing this parameter as a node input in the graph"
.tooltip_description(if exposed {
"Stop exposing this parameter as a node input in the graph."
} else {
"Expose this parameter as a node input in the graph"
"Expose this parameter as a node input in the graph."
})
.on_update(move |_parameter| Message::Batched {
messages: Box::new([NodeGraphMessage::ExposeInput {
@@ -97,12 +97,11 @@ pub fn start_widgets(parameter_widgets_info: ParameterWidgetsInfo) -> Vec<Widget
log::warn!("A widget failed to be built because its node's input index is invalid.");
return vec![];
};
let description = if description != "TODO" { description } else { String::new() };
let mut widgets = Vec::with_capacity(6);
if exposable {
widgets.push(expose_widget(node_id, index, input_type, input.is_exposed()));
}
widgets.push(TextLabel::new(name).tooltip(description).widget_holder());
widgets.push(TextLabel::new(name).tooltip_description(description).widget_holder());
if blank_assist {
add_blank_assist(&mut widgets);
}
@@ -232,16 +231,16 @@ pub(crate) fn property_from_type(
widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(),
TextLabel::new("-")
.tooltip(format!(
"This data can only be supplied through the node graph because no widget exists for its type:\n\
{}",
// TODO: Avoid needing to remove spaces here by fixing how `alias` is generated
.tooltip_label(format!(
"Data Type: {}",
concrete_type
.alias
.as_deref()
// TODO: Avoid needing to remove spaces here by fixing how `alias` is generated
.map(|s| s.to_string().replace(" ", ""))
.unwrap_or_else(|| graphene_std::format_type(concrete_type.name.as_ref()))
.unwrap_or_else(|| graphene_std::format_type(concrete_type.name.as_ref())),
))
.tooltip_description("This data can only be supplied through the node graph because no widget exists for its type.")
.widget_holder(),
]);
return Err(vec![widgets.into()]);
@@ -961,7 +960,7 @@ pub fn blend_mode_widget(parameter_widgets_info: ParameterWidgetsInfo) -> Layout
.widget_holder(),
]);
}
LayoutGroup::Row { widgets }.with_tooltip("Formula used for blending")
LayoutGroup::Row { widgets }.with_tooltip_description("Formula used for blending.")
}
pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button: ColorInput) -> LayoutGroup {
@@ -1400,12 +1399,12 @@ pub(crate) fn spiral_properties(node_id: NodeId, context: &mut NodePropertiesCon
widgets
}
pub(crate) const SAMPLE_POLYLINE_TOOLTIP_SPACING: &str = "Use a point sampling density controlled by a distance between, or specific number of, points.";
pub(crate) const SAMPLE_POLYLINE_TOOLTIP_SEPARATION: &str = "Distance between each instance (exact if 'Adaptive Spacing' is disabled, approximate if enabled).";
pub(crate) const SAMPLE_POLYLINE_TOOLTIP_QUANTITY: &str = "Number of points to place along the path.";
pub(crate) const SAMPLE_POLYLINE_TOOLTIP_START_OFFSET: &str = "Exclude some distance from the start of the path before the first instance.";
pub(crate) const SAMPLE_POLYLINE_TOOLTIP_STOP_OFFSET: &str = "Exclude some distance from the end of the path after the last instance.";
pub(crate) const SAMPLE_POLYLINE_TOOLTIP_ADAPTIVE_SPACING: &str = "Round 'Separation' to a nearby value that divides into the path length evenly.";
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_SPACING: &str = "Use a point sampling density controlled by a distance between, or specific number of, points.";
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_SEPARATION: &str = "Distance between each instance (exact if 'Adaptive Spacing' is disabled, approximate if enabled).";
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_QUANTITY: &str = "Number of points to place along the path.";
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_START_OFFSET: &str = "Exclude some distance from the start of the path before the first instance.";
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_STOP_OFFSET: &str = "Exclude some distance from the end of the path after the last instance.";
pub(crate) const SAMPLE_POLYLINE_DESCRIPTION_ADAPTIVE_SPACING: &str = "Round 'Separation' to a nearby value that divides into the path length evenly.";
pub(crate) fn sample_polyline_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::vector::sample_polyline::*;
@@ -1434,15 +1433,15 @@ pub(crate) fn sample_polyline_properties(node_id: NodeId, context: &mut NodeProp
);
vec![
spacing.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_SPACING),
spacing.with_tooltip_description(SAMPLE_POLYLINE_DESCRIPTION_SPACING),
match current_spacing {
Some(TaggedValue::PointSpacingType(PointSpacingType::Separation)) => LayoutGroup::Row { widgets: separation }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_SEPARATION),
Some(TaggedValue::PointSpacingType(PointSpacingType::Quantity)) => LayoutGroup::Row { widgets: quantity }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_QUANTITY),
Some(TaggedValue::PointSpacingType(PointSpacingType::Separation)) => LayoutGroup::Row { widgets: separation }.with_tooltip_description(SAMPLE_POLYLINE_DESCRIPTION_SEPARATION),
Some(TaggedValue::PointSpacingType(PointSpacingType::Quantity)) => LayoutGroup::Row { widgets: quantity }.with_tooltip_description(SAMPLE_POLYLINE_DESCRIPTION_QUANTITY),
_ => LayoutGroup::Row { widgets: vec![] },
},
LayoutGroup::Row { widgets: start_offset }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_START_OFFSET),
LayoutGroup::Row { widgets: stop_offset }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_STOP_OFFSET),
LayoutGroup::Row { widgets: adaptive_spacing }.with_tooltip(SAMPLE_POLYLINE_TOOLTIP_ADAPTIVE_SPACING),
LayoutGroup::Row { widgets: start_offset }.with_tooltip_description(SAMPLE_POLYLINE_DESCRIPTION_START_OFFSET),
LayoutGroup::Row { widgets: stop_offset }.with_tooltip_description(SAMPLE_POLYLINE_DESCRIPTION_STOP_OFFSET),
LayoutGroup::Row { widgets: adaptive_spacing }.with_tooltip_description(SAMPLE_POLYLINE_DESCRIPTION_ADAPTIVE_SPACING),
]
}
@@ -1776,7 +1775,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
Fill::Solid(_) | Fill::None => add_blank_assist(&mut row),
Fill::Gradient(gradient) => {
let reverse_button = IconButton::new("Reverse", 24)
.tooltip("Reverse the gradient color stops")
.tooltip_description("Reverse the gradient color stops.")
.on_update(update_value(
{
let gradient = gradient.clone();
@@ -1826,7 +1825,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
(gradient.start.x + gradient.start.y) < (gradient.end.x + gradient.end.y)
};
let reverse_radial_gradient_button = IconButton::new(if orientation { "ReverseRadialGradientToRight" } else { "ReverseRadialGradientToLeft" }, 24)
.tooltip("Reverse which end the gradient radiates from")
.tooltip_description("Reverse which end the gradient radiates from.")
.on_update(update_value(
{
let gradient = gradient.clone();
@@ -2027,9 +2026,9 @@ pub fn math_properties(node_id: NodeId, context: &mut NodePropertiesContext) ->
let operand_a_hint = vec![TextLabel::new("(Operand A is the primary input)").widget_holder()];
vec![
LayoutGroup::Row { widgets: expression }.with_tooltip(r#"A math expression that may incorporate "A" and/or "B", such as "sqrt(A + B) - B^2""#),
LayoutGroup::Row { widgets: operand_b }.with_tooltip(r#"The value of "B" when calculating the expression"#),
LayoutGroup::Row { widgets: operand_a_hint }.with_tooltip(r#""A" is fed by the value from the previous node in the primary data flow, or it is 0 if disconnected"#),
LayoutGroup::Row { widgets: expression }.with_tooltip_description(r#"A math expression that may incorporate "A" and/or "B", such as "sqrt(A + B) - B^2"."#),
LayoutGroup::Row { widgets: operand_b }.with_tooltip_description(r#"The value of "B" when calculating the expression."#),
LayoutGroup::Row { widgets: operand_a_hint }.with_tooltip_description(r#""A" is fed by the value from the previous node in the primary data flow, or it is 0 if disconnected."#),
]
}
@@ -2149,13 +2148,12 @@ pub mod choice {
.map(|(item, var_meta)| {
let updater = updater_factory();
let committer = committer_factory();
let entry = RadioEntryData::new(var_meta.name).on_update(move |_| updater(item)).on_commit(committer);
match (var_meta.icon, var_meta.docstring) {
(None, None) => entry.label(var_meta.label),
(None, Some(doc)) => entry.label(var_meta.label).tooltip(doc),
(Some(icon), None) => entry.icon(icon).tooltip(var_meta.label),
(Some(icon), Some(doc)) => entry.icon(icon).tooltip(format!("{}\n\n{}", var_meta.label, doc)),
}
let entry = RadioEntryData::new(var_meta.name)
.on_update(move |_| updater(item))
.on_commit(committer)
.tooltip_label(var_meta.label)
.tooltip_description(var_meta.description.unwrap_or_default());
if let Some(icon) = var_meta.icon { entry.icon(icon) } else { entry.label(var_meta.label) }
})
.collect();
RadioInput::new(items).selected_index(Some(current.as_u32())).widget_holder()
@@ -2229,7 +2227,7 @@ pub mod choice {
let mut row = LayoutGroup::Row { widgets };
if let Some(desc) = self.widget_factory.description() {
row = row.with_tooltip(desc);
row = row.with_tooltip_label(desc);
}
row
}
@@ -54,7 +54,7 @@ pub struct FrontendGraphInput {
#[serde(rename = "validTypes")]
pub valid_types: Vec<String>,
#[serde(rename = "connectedTo")]
/// Either "nothing", "import index {index}", or "{node name} output {output_index}".
/// Either "nothing", "import #{index}", or "{node name} #{output_index}".
pub connected_to: String,
}
@@ -276,14 +276,14 @@ pub fn overlay_options(grid: &GridSnapping) -> Vec<LayoutGroup> {
color_widgets.extend([
CheckboxInput::new(grid.dot_display)
.icon("GridDotted")
.tooltip("Display as dotted grid")
.tooltip_label("Display as Dotted Grid")
.on_update(update_display(grid, |grid| Some(&mut grid.dot_display)))
.widget_holder(),
Separator::new(SeparatorType::Related).widget_holder(),
]);
color_widgets.push(
ColorInput::new(FillChoice::Solid(grid.grid_color.to_gamma_srgb()))
.tooltip("Grid display color")
.tooltip_label("Grid Display Color")
.allow_none(false)
.on_update(update_color(grid, |grid| Some(&mut grid.grid_color)))
.widget_holder(),
@@ -386,55 +386,55 @@ pub const SNAP_FUNCTIONS_FOR_BOUNDING_BOXES: [(&str, GetSnapState, &str); 5] = [
(
"Align with Edges",
(|snapping_state| &mut snapping_state.bounding_box.align_with_edges) as GetSnapState,
"Snaps to horizontal/vertical alignment with the edges of any layer's bounding box",
"Snaps to horizontal/vertical alignment with the edges of any layer's bounding box.",
),
(
"Corner Points",
(|snapping_state| &mut snapping_state.bounding_box.corner_point) as GetSnapState,
"Snaps to the four corners of any layer's bounding box",
"Snaps to the four corners of any layer's bounding box.",
),
(
"Center Points",
(|snapping_state| &mut snapping_state.bounding_box.center_point) as GetSnapState,
"Snaps to the center point of any layer's bounding box",
"Snaps to the center point of any layer's bounding box.",
),
(
"Edge Midpoints",
(|snapping_state| &mut snapping_state.bounding_box.edge_midpoint) as GetSnapState,
"Snaps to any of the four points at the middle of the edges of any layer's bounding box",
"Snaps to any of the four points at the middle of the edges of any layer's bounding box.",
),
(
"Distribute Evenly",
(|snapping_state| &mut snapping_state.bounding_box.distribute_evenly) as GetSnapState,
"Snaps to a consistent distance offset established by the bounding boxes of nearby layers",
"Snaps to a consistent distance offset established by the bounding boxes of nearby layers.",
),
];
pub const SNAP_FUNCTIONS_FOR_PATHS: [(&str, GetSnapState, &str); 7] = [
(
"Align with Anchor Points",
(|snapping_state: &mut SnappingState| &mut snapping_state.path.align_with_anchor_point) as GetSnapState,
"Snaps to horizontal/vertical alignment with the anchor points of any vector path",
"Snaps to horizontal/vertical alignment with the anchor points of any vector path.",
),
(
"Anchor Points",
(|snapping_state: &mut SnappingState| &mut snapping_state.path.anchor_point) as GetSnapState,
"Snaps to the anchor point of any vector path",
"Snaps to the anchor point of any vector path.",
),
(
// TODO: Extend to the midpoints of curved segments and rename to "Segment Midpoint"
"Line Midpoints",
(|snapping_state: &mut SnappingState| &mut snapping_state.path.line_midpoint) as GetSnapState,
"Snaps to the point at the middle of any straight line segment of a vector path",
"Snaps to the point at the middle of any straight line segment of a vector path.",
),
(
"Path Intersection Points",
(|snapping_state: &mut SnappingState| &mut snapping_state.path.path_intersection_point) as GetSnapState,
"Snaps to any points where vector paths intersect",
"Snaps to any points where vector paths intersect.",
),
(
"Along Paths",
(|snapping_state: &mut SnappingState| &mut snapping_state.path.along_path) as GetSnapState,
"Snaps along the length of any vector path",
"Snaps along the length of any vector path.",
),
(
// TODO: This works correctly for line segments, but not curved segments.
@@ -442,7 +442,7 @@ pub const SNAP_FUNCTIONS_FOR_PATHS: [(&str, GetSnapState, &str); 7] = [
"Normal to Paths",
(|snapping_state: &mut SnappingState| &mut snapping_state.path.normal_to_path) as GetSnapState,
// TODO: Fix the bug/limitation that requires 'Intersections of Paths' to be enabled
"Snaps a line to a point perpendicular to a vector path\n(due to a bug, 'Intersections of Paths' must be enabled)",
"Snaps a line to a point perpendicular to a vector path.\n(Due to a bug, 'Intersections of Paths' must be enabled.)",
),
(
// TODO: This works correctly for line segments, but not curved segments.
@@ -450,7 +450,7 @@ pub const SNAP_FUNCTIONS_FOR_PATHS: [(&str, GetSnapState, &str); 7] = [
"Tangent to Paths",
(|snapping_state: &mut SnappingState| &mut snapping_state.path.tangent_to_path) as GetSnapState,
// TODO: Fix the bug/limitation that requires 'Intersections of Paths' to be enabled
"Snaps a line to a point tangent to a vector path\n(due to a bug, 'Intersections of Paths' must be enabled)",
"Snaps a line to a point tangent to a vector path.\n(Due to a bug, 'Intersections of Paths' must be enabled.)",
),
];
@@ -631,15 +631,12 @@ impl NodeNetworkInterface {
.upstream_output_connector(input_connector, network_path)
.map(|output_connector| match output_connector {
OutputConnector::Node { node_id, output_index } => {
let mut name = self.display_name(&node_id, network_path);
if cfg!(debug_assertions) {
name.push_str(&format!(" (id: {node_id})"));
}
format!("{name} output {output_index}")
let name = self.display_name(&node_id, network_path);
format!("Connected to output #{output_index} of \"{name}\", ID: {node_id}.")
}
OutputConnector::Import(import_index) => format!("Import index {import_index}"),
OutputConnector::Import(import_index) => format!("Connected to import #{import_index}."),
})
.unwrap_or("nothing".to_string());
.unwrap_or("Connected to nothing.".to_string());
let (name, description) = match input_connector {
InputConnector::Node { node_id, input_index } => self.displayed_input_name_and_description(node_id, *input_index, network_path),
@@ -659,7 +656,7 @@ impl NodeNetworkInterface {
} else if let Some(export_type_name) = input_type.compiled_nested_type().map(|nested| nested.to_string()) {
export_type_name
} else {
format!("Export index {}", export_index)
format!("Export #{}", export_index)
};
(export_name, String::new())
@@ -709,7 +706,7 @@ impl NodeNetworkInterface {
} else if let Some(import_type_name) = output_type.compiled_nested_type().map(|nested| nested.to_string()) {
import_type_name
} else {
format!("Import index {}", import_index)
format!("Import #{}", import_index)
};
(import_name, description)
@@ -724,19 +721,16 @@ impl NodeNetworkInterface {
.unwrap_or_default()
.iter()
.map(|input| match input {
InputConnector::Node { node_id, input_index } => {
let mut name = self.display_name(node_id, network_path);
if cfg!(debug_assertions) {
name.push_str(&format!(" (id: {node_id})"));
}
format!("{name} input {input_index}")
&InputConnector::Node { node_id, input_index } => {
let name = self.display_name(&node_id, network_path);
format!("Connected to input #{input_index} of \"{name}\", ID: {node_id}.")
}
InputConnector::Export(export_index) => format!("Export index {export_index}"),
InputConnector::Export(export_index) => format!("Connected to export #{export_index}."),
})
.collect::<Vec<_>>();
if connected_to.is_empty() {
connected_to.push("nothing".to_string());
connected_to.push("Connected to nothing.".to_string());
}
Some(FrontendGraphOutput {
@@ -1014,7 +1008,6 @@ impl NodeNetworkInterface {
pub fn description(&self, node_id: &NodeId, network_path: &[NodeId]) -> String {
self.get_node_definition(node_id, network_path)
.map(|node_definition| node_definition.description.to_string())
.filter(|description| description != "TODO")
.unwrap_or_default()
}
@@ -6170,7 +6163,7 @@ pub struct InputPersistentMetadata {
pub widget_override: Option<String>,
/// An empty input name means to use the type as the name.
pub input_name: String,
/// Displayed as the tooltip.
/// Displayed as the tooltip description.
pub input_description: String,
}
@@ -6233,8 +6226,8 @@ impl InputPersistentMetadata {
self
}
pub fn with_description(mut self, tooltip: &str) -> Self {
self.input_description = tooltip.to_string();
pub fn with_description(mut self, description: &str) -> Self {
self.input_description = description.to_string();
self
}
}
@@ -6314,9 +6307,9 @@ impl From<(&str, &str)> for InputMetadata {
}
impl InputMetadata {
pub fn with_name_description_override(input_name: &str, tooltip: &str, widget_override: WidgetOverride) -> Self {
pub fn with_name_description_override(input_name: &str, description: &str, widget_override: WidgetOverride) -> Self {
InputMetadata {
persistent_metadata: InputPersistentMetadata::default().with_name(input_name).with_description(tooltip).with_override(widget_override),
persistent_metadata: InputPersistentMetadata::default().with_name(input_name).with_description(description).with_override(widget_override),
..Default::default()
}
}
@@ -88,7 +88,7 @@ impl TypeSource {
self.compiled_nested_type().map(|ty| format!("type:{ty}"))
}
/// The type to display in the tooltip.
/// The type to display in the tooltip label.
pub fn resolved_type_tooltip_string(&self) -> String {
match self {
TypeSource::Compiled(compiled_type) => format!("Data Type: {:?}", compiled_type.nested_type().to_string()),
@@ -35,7 +35,6 @@ impl serde::Serialize for JsRawBuffer {
pub struct LayerPanelEntry {
pub id: NodeId,
pub alias: String,
pub tooltip: String,
#[serde(rename = "inSelectedNetwork")]
pub in_selected_network: bool,
#[serde(rename = "childrenAllowed")]
@@ -42,8 +42,8 @@ impl std::fmt::Display for GraphWireStyle {
impl GraphWireStyle {
pub fn tooltip_description(&self) -> &'static str {
match self {
GraphWireStyle::GridAligned => "Wires follow the grid, running in straight lines between nodes",
GraphWireStyle::Direct => "Wires bend to run at an angle directly between nodes",
GraphWireStyle::GridAligned => "Wires follow the grid, running in straight lines between nodes.",
GraphWireStyle::Direct => "Wires bend to run at an angle directly between nodes.",
}
}