Refactor the WidgetLayout struct to remove SubLayout and avoid sending LayoutTarget to frontend

This commit is contained in:
Keavon Chambers
2025-12-04 02:39:23 -08:00
parent 4581689d9c
commit 3c4ad8b720
50 changed files with 207 additions and 247 deletions

View File

@@ -547,9 +547,9 @@ mod test {
for response in responses {
// Check for the existence of the file format incompatibility warning dialog after opening the test file
if let FrontendMessage::UpdateDialogColumn1 { layout_target: _, diff } = response {
if let DiffUpdate::SubLayout(sub_layout) = &diff[0].new_value {
if let LayoutGroup::Row { widgets } = &sub_layout[0] {
if let FrontendMessage::UpdateDialogColumn1 { diff } = response {
if let DiffUpdate::WidgetLayout(sub_layout) = &diff[0].new_value {
if let LayoutGroup::Row { widgets } = &sub_layout.0[0] {
if let Widget::TextLabel(TextLabel { value, .. }) = &widgets[0].widget {
print_problem_to_terminal_on_failure(value);
}

View File

@@ -76,7 +76,7 @@ impl DialogLayoutHolder for ExportDialogMessageHandler {
TextButton::new("Cancel").on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}
@@ -160,7 +160,7 @@ impl LayoutHolder for ExportDialogMessageHandler {
.widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![
Layout::WidgetLayout(WidgetLayout(vec![
LayoutGroup::Row { widgets: export_type },
LayoutGroup::Row { widgets: resolution },
LayoutGroup::Row { widgets: export_area },

View File

@@ -66,7 +66,7 @@ impl DialogLayoutHolder for NewDocumentDialogMessageHandler {
TextButton::new("Cancel").on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}
@@ -117,7 +117,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
.widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![
Layout::WidgetLayout(WidgetLayout(vec![
LayoutGroup::Row { widgets: name },
LayoutGroup::Row { widgets: infinite },
LayoutGroup::Row { widgets: scale },

View File

@@ -224,7 +224,7 @@ impl PreferencesDialogMessageHandler {
.widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![
Layout::WidgetLayout(WidgetLayout(vec![
LayoutGroup::Row { widgets: navigation_header },
LayoutGroup::Row { widgets: zoom_rate_label },
LayoutGroup::Row { widgets: zoom_rate },
@@ -272,7 +272,7 @@ impl PreferencesDialogMessageHandler {
TextButton::new("Reset to Defaults").on_update(|_| PreferencesMessage::ResetToDefaults.into()).widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
fn send_layout_buttons(&self, responses: &mut VecDeque<Message>, layout_target: LayoutTarget) {

View File

@@ -15,7 +15,7 @@ impl DialogLayoutHolder for AboutGraphiteDialog {
fn layout_buttons(&self) -> Layout {
let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance()];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
fn layout_column_2(&self) -> Layout {
@@ -51,13 +51,13 @@ impl DialogLayoutHolder for AboutGraphiteDialog {
.widget_instance(),
);
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Column { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Column { widgets }]))
}
}
impl LayoutHolder for AboutGraphiteDialog {
fn layout(&self) -> Layout {
Layout::WidgetLayout(WidgetLayout::new(vec![
Layout::WidgetLayout(WidgetLayout(vec![
LayoutGroup::Row {
widgets: vec![TextLabel::new("About this release").bold(true).widget_instance()],
},

View File

@@ -24,7 +24,7 @@ impl DialogLayoutHolder for CloseAllDocumentsDialog {
TextButton::new("Cancel").on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}
@@ -32,7 +32,7 @@ impl LayoutHolder for CloseAllDocumentsDialog {
fn layout(&self) -> Layout {
let unsaved_list = "".to_string() + &self.unsaved_document_names.join("\n");
Layout::WidgetLayout(WidgetLayout::new(vec![
Layout::WidgetLayout(WidgetLayout(vec![
LayoutGroup::Row {
widgets: vec![TextLabel::new("Save documents before closing them?").bold(true).multiline(true).widget_instance()],
},

View File

@@ -35,7 +35,7 @@ impl DialogLayoutHolder for CloseDocumentDialog {
TextButton::new("Cancel").on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}
@@ -51,7 +51,7 @@ impl LayoutHolder for CloseDocumentDialog {
let break_lines = if self.document_name.len() > max_one_line_length { '\n' } else { ' ' };
Layout::WidgetLayout(WidgetLayout::new(vec![
Layout::WidgetLayout(WidgetLayout(vec![
LayoutGroup::Row {
widgets: vec![TextLabel::new("Save document before closing it?").bold(true).widget_instance()],
},

View File

@@ -13,7 +13,7 @@ impl DialogLayoutHolder for ComingSoonDialog {
fn layout_buttons(&self) -> Layout {
let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance()];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}
@@ -43,6 +43,6 @@ impl LayoutHolder for ComingSoonDialog {
rows.push(LayoutGroup::Row { widgets: row3 });
}
Layout::WidgetLayout(WidgetLayout::new(rows))
Layout::WidgetLayout(WidgetLayout(rows))
}
}

View File

@@ -22,7 +22,7 @@ impl DialogLayoutHolder for DemoArtworkDialog {
fn layout_buttons(&self) -> Layout {
let widgets = vec![TextButton::new("Close").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance()];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}
@@ -59,6 +59,6 @@ impl LayoutHolder for DemoArtworkDialog {
.collect();
let _ = rows_of_images_with_buttons.pop();
Layout::WidgetLayout(WidgetLayout::new(rows_of_images_with_buttons))
Layout::WidgetLayout(WidgetLayout(rows_of_images_with_buttons))
}
}

View File

@@ -14,13 +14,13 @@ impl DialogLayoutHolder for ErrorDialog {
fn layout_buttons(&self) -> Layout {
let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance()];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}
impl LayoutHolder for ErrorDialog {
fn layout(&self) -> Layout {
Layout::WidgetLayout(WidgetLayout::new(vec![
Layout::WidgetLayout(WidgetLayout(vec![
LayoutGroup::Row {
widgets: vec![TextLabel::new(&self.title).bold(true).widget_instance()],
},

View File

@@ -12,7 +12,7 @@ impl DialogLayoutHolder for LicensesDialog {
fn layout_buttons(&self) -> Layout {
let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance()];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
fn layout_column_2(&self) -> Layout {
@@ -43,7 +43,7 @@ impl DialogLayoutHolder for LicensesDialog {
.map(|&(icon, label, message_factory)| TextButton::new(label).icon(Some((icon).into())).flush(true).on_update(move |_| message_factory()).widget_instance())
.collect();
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Column { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Column { widgets }]))
}
}
@@ -63,7 +63,7 @@ impl LayoutHolder for LicensesDialog {
);
let description = description.trim();
Layout::WidgetLayout(WidgetLayout::new(vec![
Layout::WidgetLayout(WidgetLayout(vec![
LayoutGroup::Row {
widgets: vec![TextLabel::new("Graphite is free, open source software").bold(true).widget_instance()],
},

View File

@@ -12,7 +12,7 @@ impl DialogLayoutHolder for LicensesThirdPartyDialog {
fn layout_buttons(&self) -> Layout {
let widgets = vec![TextButton::new("OK").emphasized(true).on_update(|_| FrontendMessage::DisplayDialogDismiss.into()).widget_instance()];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}
@@ -31,7 +31,7 @@ impl LayoutHolder for LicensesThirdPartyDialog {
// Two characters (one before, one after) the sequence of underscore characters, plus one additional column to provide a space between the text and the scrollbar
let non_wrapping_column_width = license_text.split('\n').map(|line| line.chars().filter(|&c| c == '_').count()).max().unwrap_or(0) + 2 + 1;
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row {
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row {
widgets: vec![
TextLabel::new(license_text)
.monospace(true)

View File

@@ -170,8 +170,6 @@ pub enum FrontendMessage {
open: bool,
},
UpdateDataPanelLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateImportReorderIndex {
@@ -191,18 +189,12 @@ pub enum FrontendMessage {
has_left_input_wire: HashMap<NodeId, bool>,
},
UpdateDialogButtons {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateDialogColumn1 {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateDialogColumn2 {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateDocumentArtwork {
@@ -212,8 +204,6 @@ pub enum FrontendMessage {
image_data: Vec<(u64, Image<Color>)>,
},
UpdateDocumentBarLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateDocumentLayerDetails {
@@ -228,8 +218,6 @@ pub enum FrontendMessage {
data_buffer: JsRawBuffer,
},
UpdateDocumentModeLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateDocumentRulers {
@@ -257,23 +245,15 @@ pub enum FrontendMessage {
percentage: f64,
},
UpdateLayersPanelControlBarLeftLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateLayersPanelControlBarRightLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateLayersPanelBottomBarLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateMenuBarLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateMouseCursor {
@@ -293,8 +273,6 @@ pub enum FrontendMessage {
},
ClearAllNodeGraphWires,
UpdateNodeGraphControlBarLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateNodeGraphSelection {
@@ -312,18 +290,12 @@ pub enum FrontendMessage {
open_documents: Vec<OpenDocument>,
},
UpdatePropertiesPanelLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateToolOptionsLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateToolShelfLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateWirePathInProgress {
@@ -331,18 +303,12 @@ pub enum FrontendMessage {
wire_path: Option<WirePath>,
},
UpdateWelcomeScreenButtonsLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateStatusBarHintsLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdateWorkingColorsLayout {
#[serde(rename = "layoutTarget")]
layout_target: LayoutTarget,
diff: Vec<WidgetDiff>,
},
UpdatePlatform {

View File

@@ -62,7 +62,7 @@ impl MessageHandler<LayoutMessage, LayoutMessageContext<'_>> for LayoutMessageHa
impl LayoutMessageHandler {
/// Get the widget path for the widget with the specified id
fn get_widget_path(widget_layout: &WidgetLayout, widget_id: WidgetId) -> Option<(&WidgetInstance, Vec<usize>)> {
let mut stack = widget_layout.layout.iter().enumerate().map(|(index, val)| (vec![index], val)).collect::<Vec<_>>();
let mut stack = widget_layout.0.iter().enumerate().map(|(index, val)| (vec![index], val)).collect::<Vec<_>>();
while let Some((mut widget_path, layout_group)) = stack.pop() {
match layout_group {
// Check if any of the widgets in the current column or row have the correct id
@@ -75,13 +75,20 @@ impl LayoutMessageHandler {
}
if let Widget::PopoverButton(popover) = &widget.widget {
stack.extend(popover.popover_layout.iter().enumerate().map(|(child, val)| ([widget_path.as_slice(), &[index, child]].concat(), val)));
stack.extend(
popover
.popover_layout
.0
.iter()
.enumerate()
.map(|(child, val)| ([widget_path.as_slice(), &[index, child]].concat(), val)),
);
}
}
}
// A section contains more LayoutGroups which we add to the stack.
LayoutGroup::Section { layout, .. } => {
stack.extend(layout.iter().enumerate().map(|(index, val)| ([widget_path.as_slice(), &[index]].concat(), val)));
stack.extend(layout.0.iter().enumerate().map(|(index, val)| ([widget_path.as_slice(), &[index]].concat(), val)));
}
LayoutGroup::Table { rows, .. } => {
for (row_index, row) in rows.iter().enumerate() {
@@ -97,6 +104,7 @@ impl LayoutMessageHandler {
stack.extend(
popover
.popover_layout
.0
.iter()
.enumerate()
.map(|(child, val)| ([widget_path.as_slice(), &[row_index, cell_index, child]].concat(), val)),
@@ -489,7 +497,7 @@ impl LayoutMessageHandler {
if layout_target == LayoutTarget::MenuBar {
widget_diffs = vec![WidgetDiff {
widget_path: Vec::new(),
new_value: DiffUpdate::SubLayout(current.layout.clone()),
new_value: DiffUpdate::WidgetLayout(current.layout.clone()),
}];
}
@@ -503,23 +511,23 @@ impl LayoutMessageHandler {
diff.iter_mut().for_each(|diff| diff.new_value.apply_keyboard_shortcut(action_input_mapping));
let message = match layout_target {
LayoutTarget::DataPanel => FrontendMessage::UpdateDataPanelLayout { layout_target, diff },
LayoutTarget::DialogButtons => FrontendMessage::UpdateDialogButtons { layout_target, diff },
LayoutTarget::DialogColumn1 => FrontendMessage::UpdateDialogColumn1 { layout_target, diff },
LayoutTarget::DialogColumn2 => FrontendMessage::UpdateDialogColumn2 { layout_target, diff },
LayoutTarget::DocumentBar => FrontendMessage::UpdateDocumentBarLayout { layout_target, diff },
LayoutTarget::DocumentMode => FrontendMessage::UpdateDocumentModeLayout { layout_target, diff },
LayoutTarget::LayersPanelBottomBar => FrontendMessage::UpdateLayersPanelBottomBarLayout { layout_target, diff },
LayoutTarget::LayersPanelControlLeftBar => FrontendMessage::UpdateLayersPanelControlBarLeftLayout { layout_target, diff },
LayoutTarget::LayersPanelControlRightBar => FrontendMessage::UpdateLayersPanelControlBarRightLayout { layout_target, diff },
LayoutTarget::MenuBar => FrontendMessage::UpdateMenuBarLayout { layout_target, diff },
LayoutTarget::NodeGraphControlBar => FrontendMessage::UpdateNodeGraphControlBarLayout { layout_target, diff },
LayoutTarget::PropertiesPanel => FrontendMessage::UpdatePropertiesPanelLayout { layout_target, diff },
LayoutTarget::StatusBarHints => FrontendMessage::UpdateStatusBarHintsLayout { layout_target, diff },
LayoutTarget::ToolOptions => FrontendMessage::UpdateToolOptionsLayout { layout_target, diff },
LayoutTarget::ToolShelf => FrontendMessage::UpdateToolShelfLayout { layout_target, diff },
LayoutTarget::WelcomeScreenButtons => FrontendMessage::UpdateWelcomeScreenButtonsLayout { layout_target, diff },
LayoutTarget::WorkingColors => FrontendMessage::UpdateWorkingColorsLayout { layout_target, diff },
LayoutTarget::DataPanel => FrontendMessage::UpdateDataPanelLayout { diff },
LayoutTarget::DialogButtons => FrontendMessage::UpdateDialogButtons { diff },
LayoutTarget::DialogColumn1 => FrontendMessage::UpdateDialogColumn1 { diff },
LayoutTarget::DialogColumn2 => FrontendMessage::UpdateDialogColumn2 { diff },
LayoutTarget::DocumentBar => FrontendMessage::UpdateDocumentBarLayout { diff },
LayoutTarget::DocumentMode => FrontendMessage::UpdateDocumentModeLayout { diff },
LayoutTarget::LayersPanelBottomBar => FrontendMessage::UpdateLayersPanelBottomBarLayout { diff },
LayoutTarget::LayersPanelControlLeftBar => FrontendMessage::UpdateLayersPanelControlBarLeftLayout { diff },
LayoutTarget::LayersPanelControlRightBar => FrontendMessage::UpdateLayersPanelControlBarRightLayout { diff },
LayoutTarget::MenuBar => FrontendMessage::UpdateMenuBarLayout { diff },
LayoutTarget::NodeGraphControlBar => FrontendMessage::UpdateNodeGraphControlBarLayout { diff },
LayoutTarget::PropertiesPanel => FrontendMessage::UpdatePropertiesPanelLayout { diff },
LayoutTarget::StatusBarHints => FrontendMessage::UpdateStatusBarHintsLayout { diff },
LayoutTarget::ToolOptions => FrontendMessage::UpdateToolOptionsLayout { diff },
LayoutTarget::ToolShelf => FrontendMessage::UpdateToolShelfLayout { diff },
LayoutTarget::WelcomeScreenButtons => FrontendMessage::UpdateWelcomeScreenButtonsLayout { diff },
LayoutTarget::WorkingColors => FrontendMessage::UpdateWorkingColorsLayout { diff },
LayoutTarget::LayoutTargetLength => panic!("`LayoutTargetLength` is not a valid Layout Target and is used for array indexing"),
};

View File

@@ -118,25 +118,19 @@ impl Default for Layout {
// TODO: Unwrap this struct
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize, PartialEq, specta::Type)]
pub struct WidgetLayout {
pub layout: SubLayout,
}
pub struct WidgetLayout(pub Vec<LayoutGroup>);
impl WidgetLayout {
pub fn new(layout: SubLayout) -> Self {
Self { layout }
}
pub fn iter(&self) -> WidgetIter<'_> {
WidgetIter {
stack: self.layout.iter().collect(),
stack: self.0.iter().collect(),
..Default::default()
}
}
pub fn iter_mut(&mut self) -> WidgetIterMut<'_> {
WidgetIterMut {
stack: self.layout.iter_mut().collect(),
stack: self.0.iter_mut().collect(),
..Default::default()
}
}
@@ -145,12 +139,12 @@ impl WidgetLayout {
pub fn diff(&mut self, new: Self, widget_path: &mut Vec<usize>, widget_diffs: &mut Vec<WidgetDiff>) {
// Check if the length of items is different
// TODO: Diff insersion and deletion of items
if self.layout.len() != new.layout.len() {
if self.0.len() != new.0.len() {
// Update the layout to the new layout
self.layout.clone_from(&new.layout);
self.0.clone_from(&new.0);
// Push an update sublayout to the diff
let new = DiffUpdate::SubLayout(new.layout);
let new = DiffUpdate::WidgetLayout(new);
widget_diffs.push(WidgetDiff {
widget_path: widget_path.to_vec(),
new_value: new,
@@ -158,7 +152,7 @@ impl WidgetLayout {
return;
}
// Diff all of the children
for (index, (current_child, new_child)) in self.layout.iter_mut().zip(new.layout).enumerate() {
for (index, (current_child, new_child)) in self.0.iter_mut().zip(new.0).enumerate() {
widget_path.push(index);
current_child.diff(new_child, widget_path, widget_diffs);
widget_path.pop();
@@ -185,7 +179,7 @@ impl<'a> Iterator for WidgetIter<'a> {
if let Some(item) = widget {
if let WidgetInstance { widget: Widget::PopoverButton(p), .. } = item {
self.stack.extend(p.popover_layout.iter());
self.stack.extend(p.popover_layout.0.iter());
return self.next();
}
@@ -206,7 +200,7 @@ impl<'a> Iterator for WidgetIter<'a> {
self.next()
}
Some(LayoutGroup::Section { layout, .. }) => {
for layout_row in layout {
for layout_row in &layout.0 {
self.stack.push(layout_row);
}
self.next()
@@ -235,7 +229,7 @@ impl<'a> Iterator for WidgetIterMut<'a> {
if let Some(widget) = widget {
if let WidgetInstance { widget: Widget::PopoverButton(p), .. } = widget {
self.stack.extend(p.popover_layout.iter_mut());
self.stack.extend(p.popover_layout.0.iter_mut());
return self.next();
}
@@ -256,7 +250,7 @@ impl<'a> Iterator for WidgetIterMut<'a> {
self.next()
}
Some(LayoutGroup::Section { layout, .. }) => {
for layout_row in layout {
for layout_row in &mut layout.0 {
self.stack.push(layout_row);
}
self.next()
@@ -266,8 +260,6 @@ impl<'a> Iterator for WidgetIterMut<'a> {
}
}
pub type SubLayout = Vec<LayoutGroup>;
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub enum LayoutGroup {
#[serde(rename = "column")]
@@ -293,7 +285,7 @@ pub enum LayoutGroup {
visible: bool,
pinned: bool,
id: u64,
layout: SubLayout,
layout: WidgetLayout,
},
}
@@ -425,7 +417,7 @@ impl LayoutGroup {
) => {
// Resend the entire panel if the lengths, names, visibility, or node IDs are different
// TODO: Diff insersion and deletion of items
if current_layout.len() != new_layout.len()
if current_layout.0.len() != new_layout.0.len()
|| *current_name != new_name
|| *current_description != new_description
|| *current_visible != new_visible
@@ -454,7 +446,7 @@ impl LayoutGroup {
}
// Diff all of the children
else {
for (index, (current_child, new_child)) in current_layout.iter_mut().zip(new_layout).enumerate() {
for (index, (current_child, new_child)) in current_layout.0.iter_mut().zip(new_layout.0).enumerate() {
widget_path.push(index);
current_child.diff(new_child, widget_path, widget_diffs);
widget_path.pop();
@@ -478,7 +470,6 @@ impl LayoutGroup {
}
}
// TODO: Rename to WidgetInstance
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct WidgetInstance {
#[serde(rename = "widgetId")]
@@ -514,7 +505,7 @@ impl WidgetInstance {
&& button1.popover_min_width == button2.popover_min_width
{
let mut new_widget_path = widget_path.to_vec();
for (i, (a, b)) in button1.popover_layout.iter_mut().zip(button2.popover_layout.iter()).enumerate() {
for (i, (a, b)) in button1.popover_layout.0.iter_mut().zip(button2.popover_layout.0.iter()).enumerate() {
new_widget_path.push(i);
a.diff(b.clone(), &mut new_widget_path, widget_diffs);
new_widget_path.pop();
@@ -598,11 +589,11 @@ pub struct WidgetDiff {
/// The new value of the UI, sent as part of a diff.
///
/// An update can represent a single widget or an entire SubLayout, or just a single layout group.
/// An update can represent a single widget or an entire WidgetLayout, or just a single layout group.
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
pub enum DiffUpdate {
#[serde(rename = "subLayout")]
SubLayout(SubLayout),
#[serde(rename = "widgetLayout")]
WidgetLayout(WidgetLayout),
#[serde(rename = "layoutGroup")]
LayoutGroup(LayoutGroup),
#[serde(rename = "widget")]
@@ -684,7 +675,7 @@ impl DiffUpdate {
};
match self {
Self::SubLayout(sub_layout) => sub_layout.iter_mut().flat_map(|layout_group| layout_group.iter_mut()).for_each(|widget_instance| {
Self::WidgetLayout(widget_layout) => widget_layout.0.iter_mut().flat_map(|layout_group| layout_group.iter_mut()).for_each(|widget_instance| {
convert_tooltip(widget_instance);
convert_menu_lists(widget_instance);
}),

View File

@@ -63,7 +63,7 @@ pub struct PopoverButton {
pub tooltip_shortcut: Option<ActionShortcut>,
#[serde(rename = "popoverLayout")]
pub popover_layout: SubLayout,
pub popover_layout: WidgetLayout,
#[serde(rename = "popoverMinWidth")]
pub popover_min_width: Option<u32>,

View File

@@ -131,7 +131,7 @@ impl DataPanelMessageHandler {
}
responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(WidgetLayout { layout }),
layout: Layout::WidgetLayout(WidgetLayout(layout)),
layout_target: LayoutTarget::DataPanel,
});
}

View File

@@ -2175,7 +2175,7 @@ impl DocumentMessageHandler {
pub fn update_document_widgets(&self, responses: &mut VecDeque<Message>, animation_is_playing: bool, time: Duration) {
// Document mode (dropdown menu at the left of the bar above the viewport, before the tool options)
let document_mode_layout = WidgetLayout::new(vec![LayoutGroup::Row {
let document_mode_layout = WidgetLayout(vec![LayoutGroup::Row {
widgets: vec![
// DropdownInput::new(
// vec![vec![
@@ -2235,7 +2235,7 @@ impl DocumentMessageHandler {
})
.widget_instance(),
PopoverButton::new()
.popover_layout(vec![
.popover_layout(WidgetLayout(vec![
LayoutGroup::Row {
widgets: vec![TextLabel::new("Overlays").bold(true).widget_instance()],
},
@@ -2468,7 +2468,7 @@ impl DocumentMessageHandler {
]
},
},
])
]))
.widget_instance(),
Separator::new(SeparatorType::Related).widget_instance(),
CheckboxInput::new(snapping_state.snapping_enabled)
@@ -2484,7 +2484,7 @@ impl DocumentMessageHandler {
})
.widget_instance(),
PopoverButton::new()
.popover_layout(
.popover_layout(WidgetLayout(
[
LayoutGroup::Row {
widgets: vec![TextLabel::new("Snapping").bold(true).widget_instance()],
@@ -2538,7 +2538,7 @@ impl DocumentMessageHandler {
},
}))
.collect(),
)
))
.widget_instance(),
Separator::new(SeparatorType::Related).widget_instance(),
CheckboxInput::new(self.snapping_state.grid_snapping)
@@ -2548,7 +2548,7 @@ impl DocumentMessageHandler {
.on_update(|optional_input: &CheckboxInput| DocumentMessage::GridVisibility { visible: optional_input.checked }.into())
.widget_instance(),
PopoverButton::new()
.popover_layout(overlay_options(&self.snapping_state.grid))
.popover_layout(WidgetLayout(overlay_options(&self.snapping_state.grid)))
.popover_min_width(Some(320))
.widget_instance(),
Separator::new(SeparatorType::Unrelated).widget_instance(),
@@ -2573,8 +2573,8 @@ impl DocumentMessageHandler {
.selected_index(Some(self.render_mode as u32))
.narrow(true)
.widget_instance(),
// PopoverButton::new()
// .popover_layout(vec![
// PopoverButton::new().popover_layout(
// WidgetLayout(vec![
// LayoutGroup::Row {
// widgets: vec![TextLabel::new("Render Mode").bold(true).widget_instance()],
// },
@@ -2583,6 +2583,7 @@ impl DocumentMessageHandler {
// },
// ])
// .widget_instance(),
// ),
Separator::new(SeparatorType::Unrelated).widget_instance(),
];
@@ -2631,7 +2632,7 @@ impl DocumentMessageHandler {
.widget_instance(),
]);
let document_bar_layout = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]);
let document_bar_layout = WidgetLayout(vec![LayoutGroup::Row { widgets }]);
responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(document_bar_layout),
@@ -2772,7 +2773,7 @@ impl DocumentMessageHandler {
.tooltip_label("Fill")
.widget_instance(),
];
let layers_panel_control_bar_left = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]);
let layers_panel_control_bar_left = WidgetLayout(vec![LayoutGroup::Row { widgets }]);
let widgets = vec![
IconButton::new(if selection_all_locked { "PadlockLocked" } else { "PadlockUnlocked" }, 24)
@@ -2790,7 +2791,7 @@ impl DocumentMessageHandler {
.disabled(!has_selection)
.widget_instance(),
];
let layers_panel_control_bar_right = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]);
let layers_panel_control_bar_right = WidgetLayout(vec![LayoutGroup::Row { widgets }]);
responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(layers_panel_control_bar_left),
@@ -2844,7 +2845,7 @@ impl DocumentMessageHandler {
}
})
.widget_instance();
vec![LayoutGroup::Row { widgets: vec![node_chooser] }]
WidgetLayout(vec![LayoutGroup::Row { widgets: vec![node_chooser] }])
})
.widget_instance(),
Separator::new(SeparatorType::Unrelated).widget_instance(),
@@ -2869,7 +2870,7 @@ impl DocumentMessageHandler {
.disabled(!has_selection)
.widget_instance(),
];
let layers_panel_bottom_bar = WidgetLayout::new(vec![LayoutGroup::Row { widgets }]);
let layers_panel_bottom_bar = WidgetLayout(vec![LayoutGroup::Row { widgets }]);
responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(layers_panel_bottom_bar),

View File

@@ -2069,7 +2069,7 @@ impl NodeGraphMessageHandler {
/// Send the cached layout to the frontend for the control bar at the top of the node panel
fn send_node_bar_layout(&self, responses: &mut VecDeque<Message>) {
responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(WidgetLayout::new(self.widgets.to_vec())),
layout: Layout::WidgetLayout(WidgetLayout(self.widgets.to_vec())),
layout_target: LayoutTarget::NodeGraphControlBar,
});
}
@@ -2145,7 +2145,7 @@ impl NodeGraphMessageHandler {
}
})
.widget_instance();
vec![LayoutGroup::Row { widgets: vec![node_chooser] }]
WidgetLayout(vec![LayoutGroup::Row { widgets: vec![node_chooser] }])
})
.widget_instance(),
//
@@ -2443,7 +2443,7 @@ impl NodeGraphMessageHandler {
.into()
})
.widget_instance();
vec![LayoutGroup::Row { widgets: vec![node_chooser] }]
WidgetLayout(vec![LayoutGroup::Row { widgets: vec![node_chooser] }])
})
.widget_instance(),
Separator::new(SeparatorType::Related).widget_instance(),

View File

@@ -1699,7 +1699,7 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
visible,
pinned,
id: node_id.0,
layout,
layout: WidgetLayout(layout),
}
}

View File

@@ -35,7 +35,7 @@ impl MessageHandler<PropertiesPanelMessage, PropertiesPanelMessageContext<'_>> f
match message {
PropertiesPanelMessage::Clear => {
responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(WidgetLayout::new(vec![])),
layout: Layout::WidgetLayout(WidgetLayout(vec![])),
layout_target: LayoutTarget::PropertiesPanel,
});
}
@@ -56,7 +56,7 @@ impl MessageHandler<PropertiesPanelMessage, PropertiesPanelMessageContext<'_>> f
let properties_sections = NodeGraphMessageHandler::collate_properties(&mut node_properties_context);
node_properties_context.responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(WidgetLayout::new(properties_sections)),
layout: Layout::WidgetLayout(WidgetLayout(properties_sections)),
layout_target: LayoutTarget::PropertiesPanel,
});
}

View File

@@ -736,6 +736,6 @@ impl LayoutHolder for MenuBarMessageHandler {
.widget_instance(),
];
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets: menu_bar_buttons }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets: menu_bar_buttons }]))
}
}

View File

@@ -924,7 +924,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
layout_target: LayoutTarget::WelcomeScreenButtons,
});
responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(WidgetLayout::new(vec![table])),
layout: Layout::WidgetLayout(WidgetLayout(vec![table])),
layout_target: LayoutTarget::WelcomeScreenButtons,
});
}

View File

@@ -220,7 +220,7 @@ impl LayoutHolder for BrushTool {
.widget_instance(),
);
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}

View File

@@ -151,7 +151,7 @@ impl LayoutHolder for FreehandTool {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_instance());
widgets.push(create_weight_widget(self.options.line_weight));
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}

View File

@@ -107,7 +107,7 @@ impl LayoutHolder for GradientTool {
.selected_index(Some((self.selected_gradient().unwrap_or(self.options.gradient_type) == GradientType::Radial) as u32))
.widget_instance();
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets: vec![gradient_type] }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets: vec![gradient_type] }]))
}
}

View File

@@ -342,7 +342,7 @@ impl LayoutHolder for PathTool {
let _pin_pivot = pin_pivot_widget(self.tool_data.pivot_gizmo.pin_active(), false, PivotToolSource::Path);
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row {
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row {
widgets: vec![
x_location,
related_seperator.clone(),

View File

@@ -238,7 +238,7 @@ impl LayoutHolder for PenTool {
.widget_instance(),
);
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}

View File

@@ -252,14 +252,14 @@ impl LayoutHolder for SelectTool {
widgets.extend(self.alignment_widgets(disabled));
// widgets.push(
// PopoverButton::new()
// .popover_layout(vec![
// .popover_layout(WidgetLayout(vec![
// LayoutGroup::Row {
// widgets: vec![TextLabel::new("Align").bold(true).widget_instance()],
// },
// LayoutGroup::Row {
// widgets: vec![TextLabel::new("Coming soon").widget_instance()],
// },
// ])
// ]))
// .disabled(disabled)
// .widget_instance(),
// );
@@ -277,7 +277,7 @@ impl LayoutHolder for SelectTool {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_instance());
widgets.extend(self.boolean_widgets(self.tool_data.selected_layers_count));
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}

View File

@@ -335,7 +335,7 @@ impl LayoutHolder for ShapeTool {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_instance());
widgets.push(create_weight_widget(self.options.line_weight));
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}

View File

@@ -158,7 +158,7 @@ impl LayoutHolder for SplineTool {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_instance());
widgets.push(create_weight_widget(self.options.line_weight));
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}

View File

@@ -203,7 +203,7 @@ impl LayoutHolder for TextTool {
},
));
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
}

View File

@@ -117,7 +117,7 @@ pub struct DocumentToolData {
impl DocumentToolData {
pub fn update_working_colors(&self, responses: &mut VecDeque<Message>) {
let layout = WidgetLayout::new(vec![
let layout = WidgetLayout(vec![
LayoutGroup::Row {
widgets: vec![WorkingColorsInput::new(self.primary_color.to_gamma_srgb(), self.secondary_color.to_gamma_srgb()).widget_instance()],
},
@@ -290,9 +290,7 @@ impl LayoutHolder for ToolData {
.skip(1)
.collect();
Layout::WidgetLayout(WidgetLayout {
layout: vec![LayoutGroup::Row { widgets: tool_groups_layout }],
})
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets: tool_groups_layout }]))
}
}
@@ -547,7 +545,7 @@ impl HintData {
}
}
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
Layout::WidgetLayout(WidgetLayout(vec![LayoutGroup::Row { widgets }]))
}
pub fn send_layout(&self, responses: &mut VecDeque<Message>) {
@@ -559,7 +557,7 @@ impl HintData {
pub fn clear_layout(responses: &mut VecDeque<Message>) {
responses.add(LayoutMessage::SendLayout {
layout: Layout::WidgetLayout(WidgetLayout::new(vec![])),
layout: Layout::WidgetLayout(WidgetLayout(vec![])),
layout_target: LayoutTarget::StatusBarHints,
});
}