summaryrefslogtreecommitdiff
path: root/iced_builder/src/types
diff options
context:
space:
mode:
authorpml68 <contact@pml68.me>2024-10-04 00:44:02 +0200
committerpml68 <contact@pml68.me>2024-10-04 00:44:02 +0200
commit510d68b92972b99868e187dd5340f04780b4c354 (patch)
tree6d0937824d8606423b5afef2a16e182a3a984f8f /iced_builder/src/types
parentfeat: implement fmt::Display for RenderedElement, work on props (diff)
downloadiced-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.rs10
-rw-r--r--iced_builder/src/types/project/mod.rs59
-rw-r--r--iced_builder/src/types/rendered_element.rs124
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![]),
+ }
}