Many subtle improvements to the UI design system (#1537)
This commit is contained in:
parent
34f952bad1
commit
96b5d7b520
|
|
@ -29,7 +29,7 @@ impl DialogLayoutHolder for AboutGraphiteDialog {
|
||||||
.map(|(icon, label, url)| {
|
.map(|(icon, label, url)| {
|
||||||
TextButton::new(label)
|
TextButton::new(label)
|
||||||
.icon(Some(icon.into()))
|
.icon(Some(icon.into()))
|
||||||
.no_background(true)
|
.flush(true)
|
||||||
.on_update(|_| FrontendMessage::TriggerVisitLink { url: url.into() }.into())
|
.on_update(|_| FrontendMessage::TriggerVisitLink { url: url.into() }.into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
})
|
})
|
||||||
|
|
@ -40,7 +40,7 @@ impl DialogLayoutHolder for AboutGraphiteDialog {
|
||||||
widgets.push(
|
widgets.push(
|
||||||
TextButton::new("Licenses")
|
TextButton::new("Licenses")
|
||||||
.icon(Some("License".into()))
|
.icon(Some("License".into()))
|
||||||
.no_background(true)
|
.flush(true)
|
||||||
.on_update(move |_| {
|
.on_update(move |_| {
|
||||||
DialogMessage::RequestLicensesDialogWithLocalizedCommitDate {
|
DialogMessage::RequestLicensesDialogWithLocalizedCommitDate {
|
||||||
localized_commit_year: localized_commit_year.clone(),
|
localized_commit_year: localized_commit_year.clone(),
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ impl LayoutHolder for ComingSoonDialog {
|
||||||
let row2 = vec![TextLabel::new("But you can help build it! Visit its issue:").widget_holder()];
|
let row2 = vec![TextLabel::new("But you can help build it! Visit its issue:").widget_holder()];
|
||||||
let row3 = vec![TextButton::new(format!("GitHub Issue #{issue}"))
|
let row3 = vec![TextButton::new(format!("GitHub Issue #{issue}"))
|
||||||
.icon(Some("Website".into()))
|
.icon(Some("Website".into()))
|
||||||
.no_background(true)
|
.flush(true)
|
||||||
.on_update(move |_| {
|
.on_update(move |_| {
|
||||||
FrontendMessage::TriggerVisitLink {
|
FrontendMessage::TriggerVisitLink {
|
||||||
url: format!("https://github.com/GraphiteEditor/Graphite/issues/{issue}"),
|
url: format!("https://github.com/GraphiteEditor/Graphite/issues/{issue}"),
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ impl DialogLayoutHolder for LicensesDialog {
|
||||||
.map(|(icon, label, url)| {
|
.map(|(icon, label, url)| {
|
||||||
TextButton::new(label)
|
TextButton::new(label)
|
||||||
.icon(Some(icon.into()))
|
.icon(Some(icon.into()))
|
||||||
.no_background(true)
|
.flush(true)
|
||||||
.on_update(|_| FrontendMessage::TriggerVisitLink { url: url.into() }.into())
|
.on_update(|_| FrontendMessage::TriggerVisitLink { url: url.into() }.into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -173,11 +173,6 @@ pub enum FrontendMessage {
|
||||||
#[serde(rename = "setColorChoice")]
|
#[serde(rename = "setColorChoice")]
|
||||||
set_color_choice: Option<String>,
|
set_color_choice: Option<String>,
|
||||||
},
|
},
|
||||||
UpdateGraphViewOverlayButtonLayout {
|
|
||||||
#[serde(rename = "layoutTarget")]
|
|
||||||
layout_target: LayoutTarget,
|
|
||||||
diff: Vec<WidgetDiff>,
|
|
||||||
},
|
|
||||||
UpdateImageData {
|
UpdateImageData {
|
||||||
#[serde(rename = "documentId")]
|
#[serde(rename = "documentId")]
|
||||||
document_id: DocumentId,
|
document_id: DocumentId,
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,8 @@ pub fn default_mapping() -> Mapping {
|
||||||
entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=ToolMessage::SelectRandomPrimaryColor),
|
entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=ToolMessage::SelectRandomPrimaryColor),
|
||||||
//
|
//
|
||||||
// DocumentMessage
|
// DocumentMessage
|
||||||
|
entry!(KeyDown(Space); modifiers=[Control], action_dispatch=DocumentMessage::GraphViewOverlayToggle),
|
||||||
|
entry!(KeyUp(Escape); action_dispatch=DocumentMessage::GraphViewOverlay { open: false }),
|
||||||
entry!(KeyDown(Delete); action_dispatch=DocumentMessage::DeleteSelectedLayers),
|
entry!(KeyDown(Delete); action_dispatch=DocumentMessage::DeleteSelectedLayers),
|
||||||
entry!(KeyDown(Backspace); action_dispatch=DocumentMessage::DeleteSelectedLayers),
|
entry!(KeyDown(Backspace); action_dispatch=DocumentMessage::DeleteSelectedLayers),
|
||||||
entry!(KeyDown(KeyP); modifiers=[Alt], action_dispatch=DocumentMessage::DebugPrintDocument),
|
entry!(KeyDown(KeyP); modifiers=[Alt], action_dispatch=DocumentMessage::DebugPrintDocument),
|
||||||
|
|
@ -337,8 +339,6 @@ pub fn default_mapping() -> Mapping {
|
||||||
entry!(KeyDown(Period); action_dispatch=NavigationMessage::FitViewportToSelection),
|
entry!(KeyDown(Period); action_dispatch=NavigationMessage::FitViewportToSelection),
|
||||||
//
|
//
|
||||||
// PortfolioMessage
|
// PortfolioMessage
|
||||||
entry!(KeyDown(Space); modifiers=[Control], action_dispatch=PortfolioMessage::GraphViewOverlayToggle),
|
|
||||||
entry!(KeyUp(Escape); action_dispatch=PortfolioMessage::GraphViewOverlay { open: false }),
|
|
||||||
entry!(KeyDown(Tab); modifiers=[Control], action_dispatch=PortfolioMessage::NextDocument),
|
entry!(KeyDown(Tab); modifiers=[Control], action_dispatch=PortfolioMessage::NextDocument),
|
||||||
entry!(KeyDown(Tab); modifiers=[Control, Shift], action_dispatch=PortfolioMessage::PrevDocument),
|
entry!(KeyDown(Tab); modifiers=[Control, Shift], action_dispatch=PortfolioMessage::PrevDocument),
|
||||||
entry!(KeyDown(KeyW); modifiers=[Accel], action_dispatch=PortfolioMessage::CloseActiveDocumentWithConfirmation),
|
entry!(KeyDown(KeyW); modifiers=[Accel], action_dispatch=PortfolioMessage::CloseActiveDocumentWithConfirmation),
|
||||||
|
|
|
||||||
|
|
@ -171,12 +171,6 @@ impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage
|
||||||
},
|
},
|
||||||
_ => {} // If it's some other type we could just ignore it and leave the value as is
|
_ => {} // If it's some other type we could just ignore it and leave the value as is
|
||||||
},
|
},
|
||||||
Widget::OptionalInput(optional_input) => {
|
|
||||||
let update_value = value.as_bool().expect("OptionalInput update was not of type: bool");
|
|
||||||
optional_input.checked = update_value;
|
|
||||||
let callback_message = (optional_input.on_update.callback)(optional_input);
|
|
||||||
responses.add(callback_message);
|
|
||||||
}
|
|
||||||
Widget::ParameterExposeButton(parameter_expose_button) => {
|
Widget::ParameterExposeButton(parameter_expose_button) => {
|
||||||
let callback_message = (parameter_expose_button.on_update.callback)(parameter_expose_button);
|
let callback_message = (parameter_expose_button.on_update.callback)(parameter_expose_button);
|
||||||
responses.add(callback_message);
|
responses.add(callback_message);
|
||||||
|
|
@ -212,7 +206,7 @@ impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage
|
||||||
responses.add(callback_message);
|
responses.add(callback_message);
|
||||||
}
|
}
|
||||||
Widget::TextLabel(_) => {}
|
Widget::TextLabel(_) => {}
|
||||||
Widget::WorkingColorsButton(_) => {}
|
Widget::WorkingColorsInput(_) => {}
|
||||||
};
|
};
|
||||||
responses.add(ResendActiveWidget { layout_target, dirty_id: widget_id });
|
responses.add(ResendActiveWidget { layout_target, dirty_id: widget_id });
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +267,6 @@ impl LayoutMessageHandler {
|
||||||
LayoutTarget::DialogColumn2 => FrontendMessage::UpdateDialogColumn2 { layout_target, diff },
|
LayoutTarget::DialogColumn2 => FrontendMessage::UpdateDialogColumn2 { layout_target, diff },
|
||||||
LayoutTarget::DocumentBar => FrontendMessage::UpdateDocumentBarLayout { layout_target, diff },
|
LayoutTarget::DocumentBar => FrontendMessage::UpdateDocumentBarLayout { layout_target, diff },
|
||||||
LayoutTarget::DocumentMode => FrontendMessage::UpdateDocumentModeLayout { layout_target, diff },
|
LayoutTarget::DocumentMode => FrontendMessage::UpdateDocumentModeLayout { layout_target, diff },
|
||||||
LayoutTarget::GraphViewOverlayButton => FrontendMessage::UpdateGraphViewOverlayButtonLayout { layout_target, diff },
|
|
||||||
LayoutTarget::LayersPanelOptions => FrontendMessage::UpdateLayersPanelOptionsLayout { layout_target, diff },
|
LayoutTarget::LayersPanelOptions => FrontendMessage::UpdateLayersPanelOptionsLayout { layout_target, diff },
|
||||||
LayoutTarget::MenuBar => unreachable!("Menu bar is not diffed"),
|
LayoutTarget::MenuBar => unreachable!("Menu bar is not diffed"),
|
||||||
LayoutTarget::NodeGraphBar => FrontendMessage::UpdateNodeGraphBarLayout { layout_target, diff },
|
LayoutTarget::NodeGraphBar => FrontendMessage::UpdateNodeGraphBarLayout { layout_target, diff },
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,6 @@ pub enum LayoutTarget {
|
||||||
DocumentBar,
|
DocumentBar,
|
||||||
/// Contains the dropdown for design / select / guide mode found on the top left of the canvas.
|
/// Contains the dropdown for design / select / guide mode found on the top left of the canvas.
|
||||||
DocumentMode,
|
DocumentMode,
|
||||||
/// The button below the tool shelf and directly above the working colors which lets the user toggle the node graph overlaid on the canvas.
|
|
||||||
GraphViewOverlayButton,
|
|
||||||
/// Options for opacity seen at the top of the Layers panel.
|
/// Options for opacity seen at the top of the Layers panel.
|
||||||
LayersPanelOptions,
|
LayersPanelOptions,
|
||||||
/// The dropdown menu at the very top of the application: File, Edit, etc.
|
/// The dropdown menu at the very top of the application: File, Edit, etc.
|
||||||
|
|
@ -337,7 +335,6 @@ impl LayoutGroup {
|
||||||
Widget::IconLabel(x) => &mut x.tooltip,
|
Widget::IconLabel(x) => &mut x.tooltip,
|
||||||
Widget::ImageLabel(x) => &mut x.tooltip,
|
Widget::ImageLabel(x) => &mut x.tooltip,
|
||||||
Widget::NumberInput(x) => &mut x.tooltip,
|
Widget::NumberInput(x) => &mut x.tooltip,
|
||||||
Widget::OptionalInput(x) => &mut x.tooltip,
|
|
||||||
Widget::ParameterExposeButton(x) => &mut x.tooltip,
|
Widget::ParameterExposeButton(x) => &mut x.tooltip,
|
||||||
Widget::PopoverButton(x) => &mut x.tooltip,
|
Widget::PopoverButton(x) => &mut x.tooltip,
|
||||||
Widget::TextAreaInput(x) => &mut x.tooltip,
|
Widget::TextAreaInput(x) => &mut x.tooltip,
|
||||||
|
|
@ -345,7 +342,7 @@ impl LayoutGroup {
|
||||||
Widget::TextInput(x) => &mut x.tooltip,
|
Widget::TextInput(x) => &mut x.tooltip,
|
||||||
Widget::TextLabel(x) => &mut x.tooltip,
|
Widget::TextLabel(x) => &mut x.tooltip,
|
||||||
Widget::BreadcrumbTrailButtons(x) => &mut x.tooltip,
|
Widget::BreadcrumbTrailButtons(x) => &mut x.tooltip,
|
||||||
Widget::InvisibleStandinInput(_) | Widget::PivotInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::WorkingColorsButton(_) => continue,
|
Widget::InvisibleStandinInput(_) | Widget::PivotInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::WorkingColorsInput(_) => continue,
|
||||||
};
|
};
|
||||||
if val.is_empty() {
|
if val.is_empty() {
|
||||||
*val = tooltip.clone();
|
*val = tooltip.clone();
|
||||||
|
|
@ -491,7 +488,6 @@ pub enum Widget {
|
||||||
ImageLabel(ImageLabel),
|
ImageLabel(ImageLabel),
|
||||||
InvisibleStandinInput(InvisibleStandinInput),
|
InvisibleStandinInput(InvisibleStandinInput),
|
||||||
NumberInput(NumberInput),
|
NumberInput(NumberInput),
|
||||||
OptionalInput(OptionalInput),
|
|
||||||
ParameterExposeButton(ParameterExposeButton),
|
ParameterExposeButton(ParameterExposeButton),
|
||||||
PivotInput(PivotInput),
|
PivotInput(PivotInput),
|
||||||
PopoverButton(PopoverButton),
|
PopoverButton(PopoverButton),
|
||||||
|
|
@ -501,7 +497,7 @@ pub enum Widget {
|
||||||
TextButton(TextButton),
|
TextButton(TextButton),
|
||||||
TextInput(TextInput),
|
TextInput(TextInput),
|
||||||
TextLabel(TextLabel),
|
TextLabel(TextLabel),
|
||||||
WorkingColorsButton(WorkingColorsButton),
|
WorkingColorsInput(WorkingColorsInput),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single change to part of the UI, containing the location of the change and the new value.
|
/// A single change to part of the UI, containing the location of the change and the new value.
|
||||||
|
|
@ -560,7 +556,6 @@ impl DiffUpdate {
|
||||||
Widget::FontInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::FontInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
Widget::IconButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::IconButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
Widget::NumberInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::NumberInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
Widget::OptionalInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
|
||||||
Widget::ParameterExposeButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::ParameterExposeButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
Widget::PopoverButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::PopoverButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
Widget::TextButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
Widget::TextButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)),
|
||||||
|
|
@ -574,7 +569,7 @@ impl DiffUpdate {
|
||||||
| Widget::TextAreaInput(_)
|
| Widget::TextAreaInput(_)
|
||||||
| Widget::TextInput(_)
|
| Widget::TextInput(_)
|
||||||
| Widget::TextLabel(_)
|
| Widget::TextLabel(_)
|
||||||
| Widget::WorkingColorsButton(_) => None,
|
| Widget::WorkingColorsInput(_) => None,
|
||||||
};
|
};
|
||||||
if let Some((tooltip, Some(tooltip_shortcut))) = &mut tooltip_shortcut {
|
if let Some((tooltip, Some(tooltip_shortcut))) = &mut tooltip_shortcut {
|
||||||
apply_shortcut_to_tooltip(tooltip_shortcut, tooltip);
|
apply_shortcut_to_tooltip(tooltip_shortcut, tooltip);
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ pub struct IconButton {
|
||||||
#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)]
|
#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)]
|
||||||
#[derivative(Debug, PartialEq, Default)]
|
#[derivative(Debug, PartialEq, Default)]
|
||||||
pub struct PopoverButton {
|
pub struct PopoverButton {
|
||||||
|
pub style: Option<String>,
|
||||||
|
|
||||||
pub icon: Option<String>,
|
pub icon: Option<String>,
|
||||||
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
|
|
@ -85,8 +87,7 @@ pub struct TextButton {
|
||||||
|
|
||||||
pub icon: Option<String>,
|
pub icon: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "noBackground")]
|
pub flush: bool,
|
||||||
pub no_background: bool,
|
|
||||||
|
|
||||||
pub emphasized: bool,
|
pub emphasized: bool,
|
||||||
|
|
||||||
|
|
@ -109,16 +110,6 @@ pub struct TextButton {
|
||||||
pub on_update: WidgetCallback<TextButton>,
|
pub on_update: WidgetCallback<TextButton>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)]
|
|
||||||
#[derivative(Debug, PartialEq, Default)]
|
|
||||||
pub struct WorkingColorsButton {
|
|
||||||
#[widget_builder(constructor)]
|
|
||||||
pub primary: Color,
|
|
||||||
|
|
||||||
#[widget_builder(constructor)]
|
|
||||||
pub secondary: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)]
|
#[derive(Clone, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)]
|
||||||
#[derivative(Debug, PartialEq, Default)]
|
#[derivative(Debug, PartialEq, Default)]
|
||||||
pub struct ColorButton {
|
pub struct ColorButton {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
|
|
||||||
use graphene_core::raster::curve::Curve;
|
use graphene_core::{raster::curve::Curve, Color};
|
||||||
use graphite_proc_macros::WidgetBuilder;
|
use graphite_proc_macros::WidgetBuilder;
|
||||||
|
|
||||||
use derivative::*;
|
use derivative::*;
|
||||||
|
|
@ -253,28 +253,6 @@ pub enum NumberInputMode {
|
||||||
Range,
|
Range,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)]
|
|
||||||
#[derivative(Debug, PartialEq)]
|
|
||||||
pub struct OptionalInput {
|
|
||||||
#[widget_builder(constructor)]
|
|
||||||
pub checked: bool,
|
|
||||||
|
|
||||||
pub disabled: bool,
|
|
||||||
|
|
||||||
#[widget_builder(constructor)]
|
|
||||||
pub icon: String,
|
|
||||||
|
|
||||||
pub tooltip: String,
|
|
||||||
|
|
||||||
#[serde(skip)]
|
|
||||||
pub tooltip_shortcut: Option<ActionKeys>,
|
|
||||||
|
|
||||||
// Callbacks
|
|
||||||
#[serde(skip)]
|
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
||||||
pub on_update: WidgetCallback<OptionalInput>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Default, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)]
|
#[derive(Clone, Default, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)]
|
||||||
#[derivative(Debug, PartialEq)]
|
#[derivative(Debug, PartialEq)]
|
||||||
pub struct RadioInput {
|
pub struct RadioInput {
|
||||||
|
|
@ -310,6 +288,16 @@ pub struct RadioEntryData {
|
||||||
pub on_update: WidgetCallback<()>,
|
pub on_update: WidgetCallback<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)]
|
||||||
|
#[derivative(Debug, PartialEq, Default)]
|
||||||
|
pub struct WorkingColorsInput {
|
||||||
|
#[widget_builder(constructor)]
|
||||||
|
pub primary: Color,
|
||||||
|
|
||||||
|
#[widget_builder(constructor)]
|
||||||
|
pub secondary: Color,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)]
|
#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)]
|
||||||
#[derivative(Debug, PartialEq, Default)]
|
#[derivative(Debug, PartialEq, Default)]
|
||||||
pub struct TextAreaInput {
|
pub struct TextAreaInput {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ pub enum SeparatorType {
|
||||||
#[default]
|
#[default]
|
||||||
Unrelated,
|
Unrelated,
|
||||||
Section,
|
Section,
|
||||||
List,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Derivative, Debug, PartialEq, Eq, Default, WidgetBuilder, specta::Type)]
|
#[derive(Clone, Serialize, Deserialize, Derivative, Debug, PartialEq, Eq, Default, WidgetBuilder, specta::Type)]
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,10 @@ pub enum DocumentMessage {
|
||||||
FlipSelectedLayers {
|
FlipSelectedLayers {
|
||||||
flip_axis: FlipAxis,
|
flip_axis: FlipAxis,
|
||||||
},
|
},
|
||||||
|
GraphViewOverlay {
|
||||||
|
open: bool,
|
||||||
|
},
|
||||||
|
GraphViewOverlayToggle,
|
||||||
GroupSelectedLayers,
|
GroupSelectedLayers,
|
||||||
ImaginateGenerate,
|
ImaginateGenerate,
|
||||||
ImaginateRandom {
|
ImaginateRandom {
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@ pub struct DocumentMessageHandler {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
undo_in_progress: bool,
|
undo_in_progress: bool,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
graph_view_overlay_open: bool,
|
||||||
|
#[serde(skip)]
|
||||||
pub snapping_state: SnappingState,
|
pub snapping_state: SnappingState,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
layer_range_selection_reference: Option<LayerNodeIdentifier>,
|
layer_range_selection_reference: Option<LayerNodeIdentifier>,
|
||||||
|
|
@ -119,6 +121,7 @@ impl Default for DocumentMessageHandler {
|
||||||
saved_hash: None,
|
saved_hash: None,
|
||||||
auto_saved_hash: None,
|
auto_saved_hash: None,
|
||||||
undo_in_progress: false,
|
undo_in_progress: false,
|
||||||
|
graph_view_overlay_open: false,
|
||||||
snapping_state: SnappingState::default(),
|
snapping_state: SnappingState::default(),
|
||||||
layer_range_selection_reference: None,
|
layer_range_selection_reference: None,
|
||||||
metadata: Default::default(),
|
metadata: Default::default(),
|
||||||
|
|
@ -227,7 +230,6 @@ pub struct DocumentInputs<'a> {
|
||||||
pub ipp: &'a InputPreprocessorMessageHandler,
|
pub ipp: &'a InputPreprocessorMessageHandler,
|
||||||
pub persistent_data: &'a PersistentData,
|
pub persistent_data: &'a PersistentData,
|
||||||
pub executor: &'a mut NodeGraphExecutor,
|
pub executor: &'a mut NodeGraphExecutor,
|
||||||
pub graph_view_overlay_open: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHandler {
|
impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHandler {
|
||||||
|
|
@ -238,7 +240,6 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
||||||
ipp,
|
ipp,
|
||||||
persistent_data,
|
persistent_data,
|
||||||
executor,
|
executor,
|
||||||
graph_view_overlay_open,
|
|
||||||
} = document_inputs;
|
} = document_inputs;
|
||||||
use DocumentMessage::*;
|
use DocumentMessage::*;
|
||||||
|
|
||||||
|
|
@ -282,7 +283,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
||||||
document_name: self.name.as_str(),
|
document_name: self.name.as_str(),
|
||||||
collapsed: &mut self.collapsed,
|
collapsed: &mut self.collapsed,
|
||||||
input: ipp,
|
input: ipp,
|
||||||
graph_view_overlay_open,
|
graph_view_overlay_open: self.graph_view_overlay_open,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -382,7 +383,11 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
||||||
self.update_layers_panel_options_bar_widgets(responses);
|
self.update_layers_panel_options_bar_widgets(responses);
|
||||||
|
|
||||||
let data_buffer: RawBuffer = self.serialize_root();
|
let data_buffer: RawBuffer = self.serialize_root();
|
||||||
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer })
|
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
||||||
|
|
||||||
|
if self.graph_view_overlay_open {
|
||||||
|
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DuplicateSelectedLayers => {
|
DuplicateSelectedLayers => {
|
||||||
// TODO: Reimplement selected layer duplication
|
// TODO: Reimplement selected layer duplication
|
||||||
|
|
@ -412,6 +417,17 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GraphViewOverlay { open } => {
|
||||||
|
self.graph_view_overlay_open = open;
|
||||||
|
|
||||||
|
if open {
|
||||||
|
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
||||||
|
}
|
||||||
|
responses.add(FrontendMessage::TriggerGraphViewOverlay { open });
|
||||||
|
}
|
||||||
|
GraphViewOverlayToggle => {
|
||||||
|
responses.add(DocumentMessage::GraphViewOverlay { open: !self.graph_view_overlay_open });
|
||||||
|
}
|
||||||
GroupSelectedLayers => {
|
GroupSelectedLayers => {
|
||||||
// TODO: Add code that changes the insert index of the new folder based on the selected layer
|
// TODO: Add code that changes the insert index of the new folder based on the selected layer
|
||||||
let parent = self.metadata().deepest_common_ancestor(self.metadata().selected_layers(), true).unwrap_or(LayerNodeIdentifier::ROOT);
|
let parent = self.metadata().deepest_common_ancestor(self.metadata().selected_layers(), true).unwrap_or(LayerNodeIdentifier::ROOT);
|
||||||
|
|
@ -1089,9 +1105,10 @@ impl DocumentMessageHandler {
|
||||||
pub fn update_document_widgets(&self, responses: &mut VecDeque<Message>) {
|
pub fn update_document_widgets(&self, responses: &mut VecDeque<Message>) {
|
||||||
let snapping_state = self.snapping_state.clone();
|
let snapping_state = self.snapping_state.clone();
|
||||||
let mut widgets = vec![
|
let mut widgets = vec![
|
||||||
OptionalInput::new(snapping_state.snapping_enabled, "Snapping")
|
CheckboxInput::new(snapping_state.snapping_enabled)
|
||||||
|
.icon("Snapping")
|
||||||
.tooltip("Snapping")
|
.tooltip("Snapping")
|
||||||
.on_update(move |optional_input: &OptionalInput| {
|
.on_update(move |optional_input: &CheckboxInput| {
|
||||||
let snapping_enabled = optional_input.checked;
|
let snapping_enabled = optional_input.checked;
|
||||||
DocumentMessage::SetSnapping {
|
DocumentMessage::SetSnapping {
|
||||||
snapping_enabled: Some(snapping_enabled),
|
snapping_enabled: Some(snapping_enabled),
|
||||||
|
|
@ -1105,6 +1122,8 @@ impl DocumentMessageHandler {
|
||||||
.options_widget(vec![
|
.options_widget(vec![
|
||||||
LayoutGroup::Row {
|
LayoutGroup::Row {
|
||||||
widgets: vec![
|
widgets: vec![
|
||||||
|
TextLabel::new(SnappingOptions::BoundingBoxes.to_string()).table_align(true).min_width(96).widget_holder(),
|
||||||
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
CheckboxInput::new(snapping_state.bounding_box_snapping)
|
CheckboxInput::new(snapping_state.bounding_box_snapping)
|
||||||
.tooltip(SnappingOptions::BoundingBoxes.to_string())
|
.tooltip(SnappingOptions::BoundingBoxes.to_string())
|
||||||
.on_update(move |input: &CheckboxInput| {
|
.on_update(move |input: &CheckboxInput| {
|
||||||
|
|
@ -1116,13 +1135,13 @@ impl DocumentMessageHandler {
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
TextLabel::new(SnappingOptions::BoundingBoxes.to_string()).table_align(false).min_width(60).widget_holder(),
|
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
LayoutGroup::Row {
|
LayoutGroup::Row {
|
||||||
widgets: vec![
|
widgets: vec![
|
||||||
|
TextLabel::new(SnappingOptions::Points.to_string()).table_align(true).min_width(96).widget_holder(),
|
||||||
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
CheckboxInput::new(self.snapping_state.node_snapping)
|
CheckboxInput::new(self.snapping_state.node_snapping)
|
||||||
.tooltip(SnappingOptions::Points.to_string())
|
.tooltip(SnappingOptions::Points.to_string())
|
||||||
.on_update(|input: &CheckboxInput| {
|
.on_update(|input: &CheckboxInput| {
|
||||||
|
|
@ -1134,22 +1153,22 @@ impl DocumentMessageHandler {
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
TextLabel::new(SnappingOptions::Points.to_string()).table_align(false).min_width(60).widget_holder(),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
OptionalInput::new(true, "Grid")
|
CheckboxInput::new(true)
|
||||||
|
.icon("Grid")
|
||||||
.tooltip("Grid")
|
.tooltip("Grid")
|
||||||
.on_update(|_| DialogMessage::RequestComingSoonDialog { issue: Some(318) }.into())
|
.on_update(|_| DialogMessage::RequestComingSoonDialog { issue: Some(318) }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
PopoverButton::new("Grid", "Coming soon").widget_holder(),
|
PopoverButton::new("Grid", "Coming soon").widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
OptionalInput::new(self.overlays_visible, "Overlays")
|
CheckboxInput::new(self.overlays_visible)
|
||||||
|
.icon("Overlays")
|
||||||
.tooltip("Overlays")
|
.tooltip("Overlays")
|
||||||
.on_update(|optional_input: &OptionalInput| DocumentMessage::SetOverlaysVisibility { visible: optional_input.checked }.into())
|
.on_update(|optional_input: &CheckboxInput| DocumentMessage::SetOverlaysVisibility { visible: optional_input.checked }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
PopoverButton::new("Overlays", "Coming soon").widget_holder(),
|
PopoverButton::new("Overlays", "Coming soon").widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
|
|
@ -1176,7 +1195,7 @@ impl DocumentMessageHandler {
|
||||||
})
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
PopoverButton::new("View Mode", "Coming soon").widget_holder(),
|
PopoverButton::new("View Mode", "Coming soon").widget_holder(),
|
||||||
Separator::new(SeparatorType::Section).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
IconButton::new("ZoomIn", 24)
|
IconButton::new("ZoomIn", 24)
|
||||||
.tooltip("Zoom In")
|
.tooltip("Zoom In")
|
||||||
.tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::IncreaseCanvasZoom))
|
.tooltip_shortcut(action_keys!(NavigationMessageDiscriminant::IncreaseCanvasZoom))
|
||||||
|
|
@ -1192,6 +1211,11 @@ impl DocumentMessageHandler {
|
||||||
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ZoomCanvasTo100Percent))
|
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::ZoomCanvasTo100Percent))
|
||||||
.on_update(|_| NavigationMessage::SetCanvasZoom { zoom_factor: 1. }.into())
|
.on_update(|_| NavigationMessage::SetCanvasZoom { zoom_factor: 1. }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
|
PopoverButton::new(
|
||||||
|
"Canvas Navigation",
|
||||||
|
"Interactive controls in this\nmenu are coming soon.\n\nPan:\n• Middle Click Drag\n\nTilt:\n• Alt + Middle Click Drag\n\nZoom:\n• Shift + Middle Click Drag\n• Ctrl + Scroll Wheel Roll",
|
||||||
|
)
|
||||||
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
NumberInput::new(Some(self.navigation_handler.snapped_scale(self.navigation.zoom) * 100.))
|
NumberInput::new(Some(self.navigation_handler.snapped_scale(self.navigation.zoom) * 100.))
|
||||||
.unit("%")
|
.unit("%")
|
||||||
|
|
@ -1208,6 +1232,13 @@ impl DocumentMessageHandler {
|
||||||
.increment_callback_decrease(|_| NavigationMessage::DecreaseCanvasZoom { center_on_mouse: false }.into())
|
.increment_callback_decrease(|_| NavigationMessage::DecreaseCanvasZoom { center_on_mouse: false }.into())
|
||||||
.increment_callback_increase(|_| NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }.into())
|
.increment_callback_increase(|_| NavigationMessage::IncreaseCanvasZoom { center_on_mouse: false }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
|
TextButton::new("Node Graph")
|
||||||
|
.icon(Some(if self.graph_view_overlay_open { "GraphViewOpen".into() } else { "GraphViewClosed".into() }))
|
||||||
|
.tooltip(if self.graph_view_overlay_open { "Hide Node Graph" } else { "Show Node Graph" })
|
||||||
|
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle))
|
||||||
|
.on_update(move |_| DocumentMessage::GraphViewOverlayToggle.into())
|
||||||
|
.widget_holder(),
|
||||||
];
|
];
|
||||||
let rotation_value = self.navigation_handler.snapped_angle(self.navigation.tilt) / (std::f64::consts::PI / 180.);
|
let rotation_value = self.navigation_handler.snapped_angle(self.navigation.tilt) / (std::f64::consts::PI / 180.);
|
||||||
if rotation_value.abs() > 0.00001 {
|
if rotation_value.abs() > 0.00001 {
|
||||||
|
|
@ -1225,14 +1256,6 @@ impl DocumentMessageHandler {
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
widgets.extend([
|
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
|
||||||
PopoverButton::new(
|
|
||||||
"Canvas Navigation",
|
|
||||||
"Interactive options in this popover\nmenu are coming soon.\n\nZoom:\n• Shift + Middle Click Drag\n• Ctrl + Scroll Wheel Roll\nRotate:\n• Alt + Left Click Drag",
|
|
||||||
)
|
|
||||||
.widget_holder(),
|
|
||||||
]);
|
|
||||||
let document_bar_layout = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]);
|
let document_bar_layout = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]);
|
||||||
|
|
||||||
let document_mode_layout = WidgetLayout::new(vec![LayoutGroup::Row {
|
let document_mode_layout = WidgetLayout::new(vec![LayoutGroup::Row {
|
||||||
|
|
@ -1339,7 +1362,7 @@ impl DocumentMessageHandler {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Section).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
IconButton::new("Folder", 24)
|
IconButton::new("Folder", 24)
|
||||||
.tooltip("New Folder")
|
.tooltip("New Folder")
|
||||||
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder))
|
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder))
|
||||||
|
|
@ -1398,7 +1421,7 @@ impl DocumentMessageHandler {
|
||||||
responses.add(DocumentMessage::MoveSelectedLayersTo { parent, insert_index });
|
responses.add(DocumentMessage::MoveSelectedLayersTo { parent, insert_index });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn actions_with_graph_open(&self, graph_open: bool) -> ActionList {
|
pub fn actions_with_graph_open(&self) -> ActionList {
|
||||||
let mut common = actions!(DocumentMessageDiscriminant;
|
let mut common = actions!(DocumentMessageDiscriminant;
|
||||||
Undo,
|
Undo,
|
||||||
Redo,
|
Redo,
|
||||||
|
|
@ -1411,9 +1434,15 @@ impl DocumentMessageHandler {
|
||||||
ZoomCanvasToFitAll,
|
ZoomCanvasToFitAll,
|
||||||
ZoomCanvasTo100Percent,
|
ZoomCanvasTo100Percent,
|
||||||
ZoomCanvasTo200Percent,
|
ZoomCanvasTo200Percent,
|
||||||
|
GraphViewOverlayToggle,
|
||||||
CreateEmptyFolder,
|
CreateEmptyFolder,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if self.graph_view_overlay_open {
|
||||||
|
let escape = actions!(DocumentMessageDiscriminant; GraphViewOverlay);
|
||||||
|
common.extend(escape);
|
||||||
|
}
|
||||||
|
|
||||||
if self.metadata().selected_layers().next().is_some() {
|
if self.metadata().selected_layers().next().is_some() {
|
||||||
let select = actions!(DocumentMessageDiscriminant;
|
let select = actions!(DocumentMessageDiscriminant;
|
||||||
DeleteSelectedLayers,
|
DeleteSelectedLayers,
|
||||||
|
|
@ -1429,7 +1458,7 @@ impl DocumentMessageHandler {
|
||||||
common.extend(select);
|
common.extend(select);
|
||||||
}
|
}
|
||||||
common.extend(self.navigation_handler.actions());
|
common.extend(self.navigation_handler.actions());
|
||||||
common.extend(self.node_graph_handler.actions_with_node_graph_open(graph_open));
|
common.extend(self.node_graph_handler.actions_with_node_graph_open(self.graph_view_overlay_open));
|
||||||
common
|
common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,14 +130,22 @@ pub struct NodeGraphMessageHandler {
|
||||||
|
|
||||||
impl Default for NodeGraphMessageHandler {
|
impl Default for NodeGraphMessageHandler {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
// TODO: Replace this with an "Add Node" button, also next to an "Add Layer" button
|
let right_side_widgets = vec![
|
||||||
let add_nodes_label = TextLabel::new("Right Click Graph to Add Nodes").italic(true).widget_holder();
|
// TODO: Replace this with an "Add Node" button, also next to an "Add Layer" button
|
||||||
let add_nodes_label_row = LayoutGroup::Row { widgets: vec![add_nodes_label] };
|
TextLabel::new("Right Click in Graph to Add Nodes").italic(true).widget_holder(),
|
||||||
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
|
TextButton::new("Node Graph")
|
||||||
|
.icon(Some("GraphViewOpen".into()))
|
||||||
|
.tooltip("Hide Node Graph")
|
||||||
|
.tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle))
|
||||||
|
.on_update(move |_| DocumentMessage::GraphViewOverlayToggle.into())
|
||||||
|
.widget_holder(),
|
||||||
|
];
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
network: Vec::new(),
|
network: Vec::new(),
|
||||||
has_selection: false,
|
has_selection: false,
|
||||||
widgets: [add_nodes_label_row, LayoutGroup::default()],
|
widgets: [LayoutGroup::Row { widgets: Vec::new() }, LayoutGroup::Row { widgets: right_side_widgets }],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -161,8 +169,6 @@ impl NodeGraphMessageHandler {
|
||||||
|
|
||||||
// If there is at least one other selected node then show the hide or show button
|
// If there is at least one other selected node then show the hide or show button
|
||||||
if selected_nodes.next().is_some() {
|
if selected_nodes.next().is_some() {
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
|
||||||
|
|
||||||
// Check if any of the selected nodes are disabled
|
// Check if any of the selected nodes are disabled
|
||||||
let is_hidden = document_metadata.selected_nodes().any(|id| network.disabled.contains(id));
|
let is_hidden = document_metadata.selected_nodes().any(|id| network.disabled.contains(id));
|
||||||
|
|
||||||
|
|
@ -178,13 +184,13 @@ impl NodeGraphMessageHandler {
|
||||||
.on_update(move |_| NodeGraphMessage::ToggleSelectedHidden.into())
|
.on_update(move |_| NodeGraphMessage::ToggleSelectedHidden.into())
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
widgets.push(hide_button);
|
widgets.push(hide_button);
|
||||||
|
|
||||||
|
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If only one node is selected then show the preview or stop previewing button
|
// If only one node is selected then show the preview or stop previewing button
|
||||||
let mut selected_nodes = document_metadata.selected_nodes();
|
let mut selected_nodes = document_metadata.selected_nodes();
|
||||||
if let (Some(&node_id), None) = (selected_nodes.next(), selected_nodes.next()) {
|
if let (Some(&node_id), None) = (selected_nodes.next(), selected_nodes.next()) {
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
|
||||||
|
|
||||||
// Is this node the current output
|
// Is this node the current output
|
||||||
let is_output = network.outputs_contain(node_id);
|
let is_output = network.outputs_contain(node_id);
|
||||||
|
|
||||||
|
|
@ -199,7 +205,7 @@ impl NodeGraphMessageHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.widgets[1] = LayoutGroup::Row { widgets };
|
self.widgets[0] = LayoutGroup::Row { widgets };
|
||||||
}
|
}
|
||||||
self.send_node_bar_layout(responses);
|
self.send_node_bar_layout(responses);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,22 +52,19 @@ fn expose_widget(node_id: NodeId, index: usize, data_type: FrontendGraphDataType
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this when we have proper entry row formatting that includes room for Assists.
|
||||||
fn add_blank_assist(widgets: &mut Vec<WidgetHolder>) {
|
fn add_blank_assist(widgets: &mut Vec<WidgetHolder>) {
|
||||||
widgets.extend_from_slice(&[
|
widgets.extend_from_slice(&[
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: These three separators add up to 24px,
|
// Custom CSS specific to the Properties panel converts this Section separator into the width of an assist (24px).
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: which is the width of the Assist area.
|
Separator::new(SeparatorType::Section).widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: Remove these when we have proper entry row formatting that includes room for Assists.
|
// This last one is the separator after the 24px assist.
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: This last one is the separator after the 24px assist.
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_widgets(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, data_type: FrontendGraphDataType, blank_assist: bool) -> Vec<WidgetHolder> {
|
fn start_widgets(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, data_type: FrontendGraphDataType, blank_assist: bool) -> Vec<WidgetHolder> {
|
||||||
let input = document_node.inputs.get(index).expect("A widget failed to be built because its node's input index is invalid.");
|
let input = document_node.inputs.get(index).expect("A widget failed to be built because its node's input index is invalid.");
|
||||||
let mut widgets = vec![
|
let mut widgets = vec![expose_widget(node_id, index, data_type, input.is_exposed()), TextLabel::new(name).widget_holder()];
|
||||||
expose_widget(node_id, index, data_type, input.is_exposed()),
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
TextLabel::new(name).widget_holder(),
|
|
||||||
];
|
|
||||||
if blank_assist {
|
if blank_assist {
|
||||||
add_blank_assist(&mut widgets);
|
add_blank_assist(&mut widgets);
|
||||||
}
|
}
|
||||||
|
|
@ -291,18 +288,17 @@ fn font_inputs(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
||||||
.on_update(update_value(from_font_input, node_id, index))
|
.on_update(update_value(from_font_input, node_id, index))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
]);
|
]);
|
||||||
second_widgets = Some(vec![
|
|
||||||
TextLabel::new("").widget_holder(),
|
let mut second_row = vec![TextLabel::new("").widget_holder()];
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
add_blank_assist(&mut second_row);
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
second_row.extend_from_slice(&[
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
FontInput::new(font.font_family.clone(), font.font_style.clone())
|
FontInput::new(font.font_family.clone(), font.font_style.clone())
|
||||||
.is_style_picker(true)
|
.is_style_picker(true)
|
||||||
.on_update(update_value(from_font_input, node_id, index))
|
.on_update(update_value(from_font_input, node_id, index))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
]);
|
]);
|
||||||
|
second_widgets = Some(second_row);
|
||||||
}
|
}
|
||||||
(first_widgets, second_widgets)
|
(first_widgets, second_widgets)
|
||||||
}
|
}
|
||||||
|
|
@ -1559,16 +1555,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
||||||
let transform_not_connected = false;
|
let transform_not_connected = false;
|
||||||
|
|
||||||
let progress = {
|
let progress = {
|
||||||
|
let mut widgets = vec![TextLabel::new("Progress").widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder()];
|
||||||
|
add_blank_assist(&mut widgets);
|
||||||
let status = imaginate_status.to_text();
|
let status = imaginate_status.to_text();
|
||||||
let widgets = vec![
|
widgets.push(TextLabel::new(status.as_ref()).bold(true).widget_holder());
|
||||||
TextLabel::new("Progress").widget_holder(),
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: These three separators add up to 24px,
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: which is the width of the Assist area.
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: Remove these when we have proper entry row formatting that includes room for Assists.
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
TextLabel::new(status.as_ref()).bold(true).widget_holder(),
|
|
||||||
];
|
|
||||||
LayoutGroup::Row { widgets }.with_tooltip(match imaginate_status {
|
LayoutGroup::Row { widgets }.with_tooltip(match imaginate_status {
|
||||||
ImaginateStatus::Failed(_) => status.as_ref(),
|
ImaginateStatus::Failed(_) => status.as_ref(),
|
||||||
_ => "When generating, the percentage represents how many sampling steps have so far been processed out of the target number",
|
_ => "When generating, the percentage represents how many sampling steps have so far been processed out of the target number",
|
||||||
|
|
@ -1577,20 +1567,14 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
||||||
|
|
||||||
let image_controls = {
|
let image_controls = {
|
||||||
let mut widgets = vec![TextLabel::new("Image").widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder()];
|
let mut widgets = vec![TextLabel::new("Image").widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder()];
|
||||||
let assist_separators = [
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: These three separators add up to 24px,
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: which is the width of the Assist area.
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(), // TODO: Remove these when we have proper entry row formatting that includes room for Assists.
|
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
|
||||||
];
|
|
||||||
|
|
||||||
match &imaginate_status {
|
match &imaginate_status {
|
||||||
ImaginateStatus::Beginning | ImaginateStatus::Uploading => {
|
ImaginateStatus::Beginning | ImaginateStatus::Uploading => {
|
||||||
widgets.extend_from_slice(&assist_separators);
|
add_blank_assist(&mut widgets);
|
||||||
widgets.push(TextButton::new("Beginning...").tooltip("Sending image generation request to the server").disabled(true).widget_holder());
|
widgets.push(TextButton::new("Beginning...").tooltip("Sending image generation request to the server").disabled(true).widget_holder());
|
||||||
}
|
}
|
||||||
ImaginateStatus::Generating(_) => {
|
ImaginateStatus::Generating(_) => {
|
||||||
widgets.extend_from_slice(&assist_separators);
|
add_blank_assist(&mut widgets);
|
||||||
widgets.push(
|
widgets.push(
|
||||||
TextButton::new("Terminate")
|
TextButton::new("Terminate")
|
||||||
.tooltip("Cancel the in-progress image generation and keep the latest progress")
|
.tooltip("Cancel the in-progress image generation and keep the latest progress")
|
||||||
|
|
@ -1605,7 +1589,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ImaginateStatus::Terminating => {
|
ImaginateStatus::Terminating => {
|
||||||
widgets.extend_from_slice(&assist_separators);
|
add_blank_assist(&mut widgets);
|
||||||
widgets.push(
|
widgets.push(
|
||||||
TextButton::new("Terminating...")
|
TextButton::new("Terminating...")
|
||||||
.tooltip("Waiting on the final image generated after termination")
|
.tooltip("Waiting on the final image generated after termination")
|
||||||
|
|
@ -1755,7 +1739,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
||||||
resolution_index,
|
resolution_index,
|
||||||
))
|
))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
NumberInput::new(Some(vec2.x))
|
NumberInput::new(Some(vec2.x))
|
||||||
.label("W")
|
.label("W")
|
||||||
.min(64.)
|
.min(64.)
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,10 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
||||||
let options_bar = vec![LayoutGroup::Row {
|
let options_bar = vec![LayoutGroup::Row {
|
||||||
widgets: vec![
|
widgets: vec![
|
||||||
IconLabel::new("File").tooltip("Document").widget_holder(),
|
IconLabel::new("File").tooltip("Document").widget_holder(),
|
||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
TextInput::new(document_name)
|
TextInput::new(document_name)
|
||||||
.on_update(|text_input| DocumentMessage::RenameDocument { new_name: text_input.value.clone() }.into())
|
.on_update(|text_input| DocumentMessage::RenameDocument { new_name: text_input.value.clone() }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
|
||||||
PopoverButton::new("Additional Options", "Coming soon").widget_holder(),
|
|
||||||
],
|
],
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,6 @@ pub enum PortfolioMessage {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
is_default: bool,
|
is_default: bool,
|
||||||
},
|
},
|
||||||
GraphViewOverlay {
|
|
||||||
open: bool,
|
|
||||||
},
|
|
||||||
GraphViewOverlayToggle,
|
|
||||||
ImaginateCheckServerStatus,
|
ImaginateCheckServerStatus,
|
||||||
ImaginatePollServerStatus,
|
ImaginatePollServerStatus,
|
||||||
ImaginatePreferences,
|
ImaginatePreferences,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use crate::application::generate_uuid;
|
||||||
use crate::consts::{DEFAULT_DOCUMENT_NAME, GRAPHITE_DOCUMENT_VERSION};
|
use crate::consts::{DEFAULT_DOCUMENT_NAME, GRAPHITE_DOCUMENT_VERSION};
|
||||||
use crate::messages::dialog::simple_dialogs;
|
use crate::messages::dialog::simple_dialogs;
|
||||||
use crate::messages::frontend::utility_types::FrontendDocumentDetails;
|
use crate::messages::frontend::utility_types::FrontendDocumentDetails;
|
||||||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
|
use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT};
|
||||||
use crate::messages::portfolio::document::DocumentInputs;
|
use crate::messages::portfolio::document::DocumentInputs;
|
||||||
|
|
@ -22,7 +21,6 @@ pub struct PortfolioMessageHandler {
|
||||||
documents: HashMap<DocumentId, DocumentMessageHandler>,
|
documents: HashMap<DocumentId, DocumentMessageHandler>,
|
||||||
document_ids: Vec<DocumentId>,
|
document_ids: Vec<DocumentId>,
|
||||||
active_document_id: Option<DocumentId>,
|
active_document_id: Option<DocumentId>,
|
||||||
graph_view_overlay_open: bool,
|
|
||||||
copy_buffer: [Vec<CopyBufferEntry>; INTERNAL_CLIPBOARD_COUNT as usize],
|
copy_buffer: [Vec<CopyBufferEntry>; INTERNAL_CLIPBOARD_COUNT as usize],
|
||||||
pub persistent_data: PersistentData,
|
pub persistent_data: PersistentData,
|
||||||
pub executor: NodeGraphExecutor,
|
pub executor: NodeGraphExecutor,
|
||||||
|
|
@ -55,7 +53,6 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
ipp,
|
ipp,
|
||||||
persistent_data: &self.persistent_data,
|
persistent_data: &self.persistent_data,
|
||||||
executor: &mut self.executor,
|
executor: &mut self.executor,
|
||||||
graph_view_overlay_open: self.graph_view_overlay_open,
|
|
||||||
};
|
};
|
||||||
document.process_message(message, responses, document_inputs)
|
document.process_message(message, responses, document_inputs)
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +68,6 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
ipp,
|
ipp,
|
||||||
persistent_data: &self.persistent_data,
|
persistent_data: &self.persistent_data,
|
||||||
executor: &mut self.executor,
|
executor: &mut self.executor,
|
||||||
graph_view_overlay_open: self.graph_view_overlay_open,
|
|
||||||
};
|
};
|
||||||
document.process_message(message, responses, document_inputs)
|
document.process_message(message, responses, document_inputs)
|
||||||
}
|
}
|
||||||
|
|
@ -257,29 +253,6 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PortfolioMessage::GraphViewOverlay { open } => {
|
|
||||||
self.graph_view_overlay_open = open;
|
|
||||||
|
|
||||||
let layout = WidgetLayout::new(vec![LayoutGroup::Row {
|
|
||||||
widgets: vec![IconButton::new(if open { "GraphViewOpen" } else { "GraphViewClosed" }, 32)
|
|
||||||
.tooltip(if open { "Hide Node Graph" } else { "Show Node Graph" })
|
|
||||||
.tooltip_shortcut(action_keys!(PortfolioMessageDiscriminant::GraphViewOverlayToggle))
|
|
||||||
.on_update(move |_| PortfolioMessage::GraphViewOverlay { open: !open }.into())
|
|
||||||
.widget_holder()],
|
|
||||||
}]);
|
|
||||||
responses.add(LayoutMessage::SendLayout {
|
|
||||||
layout: Layout::WidgetLayout(layout),
|
|
||||||
layout_target: LayoutTarget::GraphViewOverlayButton,
|
|
||||||
});
|
|
||||||
|
|
||||||
if open {
|
|
||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
|
||||||
}
|
|
||||||
responses.add(FrontendMessage::TriggerGraphViewOverlay { open });
|
|
||||||
}
|
|
||||||
PortfolioMessage::GraphViewOverlayToggle => {
|
|
||||||
responses.add(PortfolioMessage::GraphViewOverlay { open: !self.graph_view_overlay_open });
|
|
||||||
}
|
|
||||||
PortfolioMessage::ImaginateCheckServerStatus => {
|
PortfolioMessage::ImaginateCheckServerStatus => {
|
||||||
let server_status = self.persistent_data.imaginate.server_status().clone();
|
let server_status = self.persistent_data.imaginate.server_status().clone();
|
||||||
self.persistent_data.imaginate.poll_server_check();
|
self.persistent_data.imaginate.poll_server_check();
|
||||||
|
|
@ -473,9 +446,6 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||||
responses.add(NavigationMessage::TranslateCanvas { delta: (0., 0.).into() });
|
responses.add(NavigationMessage::TranslateCanvas { delta: (0., 0.).into() });
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
if self.graph_view_overlay_open {
|
|
||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PortfolioMessage::SetActiveDocument { document_id } => {
|
PortfolioMessage::SetActiveDocument { document_id } => {
|
||||||
self.active_document_id = Some(document_id);
|
self.active_document_id = Some(document_id);
|
||||||
|
|
@ -553,7 +523,6 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
|
|
||||||
fn actions(&self) -> ActionList {
|
fn actions(&self) -> ActionList {
|
||||||
let mut common = actions!(PortfolioMessageDiscriminant;
|
let mut common = actions!(PortfolioMessageDiscriminant;
|
||||||
GraphViewOverlayToggle,
|
|
||||||
CloseActiveDocumentWithConfirmation,
|
CloseActiveDocumentWithConfirmation,
|
||||||
CloseAllDocuments,
|
CloseAllDocuments,
|
||||||
CloseAllDocumentsWithConfirmation,
|
CloseAllDocumentsWithConfirmation,
|
||||||
|
|
@ -565,11 +534,6 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
ToggleRulers,
|
ToggleRulers,
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.graph_view_overlay_open {
|
|
||||||
let escape = actions!(PortfolioMessageDiscriminant; GraphViewOverlay);
|
|
||||||
common.extend(escape);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(document) = self.active_document() {
|
if let Some(document) = self.active_document() {
|
||||||
if document.metadata().selected_layers().next().is_some() {
|
if document.metadata().selected_layers().next().is_some() {
|
||||||
let select = actions!(PortfolioMessageDiscriminant;
|
let select = actions!(PortfolioMessageDiscriminant;
|
||||||
|
|
@ -578,7 +542,8 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
);
|
);
|
||||||
common.extend(select);
|
common.extend(select);
|
||||||
}
|
}
|
||||||
common.extend(document.actions_with_graph_open(self.graph_view_overlay_open));
|
|
||||||
|
common.extend(document.actions_with_graph_open());
|
||||||
}
|
}
|
||||||
|
|
||||||
common
|
common
|
||||||
|
|
@ -652,7 +617,6 @@ impl PortfolioMessageHandler {
|
||||||
responses.add(PortfolioMessage::SelectDocument { document_id });
|
responses.add(PortfolioMessage::SelectDocument { document_id });
|
||||||
responses.add(PortfolioMessage::LoadDocumentResources { document_id });
|
responses.add(PortfolioMessage::LoadDocumentResources { document_id });
|
||||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||||
responses.add(PortfolioMessage::GraphViewOverlay { open: self.graph_view_overlay_open });
|
|
||||||
responses.add(ToolMessage::InitTools);
|
responses.add(ToolMessage::InitTools);
|
||||||
responses.add(NodeGraphMessage::Init);
|
responses.add(NodeGraphMessage::Init);
|
||||||
responses.add(NavigationMessage::TranslateCanvas { delta: (0., 0.).into() });
|
responses.add(NavigationMessage::TranslateCanvas { delta: (0., 0.).into() });
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ impl LayoutHolder for BrushTool {
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
];
|
];
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
let draw_mode_entries: Vec<_> = [DrawMode::Draw, DrawMode::Erase, DrawMode::Restore]
|
let draw_mode_entries: Vec<_> = [DrawMode::Draw, DrawMode::Erase, DrawMode::Restore]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -149,7 +149,7 @@ impl LayoutHolder for BrushTool {
|
||||||
.collect();
|
.collect();
|
||||||
widgets.push(RadioInput::new(draw_mode_entries).selected_index(Some(self.options.draw_mode as u32)).widget_holder());
|
widgets.push(RadioInput::new(draw_mode_entries).selected_index(Some(self.options.draw_mode as u32)).widget_holder());
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.color.create_widgets(
|
widgets.append(&mut self.options.color.create_widgets(
|
||||||
"Color",
|
"Color",
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ impl LayoutHolder for EllipseTool {
|
||||||
|color: &ColorButton| EllipseToolMessage::UpdateOptions(EllipseOptionsUpdate::FillColor(color.value)).into(),
|
|color: &ColorButton| EllipseToolMessage::UpdateOptions(EllipseOptionsUpdate::FillColor(color.value)).into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ impl LayoutHolder for FreehandTool {
|
||||||
|color: &ColorButton| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColor(color.value)).into(),
|
|color: &ColorButton| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::FillColor(color.value)).into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ impl LayoutHolder for PenTool {
|
||||||
|color: &ColorButton| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColor(color.value)).into(),
|
|color: &ColorButton| PenToolMessage::UpdateOptions(PenOptionsUpdate::FillColor(color.value)).into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ impl LayoutHolder for PolygonTool {
|
||||||
create_sides_widget(self.options.vertices),
|
create_sides_widget(self.options.vertices),
|
||||||
];
|
];
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.fill.create_widgets(
|
widgets.append(&mut self.options.fill.create_widgets(
|
||||||
"Fill",
|
"Fill",
|
||||||
|
|
@ -135,7 +135,7 @@ impl LayoutHolder for PolygonTool {
|
||||||
|color: &ColorButton| PolygonToolMessage::UpdateOptions(PolygonOptionsUpdate::FillColor(color.value)).into(),
|
|color: &ColorButton| PolygonToolMessage::UpdateOptions(PolygonOptionsUpdate::FillColor(color.value)).into(),
|
||||||
));
|
));
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ impl LayoutHolder for RectangleTool {
|
||||||
|color: &ColorButton| RectangleToolMessage::UpdateOptions(RectangleOptionsUpdate::FillColor(color.value)).into(),
|
|color: &ColorButton| RectangleToolMessage::UpdateOptions(RectangleOptionsUpdate::FillColor(color.value)).into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
|
|
|
||||||
|
|
@ -175,23 +175,20 @@ impl LayoutHolder for SelectTool {
|
||||||
|
|
||||||
// Align
|
// Align
|
||||||
let disabled = self.tool_data.selected_layers_count < 2;
|
let disabled = self.tool_data.selected_layers_count < 2;
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
widgets.extend(self.alignment_widgets(disabled));
|
widgets.extend(self.alignment_widgets(disabled));
|
||||||
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
|
||||||
widgets.push(PopoverButton::new("Align", "Coming soon").disabled(disabled).widget_holder());
|
widgets.push(PopoverButton::new("Align", "Coming soon").disabled(disabled).widget_holder());
|
||||||
|
|
||||||
// Flip
|
// Flip
|
||||||
let disabled = self.tool_data.selected_layers_count == 0;
|
let disabled = self.tool_data.selected_layers_count == 0;
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
widgets.extend(self.flip_widgets(disabled));
|
widgets.extend(self.flip_widgets(disabled));
|
||||||
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
|
||||||
widgets.push(PopoverButton::new("Flip", "Coming soon").disabled(disabled).widget_holder());
|
widgets.push(PopoverButton::new("Flip", "Coming soon").disabled(disabled).widget_holder());
|
||||||
|
|
||||||
// Boolean
|
// Boolean
|
||||||
if self.tool_data.selected_layers_count >= 2 {
|
if self.tool_data.selected_layers_count >= 2 {
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
widgets.extend(self.boolean_widgets());
|
widgets.extend(self.boolean_widgets());
|
||||||
widgets.push(Separator::new(SeparatorType::Related).widget_holder());
|
|
||||||
widgets.push(PopoverButton::new("Boolean", "Coming soon").widget_holder());
|
widgets.push(PopoverButton::new("Boolean", "Coming soon").widget_holder());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ impl LayoutHolder for SplineTool {
|
||||||
|color: &ColorButton| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColor(color.value)).into(),
|
|color: &ColorButton| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::FillColor(color.value)).into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.stroke.create_widgets(
|
widgets.append(&mut self.options.stroke.create_widgets(
|
||||||
"Stroke",
|
"Stroke",
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ impl LayoutHolder for TextTool {
|
||||||
fn layout(&self) -> Layout {
|
fn layout(&self) -> Layout {
|
||||||
let mut widgets = create_text_widgets(self);
|
let mut widgets = create_text_widgets(self);
|
||||||
|
|
||||||
widgets.push(Separator::new(SeparatorType::Section).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
widgets.append(&mut self.options.fill.create_widgets(
|
widgets.append(&mut self.options.fill.create_widgets(
|
||||||
"Fill",
|
"Fill",
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ impl DocumentToolData {
|
||||||
pub fn update_working_colors(&self, responses: &mut VecDeque<Message>) {
|
pub fn update_working_colors(&self, responses: &mut VecDeque<Message>) {
|
||||||
let layout = WidgetLayout::new(vec![
|
let layout = WidgetLayout::new(vec![
|
||||||
LayoutGroup::Row {
|
LayoutGroup::Row {
|
||||||
widgets: vec![WorkingColorsButton::new(self.primary_color, self.secondary_color).widget_holder()],
|
widgets: vec![WorkingColorsInput::new(self.primary_color, self.secondary_color).widget_holder()],
|
||||||
},
|
},
|
||||||
LayoutGroup::Row {
|
LayoutGroup::Row {
|
||||||
widgets: vec![
|
widgets: vec![
|
||||||
|
|
|
||||||
|
|
@ -189,11 +189,6 @@
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sharp-right-corners.sharp-right-corners.sharp-right-corners.sharp-right-corners {
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-row,
|
.layout-row,
|
||||||
.layout-col {
|
.layout-col {
|
||||||
.scrollable-x,
|
.scrollable-x,
|
||||||
|
|
@ -265,7 +260,7 @@
|
||||||
.popover-button,
|
.popover-button,
|
||||||
.color-button > button,
|
.color-button > button,
|
||||||
.color-picker .preset-color,
|
.color-picker .preset-color,
|
||||||
.working-colors-button .swatch > button,
|
.working-colors-input .swatch > button,
|
||||||
.radio-input button,
|
.radio-input button,
|
||||||
.menu-list,
|
.menu-list,
|
||||||
.menu-list-button .entry,
|
.menu-list-button .entry,
|
||||||
|
|
|
||||||
|
|
@ -537,7 +537,7 @@
|
||||||
width: 208px;
|
width: 208px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
border: 1px solid var(--color-0-black);
|
border: 1px solid var(--color-1-nearblack);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,13 +41,13 @@
|
||||||
<div class="widget-layout details">
|
<div class="widget-layout details">
|
||||||
<div class="widget-span row"><TextLabel bold={true}>The editor crashed — sorry about that</TextLabel></div>
|
<div class="widget-span row"><TextLabel bold={true}>The editor crashed — sorry about that</TextLabel></div>
|
||||||
<div class="widget-span row"><TextLabel>Please report this by filing an issue on GitHub:</TextLabel></div>
|
<div class="widget-span row"><TextLabel>Please report this by filing an issue on GitHub:</TextLabel></div>
|
||||||
<div class="widget-span row"><TextButton label="Report Bug" icon="Warning" noBackground={true} action={() => window.open(githubUrl($dialog.panicDetails), "_blank")} /></div>
|
<div class="widget-span row"><TextButton label="Report Bug" icon="Warning" flush={true} action={() => window.open(githubUrl($dialog.panicDetails), "_blank")} /></div>
|
||||||
<div class="widget-span row"><TextLabel multiline={true}>Reload the editor to continue. If this occurs<br />immediately on repeated reloads, clear storage:</TextLabel></div>
|
<div class="widget-span row"><TextLabel multiline={true}>Reload the editor to continue. If this occurs<br />immediately on repeated reloads, clear storage:</TextLabel></div>
|
||||||
<div class="widget-span row">
|
<div class="widget-span row">
|
||||||
<TextButton
|
<TextButton
|
||||||
label="Clear Saved Documents"
|
label="Clear Saved Documents"
|
||||||
icon="Trash"
|
icon="Trash"
|
||||||
noBackground={true}
|
flush={true}
|
||||||
action={async () => {
|
action={async () => {
|
||||||
await wipeDocuments();
|
await wipeDocuments();
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
{#each entries as section, sectionIndex (sectionIndex)}
|
{#each entries as section, sectionIndex (sectionIndex)}
|
||||||
{#if sectionIndex > 0}
|
{#if sectionIndex > 0}
|
||||||
<Separator type="List" direction="Vertical" />
|
<Separator type="Section" direction="Vertical" />
|
||||||
{/if}
|
{/if}
|
||||||
{#each virtualScrollingEntryHeight ? section.slice(virtualScrollingStartIndex, virtualScrollingEndIndex) : section as entry, entryIndex (entryIndex + startIndex)}
|
{#each virtualScrollingEntryHeight ? section.slice(virtualScrollingStartIndex, virtualScrollingEndIndex) : section as entry, entryIndex (entryIndex + startIndex)}
|
||||||
<LayoutRow
|
<LayoutRow
|
||||||
|
|
@ -264,8 +264,12 @@
|
||||||
.floating-menu-container .floating-menu-content.floating-menu-content {
|
.floating-menu-container .floating-menu-content.floating-menu-content {
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
|
|
||||||
.separator div {
|
.separator {
|
||||||
background: var(--color-4-dimgray);
|
margin: 4px 0;
|
||||||
|
|
||||||
|
div {
|
||||||
|
background: var(--color-4-dimgray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-spacer {
|
.scroll-spacer {
|
||||||
|
|
@ -333,7 +337,7 @@
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&.open {
|
&.open {
|
||||||
background: var(--color-5-dullgray);
|
background: var(--color-4-dimgray);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
|
|
|
||||||
|
|
@ -450,8 +450,7 @@
|
||||||
<LayoutRow class="spacer" />
|
<LayoutRow class="spacer" />
|
||||||
{/if}
|
{/if}
|
||||||
<LayoutCol class="shelf-bottom-widgets">
|
<LayoutCol class="shelf-bottom-widgets">
|
||||||
<WidgetLayout class={"graph-overlay-button-area"} layout={$document.graphViewOverlayButtonLayout} />
|
<WidgetLayout class={"working-colors-input-area"} layout={$document.workingColorsLayout} />
|
||||||
<WidgetLayout class={"working-colors-button-area"} layout={$document.workingColorsLayout} />
|
|
||||||
</LayoutCol>
|
</LayoutCol>
|
||||||
</LayoutCol>
|
</LayoutCol>
|
||||||
<LayoutCol class="table">
|
<LayoutCol class="table">
|
||||||
|
|
@ -519,6 +518,10 @@
|
||||||
.document {
|
.document {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
&.document.document {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.options-bar {
|
.options-bar {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
@ -537,12 +540,14 @@
|
||||||
// Enables usage of the `100cqh` unit to reference the height of this container element.
|
// Enables usage of the `100cqh` unit to reference the height of this container element.
|
||||||
container-type: size;
|
container-type: size;
|
||||||
// Be sure to recalculate this if the items below the tools (working colors and graph overlay buttons) change height in the future.
|
// Be sure to recalculate this if the items below the tools (working colors and graph overlay buttons) change height in the future.
|
||||||
--height-of-elements-below-tools: 104px;
|
--height-of-elements-below-tools: 64px;
|
||||||
// Target height for the tools within the container above the lower elements.
|
// Target height for the tools within the container above the lower elements.
|
||||||
--available-height: calc(100cqh - var(--height-of-elements-below-tools));
|
--available-height: calc(100cqh - var(--height-of-elements-below-tools));
|
||||||
|
// Be sure to update this if the height changes as set in `Separator.svelte`.
|
||||||
|
--separator-height: calc(12px + 1px + 12px);
|
||||||
// The least height required to fit all the tools in 1 column and 2 columns, which the available space must exceed in order for the fewest number of columns to be used.
|
// The least height required to fit all the tools in 1 column and 2 columns, which the available space must exceed in order for the fewest number of columns to be used.
|
||||||
--1-col-required-height: calc(var(--total-tool-rows-for-1-columns) * 32px + var(--total-separators) * (1px + 8px * 2));
|
--1-col-required-height: calc(var(--total-tool-rows-for-1-columns) * 32px + var(--total-separators) * var(--separator-height));
|
||||||
--2-col-required-height: calc(var(--total-tool-rows-for-2-columns) * 32px + var(--total-separators) * (1px + 8px * 2));
|
--2-col-required-height: calc(var(--total-tool-rows-for-2-columns) * 32px + var(--total-separators) * var(--separator-height));
|
||||||
// Evaluates to 0px (if false) or 1px (if true). We multiply by 1000000 to force the result to be an integer 0 or 1 and not interpolate values in-between.
|
// Evaluates to 0px (if false) or 1px (if true). We multiply by 1000000 to force the result to be an integer 0 or 1 and not interpolate values in-between.
|
||||||
--needs-at-least-2-columns: calc(1px - clamp(0px, calc((var(--available-height) - Min(var(--available-height), var(--1-col-required-height))) * 1000000), 1px));
|
--needs-at-least-2-columns: calc(1px - clamp(0px, calc((var(--available-height) - Min(var(--available-height), var(--1-col-required-height))) * 1000000), 1px));
|
||||||
--needs-at-least-3-columns: calc(1px - clamp(0px, calc((var(--available-height) - Min(var(--available-height), var(--2-col-required-height))) * 1000000), 1px));
|
--needs-at-least-3-columns: calc(1px - clamp(0px, calc((var(--available-height) - Min(var(--available-height), var(--2-col-required-height))) * 1000000), 1px));
|
||||||
|
|
@ -563,7 +568,7 @@
|
||||||
// Remove this when the Firefox bug is fixed.
|
// Remove this when the Firefox bug is fixed.
|
||||||
@-moz-document url-prefix() {
|
@-moz-document url-prefix() {
|
||||||
--available-height-plus-1: calc(var(--available-height) + 1px);
|
--available-height-plus-1: calc(var(--available-height) + 1px);
|
||||||
--3-col-required-height: calc(var(--total-tool-rows-for-3-columns) * 32px + var(--total-separators) * (1px + 8px * 2));
|
--3-col-required-height: calc(var(--total-tool-rows-for-3-columns) * 32px + var(--total-separators) * var(--separator-height));
|
||||||
--overflows-with-3-columns: calc(1px - clamp(0px, calc((var(--available-height-plus-1) - Min(var(--available-height-plus-1), var(--3-col-required-height))) * 1000000), 1px));
|
--overflows-with-3-columns: calc(1px - clamp(0px, calc((var(--available-height-plus-1) - Min(var(--available-height-plus-1), var(--3-col-required-height))) * 1000000), 1px));
|
||||||
--firefox-scrollbar-width-space-occupied: 8; // Might change someday, or on different platforms, but this is the value in FF 120 on Windows
|
--firefox-scrollbar-width-space-occupied: 8; // Might change someday, or on different platforms, but this is the value in FF 120 on Windows
|
||||||
padding-right: calc(var(--firefox-scrollbar-width-space-occupied) * var(--overflows-with-3-columns));
|
padding-right: calc(var(--firefox-scrollbar-width-space-occupied) * var(--overflows-with-3-columns));
|
||||||
|
|
@ -610,17 +615,12 @@
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.graph-overlay-button-area {
|
.working-colors-input-area {
|
||||||
height: auto;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.working-colors-button-area {
|
|
||||||
height: auto;
|
height: auto;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|
||||||
.working-colors-button {
|
.working-colors-input {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -505,7 +505,6 @@
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font-style: italic;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,16 @@
|
||||||
|
|
||||||
.sections {
|
.sections {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
|
|
||||||
|
// Used as a placeholder for empty assist widgets
|
||||||
|
.separator.section.horizontal {
|
||||||
|
margin: 0;
|
||||||
|
margin-left: 24px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-button {
|
.text-button {
|
||||||
|
|
|
||||||
|
|
@ -741,7 +741,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
||||||
<TextLabel tooltip={editor.instance.inDevelopmentMode() ? `Node ID: ${node.id}` : undefined} italic={!node.alias}>{node.alias || "Layer"}</TextLabel>
|
<TextLabel tooltip={editor.instance.inDevelopmentMode() ? `Node ID: ${node.id}` : undefined}>{node.alias || "Layer"}</TextLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<svg class="border-mask" width="0" height="0">
|
<svg class="border-mask" width="0" height="0">
|
||||||
|
|
@ -773,14 +773,13 @@
|
||||||
<div class="primary" class:no-parameter-section={exposedInputsOutputs.length === 0}>
|
<div class="primary" class:no-parameter-section={exposedInputsOutputs.length === 0}>
|
||||||
<IconLabel icon={nodeIcon(node.name)} />
|
<IconLabel icon={nodeIcon(node.name)} />
|
||||||
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
||||||
<TextLabel tooltip={editor.instance.inDevelopmentMode() ? `Node ID: ${node.id}` : undefined} italic={!node.alias}>{node.alias || node.name}</TextLabel>
|
<TextLabel tooltip={editor.instance.inDevelopmentMode() ? `Node ID: ${node.id}` : undefined}>{node.alias || node.name}</TextLabel>
|
||||||
</div>
|
</div>
|
||||||
<!-- Parameter rows -->
|
<!-- Parameter rows -->
|
||||||
{#if exposedInputsOutputs.length > 0}
|
{#if exposedInputsOutputs.length > 0}
|
||||||
<div class="parameters">
|
<div class="parameters">
|
||||||
{#each exposedInputsOutputs as parameter, index}
|
{#each exposedInputsOutputs as parameter, index}
|
||||||
<div class={`parameter expanded ${index < node.exposedInputs.length ? "input" : "output"}`}>
|
<div class={`parameter expanded ${index < node.exposedInputs.length ? "input" : "output"}`}>
|
||||||
<div class="expand-arrow" />
|
|
||||||
<TextLabel tooltip={parameter.name}>{parameter.name}</TextLabel>
|
<TextLabel tooltip={parameter.name}>{parameter.name}</TextLabel>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
@ -1005,10 +1004,6 @@
|
||||||
.icon-label {
|
.icon-label {
|
||||||
fill: var(--color-a-softgray);
|
fill: var(--color-a-softgray);
|
||||||
}
|
}
|
||||||
|
|
||||||
.expand-arrow::after {
|
|
||||||
background: var(--icon-expand-collapse-arrow-disabled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.previewed::after {
|
&.previewed::after {
|
||||||
|
|
@ -1035,34 +1030,6 @@
|
||||||
height: 8px;
|
height: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expand-arrow {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
position: relative;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
background: var(--icon-expand-collapse-arrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover::after {
|
|
||||||
background: var(--icon-expand-collapse-arrow-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.expanded .expand-arrow::after {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-label {
|
.text-label {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
@ -1201,8 +1168,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-label {
|
.text-label {
|
||||||
margin-left: 8px; // Remove after reenabling icon-label
|
// margin-right: 4px; // Restore after reenabling icon-label
|
||||||
margin-right: 4px;
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1216,7 +1183,8 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
margin: 0 8px;
|
||||||
|
width: calc(100% - 8px - 8px);
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
|
||||||
&:last-of-type {
|
&:last-of-type {
|
||||||
|
|
@ -1227,19 +1195,10 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.input {
|
|
||||||
.expand-arrow {
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.output {
|
&.output {
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
||||||
.expand-arrow {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
svg {
|
svg {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,10 @@
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
|
|
||||||
|
+ .widget-section {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -107,7 +111,6 @@
|
||||||
padding: 0 7px;
|
padding: 0 7px;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
margin-top: -1px;
|
margin-top: -1px;
|
||||||
margin-bottom: 4px;
|
|
||||||
border: 1px solid var(--color-2-mildblack);
|
border: 1px solid var(--color-2-mildblack);
|
||||||
border-radius: 0 0 4px 4px;
|
border-radius: 0 0 4px 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
@ -130,8 +133,8 @@
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .parameter-expose-button ~ .text-label:first-of-type {
|
> .parameter-expose-button + .text-label:first-of-type {
|
||||||
margin-left: 0;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .text-button {
|
> .text-button {
|
||||||
|
|
|
||||||
|
|
@ -12,25 +12,22 @@
|
||||||
import ParameterExposeButton from "@graphite/components/widgets/buttons/ParameterExposeButton.svelte";
|
import ParameterExposeButton from "@graphite/components/widgets/buttons/ParameterExposeButton.svelte";
|
||||||
import PopoverButton from "@graphite/components/widgets/buttons/PopoverButton.svelte";
|
import PopoverButton from "@graphite/components/widgets/buttons/PopoverButton.svelte";
|
||||||
import TextButton from "@graphite/components/widgets/buttons/TextButton.svelte";
|
import TextButton from "@graphite/components/widgets/buttons/TextButton.svelte";
|
||||||
import WorkingColorsButton from "@graphite/components/widgets/buttons/WorkingColorsButton.svelte";
|
|
||||||
import CheckboxInput from "@graphite/components/widgets/inputs/CheckboxInput.svelte";
|
import CheckboxInput from "@graphite/components/widgets/inputs/CheckboxInput.svelte";
|
||||||
import CurveInput from "@graphite/components/widgets/inputs/CurveInput.svelte";
|
import CurveInput from "@graphite/components/widgets/inputs/CurveInput.svelte";
|
||||||
import DropdownInput from "@graphite/components/widgets/inputs/DropdownInput.svelte";
|
import DropdownInput from "@graphite/components/widgets/inputs/DropdownInput.svelte";
|
||||||
import FontInput from "@graphite/components/widgets/inputs/FontInput.svelte";
|
import FontInput from "@graphite/components/widgets/inputs/FontInput.svelte";
|
||||||
import NumberInput from "@graphite/components/widgets/inputs/NumberInput.svelte";
|
import NumberInput from "@graphite/components/widgets/inputs/NumberInput.svelte";
|
||||||
import OptionalInput from "@graphite/components/widgets/inputs/OptionalInput.svelte";
|
|
||||||
import PivotInput from "@graphite/components/widgets/inputs/PivotInput.svelte";
|
import PivotInput from "@graphite/components/widgets/inputs/PivotInput.svelte";
|
||||||
import RadioInput from "@graphite/components/widgets/inputs/RadioInput.svelte";
|
import RadioInput from "@graphite/components/widgets/inputs/RadioInput.svelte";
|
||||||
import TextAreaInput from "@graphite/components/widgets/inputs/TextAreaInput.svelte";
|
import TextAreaInput from "@graphite/components/widgets/inputs/TextAreaInput.svelte";
|
||||||
import TextInput from "@graphite/components/widgets/inputs/TextInput.svelte";
|
import TextInput from "@graphite/components/widgets/inputs/TextInput.svelte";
|
||||||
|
import WorkingColorsInput from "@graphite/components/widgets/inputs/WorkingColorsInput.svelte";
|
||||||
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
|
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
|
||||||
import ImageLabel from "@graphite/components/widgets/labels/ImageLabel.svelte";
|
import ImageLabel from "@graphite/components/widgets/labels/ImageLabel.svelte";
|
||||||
import Separator from "@graphite/components/widgets/labels/Separator.svelte";
|
import Separator from "@graphite/components/widgets/labels/Separator.svelte";
|
||||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||||
import WidgetLayout from "@graphite/components/widgets/WidgetLayout.svelte";
|
import WidgetLayout from "@graphite/components/widgets/WidgetLayout.svelte";
|
||||||
|
|
||||||
const SUFFIX_WIDGETS = ["PopoverButton"];
|
|
||||||
|
|
||||||
const editor = getContext<Editor>("editor");
|
const editor = getContext<Editor>("editor");
|
||||||
|
|
||||||
export let widgetData: WidgetSpanRow | WidgetSpanColumn;
|
export let widgetData: WidgetSpanRow | WidgetSpanColumn;
|
||||||
|
|
@ -47,7 +44,6 @@
|
||||||
|
|
||||||
$: direction = watchDirection(widgetData);
|
$: direction = watchDirection(widgetData);
|
||||||
$: widgets = watchWidgets(widgetData);
|
$: widgets = watchWidgets(widgetData);
|
||||||
$: widgetsAndNextSiblingIsSuffix = watchWidgetsAndNextSiblingIsSuffix(widgets);
|
|
||||||
|
|
||||||
function watchDirection(widgetData: WidgetSpanRow | WidgetSpanColumn): "row" | "column" | undefined {
|
function watchDirection(widgetData: WidgetSpanRow | WidgetSpanColumn): "row" | "column" | undefined {
|
||||||
if (isWidgetSpanRow(widgetData)) return "row";
|
if (isWidgetSpanRow(widgetData)) return "row";
|
||||||
|
|
@ -61,17 +57,6 @@
|
||||||
return widgets;
|
return widgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
function watchWidgetsAndNextSiblingIsSuffix(widgets: Widget[]): [Widget, boolean][] {
|
|
||||||
return widgets.map((widget, index): [Widget, boolean] => {
|
|
||||||
// A suffix widget is one that joins up with this widget at the end with only a 1px gap.
|
|
||||||
// It uses the CSS sibling selector to give its own left edge corners zero radius.
|
|
||||||
// But this JS is needed to set its preceding sibling widget's right edge corners to zero radius.
|
|
||||||
const nextSiblingIsSuffix = SUFFIX_WIDGETS.includes(widgets[index + 1]?.props.kind);
|
|
||||||
|
|
||||||
return [widget, nextSiblingIsSuffix];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLayout(index: number, value: unknown) {
|
function updateLayout(index: number, value: unknown) {
|
||||||
editor.instance.updateLayout(layoutTarget, widgets[index].widgetId, value);
|
editor.instance.updateLayout(layoutTarget, widgets[index].widgetId, value);
|
||||||
}
|
}
|
||||||
|
|
@ -88,14 +73,14 @@
|
||||||
<!-- TODO: Refactor this component to use `<svelte:component this={attributesObject} />` to avoid all the separate conditional components -->
|
<!-- TODO: Refactor this component to use `<svelte:component this={attributesObject} />` to avoid all the separate conditional components -->
|
||||||
|
|
||||||
<div class={`widget-span ${className} ${extraClasses}`.trim()} class:row={direction === "row"} class:column={direction === "column"}>
|
<div class={`widget-span ${className} ${extraClasses}`.trim()} class:row={direction === "row"} class:column={direction === "column"}>
|
||||||
{#each widgetsAndNextSiblingIsSuffix as [component, nextIsSuffix], index}
|
{#each widgets as component, index}
|
||||||
{@const checkboxInput = narrowWidgetProps(component.props, "CheckboxInput")}
|
{@const checkboxInput = narrowWidgetProps(component.props, "CheckboxInput")}
|
||||||
{#if checkboxInput}
|
{#if checkboxInput}
|
||||||
<CheckboxInput {...exclude(checkboxInput)} on:checked={({ detail }) => updateLayout(index, detail)} />
|
<CheckboxInput {...exclude(checkboxInput)} on:checked={({ detail }) => updateLayout(index, detail)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const colorInput = narrowWidgetProps(component.props, "ColorButton")}
|
{@const colorInput = narrowWidgetProps(component.props, "ColorButton")}
|
||||||
{#if colorInput}
|
{#if colorInput}
|
||||||
<ColorButton {...exclude(colorInput)} on:value={({ detail }) => updateLayout(index, detail)} sharpRightCorners={nextIsSuffix} />
|
<ColorButton {...exclude(colorInput)} on:value={({ detail }) => updateLayout(index, detail)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const curvesInput = narrowWidgetProps(component.props, "CurveInput")}
|
{@const curvesInput = narrowWidgetProps(component.props, "CurveInput")}
|
||||||
{#if curvesInput}
|
{#if curvesInput}
|
||||||
|
|
@ -103,11 +88,11 @@
|
||||||
{/if}
|
{/if}
|
||||||
{@const dropdownInput = narrowWidgetProps(component.props, "DropdownInput")}
|
{@const dropdownInput = narrowWidgetProps(component.props, "DropdownInput")}
|
||||||
{#if dropdownInput}
|
{#if dropdownInput}
|
||||||
<DropdownInput {...exclude(dropdownInput)} on:selectedIndex={({ detail }) => updateLayout(index, detail)} sharpRightCorners={nextIsSuffix} />
|
<DropdownInput {...exclude(dropdownInput)} on:selectedIndex={({ detail }) => updateLayout(index, detail)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const fontInput = narrowWidgetProps(component.props, "FontInput")}
|
{@const fontInput = narrowWidgetProps(component.props, "FontInput")}
|
||||||
{#if fontInput}
|
{#if fontInput}
|
||||||
<FontInput {...exclude(fontInput)} on:changeFont={({ detail }) => updateLayout(index, detail)} sharpRightCorners={nextIsSuffix} />
|
<FontInput {...exclude(fontInput)} on:changeFont={({ detail }) => updateLayout(index, detail)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const parameterExposeButton = narrowWidgetProps(component.props, "ParameterExposeButton")}
|
{@const parameterExposeButton = narrowWidgetProps(component.props, "ParameterExposeButton")}
|
||||||
{#if parameterExposeButton}
|
{#if parameterExposeButton}
|
||||||
|
|
@ -115,7 +100,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
{@const iconButton = narrowWidgetProps(component.props, "IconButton")}
|
{@const iconButton = narrowWidgetProps(component.props, "IconButton")}
|
||||||
{#if iconButton}
|
{#if iconButton}
|
||||||
<IconButton {...exclude(iconButton)} action={() => updateLayout(index, undefined)} sharpRightCorners={nextIsSuffix} />
|
<IconButton {...exclude(iconButton)} action={() => updateLayout(index, undefined)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const iconLabel = narrowWidgetProps(component.props, "IconLabel")}
|
{@const iconLabel = narrowWidgetProps(component.props, "IconLabel")}
|
||||||
{#if iconLabel}
|
{#if iconLabel}
|
||||||
|
|
@ -132,13 +117,8 @@
|
||||||
on:value={({ detail }) => debouncer((value) => updateLayout(index, value)).debounceUpdateValue(detail)}
|
on:value={({ detail }) => debouncer((value) => updateLayout(index, value)).debounceUpdateValue(detail)}
|
||||||
incrementCallbackIncrease={() => updateLayout(index, "Increment")}
|
incrementCallbackIncrease={() => updateLayout(index, "Increment")}
|
||||||
incrementCallbackDecrease={() => updateLayout(index, "Decrement")}
|
incrementCallbackDecrease={() => updateLayout(index, "Decrement")}
|
||||||
sharpRightCorners={nextIsSuffix}
|
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{@const optionalInput = narrowWidgetProps(component.props, "OptionalInput")}
|
|
||||||
{#if optionalInput}
|
|
||||||
<OptionalInput {...exclude(optionalInput)} on:checked={({ detail }) => updateLayout(index, detail)} />
|
|
||||||
{/if}
|
|
||||||
{@const pivotInput = narrowWidgetProps(component.props, "PivotInput")}
|
{@const pivotInput = narrowWidgetProps(component.props, "PivotInput")}
|
||||||
{#if pivotInput}
|
{#if pivotInput}
|
||||||
<PivotInput {...exclude(pivotInput)} on:position={({ detail }) => updateLayout(index, detail)} />
|
<PivotInput {...exclude(pivotInput)} on:position={({ detail }) => updateLayout(index, detail)} />
|
||||||
|
|
@ -156,15 +136,15 @@
|
||||||
{/if}
|
{/if}
|
||||||
{@const radioInput = narrowWidgetProps(component.props, "RadioInput")}
|
{@const radioInput = narrowWidgetProps(component.props, "RadioInput")}
|
||||||
{#if radioInput}
|
{#if radioInput}
|
||||||
<RadioInput {...exclude(radioInput)} on:selectedIndex={({ detail }) => updateLayout(index, detail)} sharpRightCorners={nextIsSuffix} />
|
<RadioInput {...exclude(radioInput)} on:selectedIndex={({ detail }) => updateLayout(index, detail)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const separator = narrowWidgetProps(component.props, "Separator")}
|
{@const separator = narrowWidgetProps(component.props, "Separator")}
|
||||||
{#if separator}
|
{#if separator}
|
||||||
<Separator {...exclude(separator)} />
|
<Separator {...exclude(separator)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const workingColorsButton = narrowWidgetProps(component.props, "WorkingColorsButton")}
|
{@const workingColorsInput = narrowWidgetProps(component.props, "WorkingColorsInput")}
|
||||||
{#if workingColorsButton}
|
{#if workingColorsInput}
|
||||||
<WorkingColorsButton {...exclude(workingColorsButton)} />
|
<WorkingColorsInput {...exclude(workingColorsInput)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const textAreaInput = narrowWidgetProps(component.props, "TextAreaInput")}
|
{@const textAreaInput = narrowWidgetProps(component.props, "TextAreaInput")}
|
||||||
{#if textAreaInput}
|
{#if textAreaInput}
|
||||||
|
|
@ -172,7 +152,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
{@const textButton = narrowWidgetProps(component.props, "TextButton")}
|
{@const textButton = narrowWidgetProps(component.props, "TextButton")}
|
||||||
{#if textButton}
|
{#if textButton}
|
||||||
<TextButton {...exclude(textButton)} action={() => updateLayout(index, undefined)} sharpRightCorners={nextIsSuffix} />
|
<TextButton {...exclude(textButton)} action={() => updateLayout(index, undefined)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const breadcrumbTrailButtons = narrowWidgetProps(component.props, "BreadcrumbTrailButtons")}
|
{@const breadcrumbTrailButtons = narrowWidgetProps(component.props, "BreadcrumbTrailButtons")}
|
||||||
{#if breadcrumbTrailButtons}
|
{#if breadcrumbTrailButtons}
|
||||||
|
|
@ -180,7 +160,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
{@const textInput = narrowWidgetProps(component.props, "TextInput")}
|
{@const textInput = narrowWidgetProps(component.props, "TextInput")}
|
||||||
{#if textInput}
|
{#if textInput}
|
||||||
<TextInput {...exclude(textInput)} on:commitText={({ detail }) => updateLayout(index, detail)} sharpRightCorners={nextIsSuffix} />
|
<TextInput {...exclude(textInput)} on:commitText={({ detail }) => updateLayout(index, detail)} />
|
||||||
{/if}
|
{/if}
|
||||||
{@const textLabel = narrowWidgetProps(component.props, "TextLabel")}
|
{@const textLabel = narrowWidgetProps(component.props, "TextLabel")}
|
||||||
{#if textLabel}
|
{#if textLabel}
|
||||||
|
|
@ -218,31 +198,6 @@
|
||||||
--widget-height: 16px;
|
--widget-height: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Target this in a better way than using the tooltip, which will break if changed, or when localized/translated
|
|
||||||
.checkbox-input [title="Preserve Aspect Ratio"] {
|
|
||||||
margin-bottom: -32px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
content: "";
|
|
||||||
pointer-events: none;
|
|
||||||
position: absolute;
|
|
||||||
left: 8px;
|
|
||||||
width: 1px;
|
|
||||||
height: 16px;
|
|
||||||
background: var(--color-7-middlegray);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
top: calc(-4px - 16px);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
bottom: calc(-4px - 16px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// paddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpadding
|
// paddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpaddingpadding
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,9 @@
|
||||||
export let allowNone = false;
|
export let allowNone = false;
|
||||||
// export let allowTransparency = false; // TODO: Implement
|
// export let allowTransparency = false; // TODO: Implement
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LayoutCol class="color-button" classes={{ disabled, none: value.none, open, "sharp-right-corners": sharpRightCorners }} {tooltip}>
|
<LayoutCol class="color-button" classes={{ disabled, none: value.none, open }} {tooltip}>
|
||||||
<button {disabled} style:--chosen-color={value.toHexOptionalAlpha()} on:click={() => (open = true)} tabindex="0" data-floating-menu-spawner></button>
|
<button {disabled} style:--chosen-color={value.toHexOptionalAlpha()} on:click={() => (open = true)} tabindex="0" data-floating-menu-spawner></button>
|
||||||
{#if disabled && !value.none}
|
{#if disabled && !value.none}
|
||||||
<TextLabel>sRGB</TextLabel>
|
<TextLabel>sRGB</TextLabel>
|
||||||
|
|
@ -59,11 +58,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.sharp-right-corners {
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> button {
|
> button {
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let active = false;
|
export let active = false;
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
export let action: (e?: MouseEvent) => void;
|
export let action: (e?: MouseEvent) => void;
|
||||||
|
|
||||||
|
|
@ -21,17 +20,7 @@
|
||||||
.join(" ");
|
.join(" ");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button class={`icon-button size-${size} ${className} ${extraClasses}`.trim()} class:disabled class:active on:click={action} {disabled} title={tooltip} tabindex={active ? -1 : 0} {...$$restProps}>
|
||||||
class={`icon-button size-${size} ${className} ${extraClasses}`.trim()}
|
|
||||||
class:disabled
|
|
||||||
class:active
|
|
||||||
class:sharp-right-corners={sharpRightCorners}
|
|
||||||
on:click={action}
|
|
||||||
{disabled}
|
|
||||||
title={tooltip}
|
|
||||||
tabindex={active ? -1 : 0}
|
|
||||||
{...$$restProps}
|
|
||||||
>
|
|
||||||
<IconLabel {icon} />
|
<IconLabel {icon} />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,22 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LayoutRow class="parameter-expose-button">
|
<LayoutRow class="parameter-expose-button">
|
||||||
<button class:exposed style:--data-type-color={`var(--color-data-${dataType})`} on:click={action} title={tooltip} tabindex="-1" />
|
<button class:exposed style:--data-type-color={`var(--color-data-${dataType})`} on:click={action} title={tooltip} tabindex="-1">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
|
||||||
|
<path class="interior" d="M0,7.882c0,1.832,1.325,2.63,2.945,1.772L8.785,6.56c1.62-.858,1.62-2.262,0-3.12L2.945.345C1.325-.512,0,.285,0,2.118Z" />
|
||||||
|
<path
|
||||||
|
class="outline"
|
||||||
|
d="M 1.705180287361145 9.999852180480957 L 1.705180287361145 8.999852180480957 C 1.9275803565979 8.999852180480957 2.194530248641968 8.920772552490234 2.476730346679688
|
||||||
|
8.771392822265625 L 8.31682014465332 5.67636251449585 C 8.788760185241699 5.426312446594238 9 5.156492233276367 9 5.000002384185791 C 9 4.843512535095215 8.788760185241699
|
||||||
|
4.573692321777344 8.316730499267578 4.323602199554443 L 2.477190256118774 1.228852391242981 C 2.194520235061646 1.079232335090637 1.927510380744934 1.000152349472046 1.70503032207489
|
||||||
|
1.000152349472046 C 1.091590285301208 1.000152349472046 1.000000357627869 1.700212359428406 1.000000357627869 2.117512464523315 L 1.000000357627869 7.882492542266846 C
|
||||||
|
1.000000357627869 8.299762725830078 1.091610312461853 8.999792098999023 1.705130338668823 8.999852180480957 L 1.705180287361145 9.999852180480957 M 1.705027341842651 9.999849319458008
|
||||||
|
C 0.7003514766693115 9.999751091003418 0 9.214582443237305 0 7.882492542266846 L 0 2.117512464523315 C 0 0.2850223779678345 1.325000405311584 -0.512467622756958 2.945000410079956
|
||||||
|
0.3450223803520203 L 8.785000801086426 3.440012454986572 C 10.40500068664551 4.298342227935791 10.40500068664551 5.701662540435791 8.785000801086426 6.55999231338501 L
|
||||||
|
2.945000410079956 9.654982566833496 C 2.502624750137329 9.889138221740723 2.082434415817261 9.999885559082031 1.705027341842651 9.999849319458008 Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
|
|
||||||
<style lang="scss" global>
|
<style lang="scss" global>
|
||||||
|
|
@ -26,22 +41,38 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 50%;
|
background: none;
|
||||||
|
fill: none;
|
||||||
|
stroke: none;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-top: -1px;
|
||||||
|
margin-left: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
&:not(.exposed) {
|
&:not(.exposed) {
|
||||||
background: none;
|
.outline {
|
||||||
border: 1px solid var(--data-type-color);
|
fill: var(--data-type-color);
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--color-6-lowergray);
|
.interior {
|
||||||
|
fill: var(--color-6-lowergray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.exposed {
|
&.exposed {
|
||||||
background: var(--data-type-color);
|
.interior {
|
||||||
|
fill: var(--data-type-color);
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border: 1px solid var(--color-f-white);
|
.outline {
|
||||||
|
fill: var(--color-f-white);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { IconName } from "@graphite/utility-functions/icons";
|
import { type IconName, type PopoverButtonStyle } from "@graphite/utility-functions/icons";
|
||||||
|
|
||||||
import FloatingMenu from "@graphite/components/layout/FloatingMenu.svelte";
|
import FloatingMenu from "@graphite/components/layout/FloatingMenu.svelte";
|
||||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||||
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
|
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
|
||||||
|
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
|
||||||
|
|
||||||
export let icon: IconName = "DropdownArrow";
|
export let style: PopoverButtonStyle = "DropdownArrow";
|
||||||
|
export let icon: IconName | undefined = undefined;
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
|
|
||||||
|
|
@ -20,8 +22,11 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LayoutRow class="popover-button">
|
<LayoutRow class="popover-button" classes={{ "has-icon": icon !== undefined }}>
|
||||||
<IconButton classes={{ open }} {disabled} action={() => onClick()} icon={icon || "DropdownArrow"} size={16} {tooltip} data-floating-menu-spawner />
|
<IconButton class="dropdown-icon" classes={{ open }} {disabled} action={() => onClick()} icon={style || "DropdownArrow"} size={16} {tooltip} data-floating-menu-spawner />
|
||||||
|
{#if icon !== undefined}
|
||||||
|
<IconLabel class="descriptive-icon" classes={{ open }} {disabled} {icon} {tooltip} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
<FloatingMenu {open} on:open={({ detail }) => (open = detail)} type="Popover" direction="Bottom">
|
<FloatingMenu {open} on:open={({ detail }) => (open = detail)} type="Popover" direction="Bottom">
|
||||||
<slot />
|
<slot />
|
||||||
|
|
@ -35,38 +40,40 @@
|
||||||
height: 24px;
|
height: 24px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
.floating-menu {
|
&.has-icon {
|
||||||
left: 50%;
|
width: 36px;
|
||||||
bottom: 0;
|
|
||||||
|
.dropdown-icon {
|
||||||
|
padding-left: calc(36px - 16px);
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button.icon-button {
|
.dropdown-icon {
|
||||||
width: 100%;
|
width: 16px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--color-1-nearblack);
|
|
||||||
fill: var(--color-e-nearwhite);
|
fill: var(--color-e-nearwhite);
|
||||||
|
|
||||||
&:hover,
|
&:hover:not(.disabled),
|
||||||
&.open {
|
&.open:not(.disabled) {
|
||||||
background: var(--color-5-dullgray);
|
background: var(--color-5-dullgray);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
background: var(--color-2-mildblack);
|
|
||||||
fill: var(--color-8-uppergray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor this and other complicated cases dealing with joined widget margins and border-radius by adding a single standard set of classes: joined-first, joined-inner, and joined-last
|
.descriptive-icon {
|
||||||
div[class*="-input"] + & {
|
width: 16px;
|
||||||
margin-left: 1px;
|
height: 16px;
|
||||||
|
margin: auto 0;
|
||||||
|
margin-left: calc(-16px - 16px);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-button {
|
.floating-menu {
|
||||||
border-radius: 0 2px 2px 0;
|
left: 50%;
|
||||||
}
|
bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,10 @@
|
||||||
export let label: string;
|
export let label: string;
|
||||||
export let icon: IconName | undefined = undefined;
|
export let icon: IconName | undefined = undefined;
|
||||||
export let emphasized = false;
|
export let emphasized = false;
|
||||||
export let noBackground = false;
|
export let flush = false;
|
||||||
export let minWidth = 0;
|
export let minWidth = 0;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
export let menuListChildren: MenuListEntry[][] | undefined = undefined;
|
export let menuListChildren: MenuListEntry[][] | undefined = undefined;
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
|
|
@ -57,8 +56,7 @@
|
||||||
class:open={self?.open}
|
class:open={self?.open}
|
||||||
class:emphasized
|
class:emphasized
|
||||||
class:disabled
|
class:disabled
|
||||||
class:no-background={noBackground}
|
class:flush
|
||||||
class:sharp-right-corners={sharpRightCorners}
|
|
||||||
style:min-width={minWidth > 0 ? `${minWidth}px` : ""}
|
style:min-width={minWidth > 0 ? `${minWidth}px` : ""}
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
data-emphasized={emphasized || undefined}
|
data-emphasized={emphasized || undefined}
|
||||||
|
|
@ -73,7 +71,7 @@
|
||||||
<IconLabel {icon} />
|
<IconLabel {icon} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if icon && label}
|
{#if icon && label}
|
||||||
<Separator type={noBackground ? "Unrelated" : "Related"} />
|
<Separator type={flush ? "Unrelated" : "Related"} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if label}
|
{#if label}
|
||||||
<TextLabel>{label}</TextLabel>
|
<TextLabel>{label}</TextLabel>
|
||||||
|
|
@ -140,7 +138,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.no-background {
|
&.flush {
|
||||||
background: none;
|
background: none;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@
|
||||||
max-width: calc(8 * var(--widget-height));
|
max-width: calc(8 * var(--widget-height));
|
||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
stroke: var(--color-7-middlegray);
|
stroke: var(--color-5-dullgray);
|
||||||
stroke-width: 0.005;
|
stroke-width: 0.005;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
@ -251,7 +251,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.handle-line {
|
.handle-line {
|
||||||
stroke: var(--color-7-middlegray);
|
stroke: var(--color-5-dullgray);
|
||||||
stroke-width: 0.005;
|
stroke-width: 0.005;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
export let interactive = true;
|
export let interactive = true;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
|
|
||||||
let activeEntry = makeActiveEntry();
|
let activeEntry = makeActiveEntry();
|
||||||
let activeEntrySkipWatcher = false;
|
let activeEntrySkipWatcher = false;
|
||||||
|
|
@ -64,7 +63,7 @@
|
||||||
<LayoutRow class="dropdown-input" bind:this={self} data-dropdown-input>
|
<LayoutRow class="dropdown-input" bind:this={self} data-dropdown-input>
|
||||||
<LayoutRow
|
<LayoutRow
|
||||||
class="dropdown-box"
|
class="dropdown-box"
|
||||||
classes={{ disabled, open, "sharp-right-corners": sharpRightCorners }}
|
classes={{ disabled, open }}
|
||||||
styles={{ "min-width": `${minWidth}px` }}
|
styles={{ "min-width": `${minWidth}px` }}
|
||||||
{tooltip}
|
{tooltip}
|
||||||
on:click={() => !disabled && (open = true)}
|
on:click={() => !disabled && (open = true)}
|
||||||
|
|
@ -128,7 +127,7 @@
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&.open {
|
&.open {
|
||||||
background: var(--color-5-dullgray);
|
background: var(--color-4-dimgray);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let textarea = false;
|
export let textarea = false;
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
export let placeholder: string | undefined = undefined;
|
export let placeholder: string | undefined = undefined;
|
||||||
export let hideContextMenu = false;
|
export let hideContextMenu = false;
|
||||||
|
|
||||||
|
|
@ -69,7 +68,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- This is a base component, extended by others like NumberInput and TextInput. It should not be used directly. -->
|
<!-- This is a base component, extended by others like NumberInput and TextInput. It should not be used directly. -->
|
||||||
<LayoutRow class={`field-input ${className}`} classes={{ disabled, "sharp-right-corners": sharpRightCorners, ...classes }} style={styleName} {styles} {tooltip}>
|
<LayoutRow class={`field-input ${className}`} classes={{ disabled, ...classes }} style={styleName} {styles} {tooltip}>
|
||||||
{#if !textarea}
|
{#if !textarea}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -154,14 +153,14 @@
|
||||||
caret-color: var(--color-e-nearwhite);
|
caret-color: var(--color-e-nearwhite);
|
||||||
|
|
||||||
&::selection {
|
&::selection {
|
||||||
background-color: var(--color-5-dullgray);
|
background-color: var(--color-4-dimgray);
|
||||||
|
|
||||||
// Target only Safari
|
// Target only Safari
|
||||||
@supports (background: -webkit-named-image(i)) {
|
@supports (background: -webkit-named-image(i)) {
|
||||||
& {
|
& {
|
||||||
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
|
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
|
||||||
// https://stackoverflow.com/a/71753552/775283
|
// https://stackoverflow.com/a/71753552/775283
|
||||||
background-color: rgba(var(--color-5-dullgray-rgb), calc(254 / 255));
|
background-color: rgba(var(--color-4-dimgray-rgb), calc(254 / 255));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@
|
||||||
export let isStyle = false;
|
export let isStyle = false;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
|
|
||||||
let open = false;
|
let open = false;
|
||||||
let entries: MenuListEntry[] = [];
|
let entries: MenuListEntry[] = [];
|
||||||
|
|
@ -107,7 +106,7 @@
|
||||||
<LayoutRow class="font-input">
|
<LayoutRow class="font-input">
|
||||||
<LayoutRow
|
<LayoutRow
|
||||||
class="dropdown-box"
|
class="dropdown-box"
|
||||||
classes={{ disabled, "sharp-right-corners": sharpRightCorners }}
|
classes={{ disabled }}
|
||||||
styles={{ "min-width": `${minWidth}px` }}
|
styles={{ "min-width": `${minWidth}px` }}
|
||||||
{tooltip}
|
{tooltip}
|
||||||
tabindex={disabled ? -1 : 0}
|
tabindex={disabled ? -1 : 0}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@
|
||||||
|
|
||||||
// Styling
|
// Styling
|
||||||
export let minWidth = 0;
|
export let minWidth = 0;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
export let incrementCallbackIncrease: (() => void) | undefined = undefined;
|
export let incrementCallbackIncrease: (() => void) | undefined = undefined;
|
||||||
|
|
@ -581,7 +580,6 @@
|
||||||
{label}
|
{label}
|
||||||
{disabled}
|
{disabled}
|
||||||
{tooltip}
|
{tooltip}
|
||||||
{sharpRightCorners}
|
|
||||||
{styles}
|
{styles}
|
||||||
hideContextMenu={true}
|
hideContextMenu={true}
|
||||||
spellcheck={false}
|
spellcheck={false}
|
||||||
|
|
@ -658,7 +656,7 @@
|
||||||
background: none;
|
background: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--color-5-dullgray);
|
background: var(--color-4-dimgray);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.right {
|
&.right {
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import type { IconName } from "@graphite/utility-functions/icons";
|
|
||||||
|
|
||||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
|
||||||
import CheckboxInput from "@graphite/components/widgets/inputs/CheckboxInput.svelte";
|
|
||||||
|
|
||||||
export let checked: boolean;
|
|
||||||
export let disabled = false;
|
|
||||||
export let icon: IconName = "Checkmark";
|
|
||||||
export let tooltip: string | undefined = undefined;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<LayoutRow class="optional-input" classes={{ disabled }}>
|
|
||||||
<CheckboxInput {checked} on:checked {disabled} {icon} {tooltip} />
|
|
||||||
</LayoutRow>
|
|
||||||
|
|
||||||
<style lang="scss" global>
|
|
||||||
.optional-input {
|
|
||||||
flex-grow: 0;
|
|
||||||
|
|
||||||
.checkbox-input label {
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border: 1px solid var(--color-5-dullgray);
|
|
||||||
border-radius: 2px 0 0 2px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled .checkbox-input label {
|
|
||||||
border: 1px solid var(--color-4-dimgray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
export let entries: RadioEntries;
|
export let entries: RadioEntries;
|
||||||
export let selectedIndex: number | undefined = undefined;
|
export let selectedIndex: number | undefined = undefined;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
|
|
||||||
function handleEntryClick(radioEntryData: RadioEntryData) {
|
function handleEntryClick(radioEntryData: RadioEntryData) {
|
||||||
const index = entries.indexOf(radioEntryData);
|
const index = entries.indexOf(radioEntryData);
|
||||||
|
|
@ -28,7 +27,6 @@
|
||||||
class:active={index === selectedIndex}
|
class:active={index === selectedIndex}
|
||||||
class:mixed={selectedIndex === undefined}
|
class:mixed={selectedIndex === undefined}
|
||||||
class:disabled
|
class:disabled
|
||||||
class:sharp-right-corners={index === entries.length - 1 && sharpRightCorners}
|
|
||||||
on:click={() => handleEntryClick(entry)}
|
on:click={() => handleEntryClick(entry)}
|
||||||
title={entry.tooltip}
|
title={entry.tooltip}
|
||||||
tabindex={index === selectedIndex ? -1 : 0}
|
tabindex={index === selectedIndex ? -1 : 0}
|
||||||
|
|
@ -38,7 +36,7 @@
|
||||||
<IconLabel icon={entry.icon} />
|
<IconLabel icon={entry.icon} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if entry.label}
|
{#if entry.label}
|
||||||
<TextLabel>{entry.label}</TextLabel>
|
<TextLabel italic={selectedIndex === undefined}>{entry.label}</TextLabel>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke-width: 1px;
|
stroke-width: 1px;
|
||||||
stroke: var(--color-7-middlegray);
|
stroke: var(--color-6-lowergray);
|
||||||
}
|
}
|
||||||
|
|
||||||
text {
|
text {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
// Styling
|
// Styling
|
||||||
export let centered = false;
|
export let centered = false;
|
||||||
export let minWidth = 0;
|
export let minWidth = 0;
|
||||||
export let sharpRightCorners = false;
|
|
||||||
|
|
||||||
let self: FieldInput | undefined;
|
let self: FieldInput | undefined;
|
||||||
let editing = false;
|
let editing = false;
|
||||||
|
|
@ -67,7 +66,6 @@
|
||||||
{disabled}
|
{disabled}
|
||||||
{tooltip}
|
{tooltip}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{sharpRightCorners}
|
|
||||||
bind:this={self}
|
bind:this={self}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={`separator ${direction.toLowerCase()} ${type.toLowerCase()}`}>
|
<div class={`separator ${direction.toLowerCase()} ${type.toLowerCase()}`}>
|
||||||
{#if ["Section", "List"].includes(type)}
|
{#if type === "Section"}
|
||||||
<div />
|
<div />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -21,27 +21,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.unrelated {
|
&.unrelated {
|
||||||
height: 8px;
|
height: 16px;
|
||||||
}
|
|
||||||
|
|
||||||
&.section,
|
|
||||||
&.list {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
div {
|
|
||||||
height: 1px;
|
|
||||||
width: calc(100% - 8px);
|
|
||||||
margin: 0 4px;
|
|
||||||
background: var(--color-7-middlegray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.section {
|
&.section {
|
||||||
margin: 8px 0;
|
// If changing this, update `--separator-height` in `Document.svelte`
|
||||||
}
|
margin: 12px 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&.list {
|
div {
|
||||||
margin: 4px 0;
|
margin: 0 4px;
|
||||||
|
height: 1px;
|
||||||
|
width: calc(100% - 8px);
|
||||||
|
background: var(--color-5-dullgray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,27 +46,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.unrelated {
|
&.unrelated {
|
||||||
width: 8px;
|
width: 16px;
|
||||||
}
|
|
||||||
|
|
||||||
&.section,
|
|
||||||
&.list {
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
div {
|
|
||||||
height: calc(100% - 8px);
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 0;
|
|
||||||
background: var(--color-7-middlegray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.section {
|
&.section {
|
||||||
margin: 0 8px;
|
margin: 0 12px;
|
||||||
}
|
height: 100%;
|
||||||
|
|
||||||
&.list {
|
div {
|
||||||
margin: 0 4px;
|
margin: 4px 0;
|
||||||
|
height: calc(100% - 8px);
|
||||||
|
width: 1px;
|
||||||
|
background: var(--color-5-dullgray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,11 +248,11 @@
|
||||||
|
|
||||||
.floating-menu-content .row:hover > & {
|
.floating-menu-content .row:hover > & {
|
||||||
.input-key {
|
.input-key {
|
||||||
border-color: var(--color-7-middlegray);
|
border-color: var(--color-8-uppergray);
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-mouse .dim {
|
.input-mouse .dim {
|
||||||
fill: var(--color-7-middlegray);
|
fill: var(--color-8-uppergray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,8 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.separator.section {
|
.separator.section {
|
||||||
margin: 0;
|
// Width of section separator (12px) minus the margin of the surrounding user input labels (8px)
|
||||||
|
margin: 0 calc(12px - 8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.plus,
|
.plus,
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@
|
||||||
<WindowButtonsMac {maximized} />
|
<WindowButtonsMac {maximized} />
|
||||||
{:else}
|
{:else}
|
||||||
{#each entries as entry}
|
{#each entries as entry}
|
||||||
<TextButton label={entry.label} icon={entry.icon} menuListChildren={entry.children} action={entry.action} noBackground={true} />
|
<TextButton label={entry.label} icon={entry.icon} menuListChildren={entry.children} action={entry.action} flush={true} />
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
import Layers from "@graphite/components/panels/Layers.svelte";
|
import Layers from "@graphite/components/panels/Layers.svelte";
|
||||||
import Properties from "@graphite/components/panels/Properties.svelte";
|
import Properties from "@graphite/components/panels/Properties.svelte";
|
||||||
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
|
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
|
||||||
import PopoverButton from "@graphite/components/widgets/buttons/PopoverButton.svelte";
|
|
||||||
import TextButton from "@graphite/components/widgets/buttons/TextButton.svelte";
|
import TextButton from "@graphite/components/widgets/buttons/TextButton.svelte";
|
||||||
|
|
||||||
const PANEL_COMPONENTS = {
|
const PANEL_COMPONENTS = {
|
||||||
|
|
@ -102,10 +101,10 @@
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
{/each}
|
{/each}
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
<PopoverButton icon="VerticalEllipsis">
|
<!-- <PopoverButton style="VerticalEllipsis">
|
||||||
<TextLabel bold={true}>Panel Options</TextLabel>
|
<TextLabel bold={true}>Panel Options</TextLabel>
|
||||||
<TextLabel multiline={true}>Coming soon</TextLabel>
|
<TextLabel multiline={true}>Coming soon</TextLabel>
|
||||||
</PopoverButton>
|
</PopoverButton> -->
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
<LayoutCol class="panel-body">
|
<LayoutCol class="panel-body">
|
||||||
{#if panelType}
|
{#if panelType}
|
||||||
|
|
@ -120,7 +119,7 @@
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<TextButton label="New Document" icon="File" noBackground={true} action={() => editor.instance.newDocumentDialog()} />
|
<TextButton label="New Document" icon="File" flush={true} action={() => editor.instance.newDocumentDialog()} />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<UserInputLabel keysWithLabelsGroups={[[...platformModifiers(true), { key: "KeyN", label: "N" }]]} />
|
<UserInputLabel keysWithLabelsGroups={[[...platformModifiers(true), { key: "KeyN", label: "N" }]]} />
|
||||||
|
|
@ -128,7 +127,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<TextButton label="Open Document" icon="Folder" noBackground={true} action={() => editor.instance.openDocument()} />
|
<TextButton label="Open Document" icon="Folder" flush={true} action={() => editor.instance.openDocument()} />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<UserInputLabel keysWithLabelsGroups={[[...platformModifiers(false), { key: "KeyO", label: "O" }]]} />
|
<UserInputLabel keysWithLabelsGroups={[[...platformModifiers(false), { key: "KeyO", label: "O" }]]} />
|
||||||
|
|
@ -136,7 +135,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<TextButton label="Open Demo Artwork" icon="Image" noBackground={true} action={() => editor.instance.demoArtworkDialog()} />
|
<TextButton label="Open Demo Artwork" icon="Image" flush={true} action={() => editor.instance.demoArtworkDialog()} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -252,9 +251,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover-button {
|
// .popover-button {
|
||||||
margin: 2px 4px;
|
// margin: 2px 4px;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-body {
|
.panel-body {
|
||||||
|
|
@ -262,6 +261,10 @@
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.empty-panel {
|
.empty-panel {
|
||||||
background: var(--color-2-mildblack);
|
background: var(--color-2-mildblack);
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import {
|
||||||
UpdateToolOptionsLayout,
|
UpdateToolOptionsLayout,
|
||||||
UpdateToolShelfLayout,
|
UpdateToolShelfLayout,
|
||||||
UpdateWorkingColorsLayout,
|
UpdateWorkingColorsLayout,
|
||||||
UpdateGraphViewOverlayButtonLayout,
|
|
||||||
UpdateNodeGraphBarLayout,
|
UpdateNodeGraphBarLayout,
|
||||||
TriggerGraphViewOverlay,
|
TriggerGraphViewOverlay,
|
||||||
} from "@graphite/wasm-communication/messages";
|
} from "@graphite/wasm-communication/messages";
|
||||||
|
|
@ -24,7 +23,6 @@ export function createDocumentState(editor: Editor) {
|
||||||
toolOptionsLayout: defaultWidgetLayout(),
|
toolOptionsLayout: defaultWidgetLayout(),
|
||||||
documentBarLayout: defaultWidgetLayout(),
|
documentBarLayout: defaultWidgetLayout(),
|
||||||
toolShelfLayout: defaultWidgetLayout(),
|
toolShelfLayout: defaultWidgetLayout(),
|
||||||
graphViewOverlayButtonLayout: defaultWidgetLayout(),
|
|
||||||
workingColorsLayout: defaultWidgetLayout(),
|
workingColorsLayout: defaultWidgetLayout(),
|
||||||
nodeGraphBarLayout: defaultWidgetLayout(),
|
nodeGraphBarLayout: defaultWidgetLayout(),
|
||||||
// Graph view overlay
|
// Graph view overlay
|
||||||
|
|
@ -69,14 +67,6 @@ export function createDocumentState(editor: Editor) {
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateGraphViewOverlayButtonLayout, async (updateGraphViewOverlayButtonLayout) => {
|
|
||||||
await tick();
|
|
||||||
|
|
||||||
update((state) => {
|
|
||||||
patchWidgetLayout(state.graphViewOverlayButtonLayout, updateGraphViewOverlayButtonLayout);
|
|
||||||
return state;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateWorkingColorsLayout, async (updateWorkingColorsLayout) => {
|
editor.subscriptions.subscribeJsMessage(UpdateWorkingColorsLayout, async (updateWorkingColorsLayout) => {
|
||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,7 @@ export const ICON_SVG_STRINGS = Object.fromEntries(Object.entries(ICONS).map(([n
|
||||||
|
|
||||||
export type IconName = keyof typeof ICONS;
|
export type IconName = keyof typeof ICONS;
|
||||||
export type IconSize = undefined | 12 | 16 | 24 | 32;
|
export type IconSize = undefined | 12 | 16 | 24 | 32;
|
||||||
|
export type PopoverButtonStyle = "DropdownArrow" | "VerticalEllipsis";
|
||||||
|
|
||||||
// The following helper type declarations allow us to avoid manually maintaining the `IconName` type declaration as a string union paralleling the keys of the
|
// The following helper type declarations allow us to avoid manually maintaining the `IconName` type declaration as a string union paralleling the keys of the
|
||||||
// icon definitions. It lets TypeScript do that for us. Our goal is to define the big key-value pair of icons by constraining its values, but inferring its keys.
|
// icon definitions. It lets TypeScript do that for us. Our goal is to define the big key-value pair of icons by constraining its values, but inferring its keys.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import { Transform, Type, plainToClass } from "class-transformer";
|
import { Transform, Type, plainToClass } from "class-transformer";
|
||||||
|
|
||||||
import { type IconName, type IconSize } from "@graphite/utility-functions/icons";
|
import { type PopoverButtonStyle, type IconName, type IconSize } from "@graphite/utility-functions/icons";
|
||||||
import { type WasmEditorInstance, type WasmRawInstance } from "@graphite/wasm-communication/editor";
|
import { type WasmEditorInstance, type WasmRawInstance } from "@graphite/wasm-communication/editor";
|
||||||
|
|
||||||
import type MenuList from "@graphite/components/floating-menus/MenuList.svelte";
|
import type MenuList from "@graphite/components/floating-menus/MenuList.svelte";
|
||||||
|
|
@ -918,18 +918,9 @@ export class NumberInput extends WidgetProps {
|
||||||
minWidth!: number;
|
minWidth!: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OptionalInput extends WidgetProps {
|
|
||||||
checked!: boolean;
|
|
||||||
|
|
||||||
disabled!: boolean;
|
|
||||||
|
|
||||||
icon!: IconName;
|
|
||||||
|
|
||||||
@Transform(({ value }: { value: string }) => value || undefined)
|
|
||||||
tooltip!: string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PopoverButton extends WidgetProps {
|
export class PopoverButton extends WidgetProps {
|
||||||
|
style!: PopoverButtonStyle | undefined;
|
||||||
|
|
||||||
icon!: IconName | undefined;
|
icon!: IconName | undefined;
|
||||||
|
|
||||||
disabled!: boolean;
|
disabled!: boolean;
|
||||||
|
|
@ -965,7 +956,7 @@ export class RadioInput extends WidgetProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SeparatorDirection = "Horizontal" | "Vertical";
|
export type SeparatorDirection = "Horizontal" | "Vertical";
|
||||||
export type SeparatorType = "Related" | "Unrelated" | "Section" | "List";
|
export type SeparatorType = "Related" | "Unrelated" | "Section";
|
||||||
|
|
||||||
export class Separator extends WidgetProps {
|
export class Separator extends WidgetProps {
|
||||||
direction!: SeparatorDirection;
|
direction!: SeparatorDirection;
|
||||||
|
|
@ -973,7 +964,7 @@ export class Separator extends WidgetProps {
|
||||||
type!: SeparatorType;
|
type!: SeparatorType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkingColorsButton extends WidgetProps {
|
export class WorkingColorsInput extends WidgetProps {
|
||||||
@Type(() => Color)
|
@Type(() => Color)
|
||||||
primary!: Color;
|
primary!: Color;
|
||||||
|
|
||||||
|
|
@ -1008,7 +999,7 @@ export class TextButton extends WidgetProps {
|
||||||
|
|
||||||
emphasized!: boolean;
|
emphasized!: boolean;
|
||||||
|
|
||||||
noBackground!: boolean;
|
flush!: boolean;
|
||||||
|
|
||||||
minWidth!: number;
|
minWidth!: number;
|
||||||
|
|
||||||
|
|
@ -1029,7 +1020,7 @@ export type TextButtonWidget = {
|
||||||
label: string;
|
label: string;
|
||||||
icon?: IconName;
|
icon?: IconName;
|
||||||
emphasized?: boolean;
|
emphasized?: boolean;
|
||||||
noBackground?: boolean;
|
flush?: boolean;
|
||||||
minWidth?: number;
|
minWidth?: number;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
|
|
@ -1103,13 +1094,12 @@ const widgetSubTypes = [
|
||||||
{ value: IconLabel, name: "IconLabel" },
|
{ value: IconLabel, name: "IconLabel" },
|
||||||
{ value: ImageLabel, name: "ImageLabel" },
|
{ value: ImageLabel, name: "ImageLabel" },
|
||||||
{ value: NumberInput, name: "NumberInput" },
|
{ value: NumberInput, name: "NumberInput" },
|
||||||
{ value: OptionalInput, name: "OptionalInput" },
|
|
||||||
{ value: ParameterExposeButton, name: "ParameterExposeButton" },
|
{ value: ParameterExposeButton, name: "ParameterExposeButton" },
|
||||||
{ value: PivotInput, name: "PivotInput" },
|
{ value: PivotInput, name: "PivotInput" },
|
||||||
{ value: PopoverButton, name: "PopoverButton" },
|
{ value: PopoverButton, name: "PopoverButton" },
|
||||||
{ value: RadioInput, name: "RadioInput" },
|
{ value: RadioInput, name: "RadioInput" },
|
||||||
{ value: Separator, name: "Separator" },
|
{ value: Separator, name: "Separator" },
|
||||||
{ value: WorkingColorsButton, name: "WorkingColorsButton" },
|
{ value: WorkingColorsInput, name: "WorkingColorsInput" },
|
||||||
{ value: TextAreaInput, name: "TextAreaInput" },
|
{ value: TextAreaInput, name: "TextAreaInput" },
|
||||||
{ value: TextButton, name: "TextButton" },
|
{ value: TextButton, name: "TextButton" },
|
||||||
{ value: TextInput, name: "TextInput" },
|
{ value: TextInput, name: "TextInput" },
|
||||||
|
|
@ -1293,8 +1283,6 @@ export class UpdateDocumentBarLayout extends WidgetDiffUpdate {}
|
||||||
|
|
||||||
export class UpdateDocumentModeLayout extends WidgetDiffUpdate {}
|
export class UpdateDocumentModeLayout extends WidgetDiffUpdate {}
|
||||||
|
|
||||||
export class UpdateGraphViewOverlayButtonLayout extends WidgetDiffUpdate {}
|
|
||||||
|
|
||||||
export class UpdateLayersPanelOptionsLayout extends WidgetDiffUpdate {}
|
export class UpdateLayersPanelOptionsLayout extends WidgetDiffUpdate {}
|
||||||
|
|
||||||
// Extends JsMessage instead of WidgetDiffUpdate because the menu bar isn't diffed
|
// Extends JsMessage instead of WidgetDiffUpdate because the menu bar isn't diffed
|
||||||
|
|
@ -1384,7 +1372,6 @@ export const messageMakers: Record<string, MessageMaker> = {
|
||||||
UpdateDocumentRulers,
|
UpdateDocumentRulers,
|
||||||
UpdateDocumentScrollbars,
|
UpdateDocumentScrollbars,
|
||||||
UpdateEyedropperSamplingState,
|
UpdateEyedropperSamplingState,
|
||||||
UpdateGraphViewOverlayButtonLayout,
|
|
||||||
UpdateImageData,
|
UpdateImageData,
|
||||||
UpdateInputHints,
|
UpdateInputHints,
|
||||||
UpdateLayersPanelOptionsLayout,
|
UpdateLayersPanelOptionsLayout,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ Before taking the time to read the coming chapters, let's build some context by
|
||||||
|
|
||||||
You can follow along with this starter project either by watching the tutorial video or referencing the step-by-step breakdown.
|
You can follow along with this starter project either by watching the tutorial video or referencing the step-by-step breakdown.
|
||||||
|
|
||||||
***The tutorial isn't ready quite yet, sorry! Please check back very soon. It should be posted by mid-December.***
|
***The tutorial isn't ready quite yet, sorry! Please check back very soon. It should be posted by late December.***
|
||||||
|
|
||||||
<!-- TODO -->
|
<!-- TODO -->
|
||||||
<!-- - Video tutorial -->
|
<!-- - Video tutorial -->
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ title = "Features and limitations"
|
||||||
order = 1
|
order = 1
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Please keep in mind that Graphite is alpha software, meaning it is actively changing and improving. Remember to save you work frequently because crashes are not unheard of.
|
Please keep in mind that Graphite is alpha software, meaning it is actively changing and improving. Remember to save your work frequently because crashes are not unheard of.
|
||||||
|
|
||||||
## Current capabilities
|
## Current capabilities
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue