diff options
| author | pml68 <contact@pml68.me> | 2024-10-04 00:44:02 +0200 |
|---|---|---|
| committer | pml68 <contact@pml68.me> | 2024-10-04 00:44:02 +0200 |
| commit | 510d68b92972b99868e187dd5340f04780b4c354 (patch) | |
| tree | 6d0937824d8606423b5afef2a16e182a3a984f8f /iced_builder/src/types | |
| parent | feat: implement fmt::Display for RenderedElement, work on props (diff) | |
| download | iced-builder-510d68b92972b99868e187dd5340f04780b4c354.tar.gz | |
feat: update to iced 0.13.1, basic project state file, prepare for drag&drop
Diffstat (limited to 'iced_builder/src/types')
| -rw-r--r-- | iced_builder/src/types/mod.rs | 10 | ||||
| -rw-r--r-- | iced_builder/src/types/project/mod.rs | 59 | ||||
| -rw-r--r-- | iced_builder/src/types/rendered_element.rs | 124 |
3 files changed, 170 insertions, 23 deletions
diff --git a/iced_builder/src/types/mod.rs b/iced_builder/src/types/mod.rs index 344f543..2d6cd8f 100644 --- a/iced_builder/src/types/mod.rs +++ b/iced_builder/src/types/mod.rs @@ -1,15 +1,9 @@ +pub mod project; pub mod rendered_element; -use rendered_element::RenderedElement; use serde::{Deserialize, Serialize}; -#[derive(Clone)] -pub struct DesignerState { - pub designer_content: Option<RenderedElement>, - pub designer_page: DesignerPage, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum ElementName { Text(String), Button(String), diff --git a/iced_builder/src/types/project/mod.rs b/iced_builder/src/types/project/mod.rs new file mode 100644 index 0000000..557fa92 --- /dev/null +++ b/iced_builder/src/types/project/mod.rs @@ -0,0 +1,59 @@ +use std::path::{Path, PathBuf}; + +use serde::{Deserialize, Serialize}; + +use crate::Error; + +use super::rendered_element::RenderedElement; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Project { + pub title: Option<String>, + pub content: Option<RenderedElement>, +} + +impl Project { + pub fn new() -> Self { + Self { + title: None, + content: None, + } + } + + pub async fn from_file() -> Result<(PathBuf, Self), Error> { + let picked_file = rfd::AsyncFileDialog::new() + .set_title("Open a JSON file...") + .add_filter("*.JSON, *.json", &["JSON", "json"]) + .pick_file() + .await + .ok_or(Error::DialogClosed)?; + + let path = picked_file.path().to_owned(); + + let contents = tokio::fs::read_to_string(&path).await?; + let element: Self = serde_json::from_str(&contents)?; + + Ok((path, element)) + } + + pub async fn write_to_file(self, path: Option<PathBuf>) -> Result<PathBuf, Error> { + let path = if let Some(p) = path { + p + } else { + rfd::AsyncFileDialog::new() + .set_title("Save to JSON file...") + .add_filter("*.JSON, *.json", &["JSON", "json"]) + .save_file() + .await + .as_ref() + .map(rfd::FileHandle::path) + .map(Path::to_owned) + .ok_or(Error::DialogClosed)? + }; + + let contents = serde_json::to_string(&self.clone())?; + tokio::fs::write(&path, contents).await?; + + Ok(path) + } +} diff --git a/iced_builder/src/types/rendered_element.rs b/iced_builder/src/types/rendered_element.rs index 2d5c81a..967352b 100644 --- a/iced_builder/src/types/rendered_element.rs +++ b/iced_builder/src/types/rendered_element.rs @@ -1,11 +1,15 @@ use std::collections::HashMap; +use iced::advanced::widget::Id; +use iced::{widget, Element, Length}; use serde::{Deserialize, Serialize}; use unique_id::{string::StringGenerator, Generator}; +use crate::Message; + use super::ElementName; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct RenderedElement { pub id: String, pub child_elements: Option<Vec<RenderedElement>>, @@ -34,27 +38,104 @@ impl RenderedElement { } } - fn preset_options(mut self, options: Vec<&str>) -> Self { - for opt in options { - self.props.insert(opt.to_owned(), None); + pub fn find_by_id(&mut self, id: Id) -> Option<&mut Self> { + if Id::new(self.id.clone()) == id.clone() { + println!(""); + return Some(self); + } else if let Some(child_elements) = self.child_elements.as_mut() { + for element in child_elements { + let element = element.find_by_id(id.clone()); + if element.is_some() { + return element; + } + } + return None; + } else { + return None; } - self } - pub fn push(mut self, element: RenderedElement) -> Self { - if let Some(els) = self.child_elements.as_mut() { - els.push(element); + pub fn find_parent(&mut self, child_element: &RenderedElement) -> Option<&mut Self> { + if child_element == self { + return Some(self); + } else if self.child_elements.is_some() { + if self.child_elements.clone()?.contains(child_element) { + return Some(self); + } else { + if let Some(child_elements) = self.child_elements.as_mut() { + for element in child_elements { + let element: Option<&mut Self> = element.find_parent(child_element); + if element.is_some() { + return element; + } + } + } + return None; + } } else { - self.child_elements = Some(vec![element]); + return None; + } + } + + pub fn remove(&mut self, element: &RenderedElement) { + let parent = self.find_parent(element); + if let Some(child_elements) = parent.unwrap().child_elements.as_mut() { + if let Some(index) = child_elements.iter().position(|x| x == element) { + child_elements.remove(index); + } + } + } + + pub fn push(&mut self, element: RenderedElement) { + if let Some(child_elements) = self.child_elements.as_mut() { + child_elements.push(element); + } + } + + pub fn insert_after(&mut self, id: Id, element: RenderedElement) { + if let Some(child_elements) = self.child_elements.as_mut() { + if let Some(index) = child_elements + .iter() + .position(|x| Id::new(x.id.clone()) == id) + { + child_elements.insert(index, element); + } else { + child_elements.push(element); + } + } + } + + fn preset_options(mut self, options: Vec<&str>) -> Self { + for opt in options { + self.props.insert(opt.to_owned(), None); } self } - pub fn option(mut self, option: &'static str, value: &'static str) -> Self { + pub fn option(&mut self, option: &'static str, value: &'static str) { self.props .entry(option.to_owned()) .and_modify(|opt| *opt = Some(value.to_owned())); - self + } + + pub fn as_element(self) -> Element<'static, Message> { + let mut children = widget::column![]; + + if let Some(els) = self.child_elements.clone() { + for el in els { + children = children.push(el.clone().as_element()); + } + } + iced_drop::droppable( + widget::container( + widget::column![widget::text(self.name.clone().to_string()), children] + .width(Length::Fill), + ) + .style(widget::container::bordered_box), + ) + .id(Id::new(self.id.clone())) + .on_drop(move |point, rect| Message::MoveElement(self.clone(), point, rect)) + .into() } } @@ -121,10 +202,23 @@ pub fn image(path: &str) -> RenderedElement { RenderedElement::new(ElementName::Image(path.to_owned())) } -pub fn container(content: RenderedElement) -> RenderedElement { - RenderedElement::from_vec(ElementName::Container, vec![content]) +pub fn container(content: Option<RenderedElement>) -> RenderedElement { + match content { + Some(el) => RenderedElement::from_vec(ElementName::Container, vec![el]), + None => RenderedElement::from_vec(ElementName::Container, vec![]), + } } -pub fn row(child_elements: Vec<RenderedElement>) -> RenderedElement { - RenderedElement::from_vec(ElementName::Row, child_elements) +pub fn row(child_elements: Option<Vec<RenderedElement>>) -> RenderedElement { + match child_elements { + Some(els) => RenderedElement::from_vec(ElementName::Row, els), + None => RenderedElement::from_vec(ElementName::Row, vec![]), + } +} + +pub fn column(child_elements: Option<Vec<RenderedElement>>) -> RenderedElement { + match child_elements { + Some(els) => RenderedElement::from_vec(ElementName::Column, els), + None => RenderedElement::from_vec(ElementName::Column, vec![]), + } } |
