summaryrefslogtreecommitdiff
path: root/iced_builder/src/types
diff options
context:
space:
mode:
authorPolesznyák Márk László <116908301+pml68@users.noreply.github.com>2024-12-26 00:12:06 +0100
committerGitHub <noreply@github.com>2024-12-26 00:12:06 +0100
commit0ae3ec6cc9babcab39c76f023606229a151916ab (patch)
treee92d0109599622984b2c485cc020951da288cec3 /iced_builder/src/types
parentMerge pull request #3 from pml68/refactor/internal-restructuring (diff)
parentfeat: add `tip` widget helper from `hecrj/icebreaker` (diff)
downloadiced-builder-0ae3ec6cc9babcab39c76f023606229a151916ab.tar.gz
Merge pull request #4 from pml68/feat/playground
Playground done **for now**
Diffstat (limited to 'iced_builder/src/types')
-rw-r--r--iced_builder/src/types/element_name.rs8
-rw-r--r--iced_builder/src/types/mod.rs9
-rw-r--r--iced_builder/src/types/project.rs26
-rwxr-xr-xiced_builder/src/types/rendered_element.rs154
4 files changed, 135 insertions, 62 deletions
diff --git a/iced_builder/src/types/element_name.rs b/iced_builder/src/types/element_name.rs
index 93e12a1..e172227 100644
--- a/iced_builder/src/types/element_name.rs
+++ b/iced_builder/src/types/element_name.rs
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
-use crate::Error;
-
use super::rendered_element::{
button, column, container, image, row, svg, text, Action, RenderedElement,
};
+use crate::{Error, Result};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ElementName {
@@ -18,7 +17,7 @@ pub enum ElementName {
}
impl ElementName {
- pub const ALL: [Self; 7] = [
+ pub const ALL: &'static [Self; 7] = &[
Self::Text(String::new()),
Self::Button(String::new()),
Self::SVG(String::new()),
@@ -32,7 +31,7 @@ impl ElementName {
&self,
element_tree: Option<&mut RenderedElement>,
action: Action,
- ) -> Result<Option<RenderedElement>, Error> {
+ ) -> Result<Option<RenderedElement>> {
let element = match self {
Self::Text(_) => text(""),
Self::Button(_) => button(""),
@@ -44,6 +43,7 @@ impl ElementName {
};
match action {
Action::Stop => Ok(None),
+ Action::Drop => Ok(None),
Action::AddNew => Ok(Some(element)),
Action::PushFront(id) => {
element_tree
diff --git a/iced_builder/src/types/mod.rs b/iced_builder/src/types/mod.rs
deleted file mode 100644
index a48a2d8..0000000
--- a/iced_builder/src/types/mod.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod element_name;
-pub mod project;
-pub mod rendered_element;
-
-#[derive(Debug, Clone)]
-pub enum DesignerPage {
- Designer,
- CodeView,
-}
diff --git a/iced_builder/src/types/project.rs b/iced_builder/src/types/project.rs
index 52da41c..f4dbcc4 100644
--- a/iced_builder/src/types/project.rs
+++ b/iced_builder/src/types/project.rs
@@ -1,12 +1,11 @@
-use rust_format::{Config, Edition, Formatter, RustFmt};
use std::path::{Path, PathBuf};
use iced::Theme;
+use rust_format::{Config, Edition, Formatter, RustFmt};
use serde::{Deserialize, Serialize};
-use crate::Error;
-
use super::rendered_element::RenderedElement;
+use crate::{Error, Result};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Project {
@@ -55,10 +54,10 @@ impl Project {
}
}
- pub async fn from_file() -> Result<(PathBuf, Self), Error> {
+ pub async fn from_path() -> Result<(PathBuf, Self)> {
let picked_file = rfd::AsyncFileDialog::new()
.set_title("Open a JSON file...")
- .add_filter("*.JSON, *.json", &["JSON", "json"])
+ .add_filter("*.json, *.JSON", &["json", "JSON"])
.pick_file()
.await
.ok_or(Error::DialogClosed)?;
@@ -71,13 +70,13 @@ impl Project {
Ok((path, element))
}
- pub async fn write_to_file(self, path: Option<PathBuf>) -> Result<PathBuf, Error> {
+ pub async fn write_to_file(self, path: Option<PathBuf>) -> Result<PathBuf> {
let path = if let Some(p) = path {
p
} else {
rfd::AsyncFileDialog::new()
.set_title("Save to JSON file...")
- .add_filter("*.JSON, *.json", &["JSON", "json"])
+ .add_filter("*.json, *.JSON", &["json", "JSON"])
.save_file()
.await
.as_ref()
@@ -86,24 +85,25 @@ impl Project {
.ok_or(Error::DialogClosed)?
};
- let contents = serde_json::to_string(&self.clone())?;
+ let contents = serde_json::to_string(&self)?;
tokio::fs::write(&path, contents).await?;
Ok(path)
}
- pub fn app_code(&self) -> Result<String, Error> {
+ pub fn app_code(&self) -> Result<String> {
match self.element_tree {
Some(ref element_tree) => {
let (imports, view) = element_tree.codegen();
- let mut app_code = format!("use iced::{{widget::{{{imports}}},Element}};");
+ let mut app_code =
+ format!("use iced::{{widget::{{{imports}}},Element}};");
app_code = format!(
r#"// Automatically generated by iced Builder
{app_code}
fn main() -> iced::Result {{
- iced::application("{}", State::update, State::view).theme(iced::Theme::{}).run()
+ iced::application("{}", State::update, State::view).theme(State::theme).run()
}}
#[derive(Default)]
@@ -115,6 +115,10 @@ impl Project {
impl State {{
fn update(&mut self, _message: Message) {{}}
+ fn theme(&self) -> iced::Theme {{
+ iced::Theme::{}
+ }}
+
fn view(&self) -> Element<Message> {{
{view}.into()
}}
diff --git a/iced_builder/src/types/rendered_element.rs b/iced_builder/src/types/rendered_element.rs
index 08d7ba3..d4d1a6c 100755
--- a/iced_builder/src/types/rendered_element.rs
+++ b/iced_builder/src/types/rendered_element.rs
@@ -1,40 +1,38 @@
-use indexmap::IndexMap;
+use std::collections::BTreeMap;
+use blob_uuid::random_blob;
use iced::advanced::widget::Id;
use iced::{widget, Element, Length};
use serde::{Deserialize, Serialize};
-use unique_id::{string::StringGenerator, Generator};
-use crate::{Error, Message};
-
-use super::element_name::ElementName;
+use super::ElementName;
+use crate::types::Message;
+use crate::Result;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RenderedElement {
id: String,
- pub child_elements: Option<Vec<RenderedElement>>,
- pub name: ElementName,
- pub options: IndexMap<String, Option<String>>,
+ child_elements: Option<Vec<RenderedElement>>,
+ name: ElementName,
+ options: BTreeMap<String, Option<String>>,
}
impl RenderedElement {
fn new(name: ElementName) -> Self {
- let gen = StringGenerator::default();
Self {
- id: gen.next_id(),
+ id: random_blob(),
child_elements: None,
name,
- options: IndexMap::new(),
+ options: BTreeMap::new(),
}
}
fn with(name: ElementName, child_elements: Vec<RenderedElement>) -> Self {
- let gen = StringGenerator::default();
Self {
- id: gen.next_id(),
+ id: random_blob(),
child_elements: Some(child_elements),
name,
- options: IndexMap::new(),
+ options: BTreeMap::new(),
}
}
@@ -58,7 +56,10 @@ impl RenderedElement {
}
}
- pub fn find_parent(&mut self, child_element: &RenderedElement) -> Option<&mut Self> {
+ 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() {
@@ -94,9 +95,12 @@ impl RenderedElement {
}
pub fn remove(&mut self, element: &RenderedElement) {
- if let Some(child_elements) = self.child_elements.as_mut() {
- if let Some(index) = child_elements.iter().position(|x| x == element) {
- child_elements.remove(index);
+ let parent = self.find_parent(element).unwrap();
+ if let Some(child_elements) = parent.child_elements.as_mut() {
+ if let Some(index) =
+ child_elements.iter().position(|x| x == element)
+ {
+ let _ = child_elements.remove(index);
}
}
}
@@ -109,7 +113,9 @@ impl RenderedElement {
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| x.get_id() == id) {
+ if let Some(index) =
+ child_elements.iter().position(|x| x.get_id() == id)
+ {
child_elements.insert(index + 1, element.clone());
} else {
child_elements.push(element.clone());
@@ -121,17 +127,21 @@ impl RenderedElement {
&self,
element_tree: Option<&mut RenderedElement>,
action: Action,
- ) -> Result<(), Error> {
+ ) -> Result<()> {
let element_tree = element_tree.unwrap();
match action {
Action::Stop => Ok(()),
+ Action::Drop => {
+ element_tree.remove(self);
+
+ Ok(())
+ }
Action::AddNew => Err(
"the action was of kind `AddNew`, but invoking it on an existing element tree is not possible".into(),
),
Action::PushFront(id) => {
- let old_parent = element_tree.find_parent(self).unwrap();
- old_parent.remove(self);
+ element_tree.remove(self);
let new_parent = element_tree.find_by_id(id).unwrap();
new_parent.push_front(self);
@@ -139,8 +149,7 @@ impl RenderedElement {
Ok(())
}
Action::InsertAfter(parent_id, target_id) => {
- let old_parent = element_tree.find_parent(self).unwrap();
- old_parent.remove(self);
+ element_tree.remove(self);
let new_parent = element_tree.find_by_id(parent_id).unwrap();
new_parent.insert_after(target_id, self);
@@ -150,18 +159,19 @@ impl RenderedElement {
}
}
- fn preset_options(mut self, options: Vec<&str>) -> Self {
+ fn preset_options<'a>(mut self, options: &[&'a str]) -> Self {
for opt in options {
- self.options.insert(opt.to_owned(), None);
+ let _ = self.options.insert(opt.to_string(), None);
}
self
}
- pub fn option<'a>(&mut self, option: &'a str, value: &'a str) -> Self {
- self.options
+ pub fn option<'a>(mut self, option: &'a str, value: &'a str) -> Self {
+ let _ = self
+ .options
.entry(option.to_owned())
.and_modify(|opt| *opt = Some(value.to_owned()));
- self.clone()
+ self
}
pub fn as_element<'a>(self) -> Element<'a, Message> {
@@ -174,16 +184,21 @@ impl RenderedElement {
}
iced_drop::droppable(
widget::container(
- widget::column![widget::text(self.name.clone().to_string()), children]
- .width(Length::Fill)
- .spacing(10),
+ widget::column![
+ widget::text(self.name.clone().to_string()),
+ children
+ ]
+ .width(Length::Fill)
+ .spacing(10),
)
.padding(10)
.style(widget::container::bordered_box),
)
.id(self.get_id())
.drag_hide(true)
- .on_drop(move |point, rect| Message::MoveElement(self.clone(), point, rect))
+ .on_drop(move |point, rect| {
+ Message::MoveElement(self.clone(), point, rect)
+ })
.into()
}
@@ -299,11 +314,66 @@ impl std::fmt::Display for RenderedElement {
}
}
+impl<'a> From<RenderedElement> for Element<'a, Message> {
+ fn from(value: RenderedElement) -> Self {
+ let child_elements = match value.child_elements {
+ Some(ref elements) => elements.clone(),
+ None => vec![],
+ };
+
+ let content: Element<'a, Message> = match value.name.clone() {
+ ElementName::Text(s) => {
+ if s == String::new() {
+ widget::text("New Text").into()
+ } else {
+ widget::text(s).into()
+ }
+ }
+ ElementName::Button(s) => {
+ if s == String::new() {
+ widget::button(widget::text("New Button")).into()
+ } else {
+ widget::button(widget::text(s)).into()
+ }
+ }
+ ElementName::SVG(p) => widget::svg(p).into(),
+ ElementName::Image(p) => widget::image(p).into(),
+ ElementName::Container => {
+ widget::container(if child_elements.len() == 1 {
+ child_elements[0].clone().into()
+ } else {
+ Element::from("")
+ })
+ .padding(20)
+ .into()
+ }
+ ElementName::Row => widget::Row::from_iter(
+ child_elements.into_iter().map(|el| el.into()),
+ )
+ .padding(20)
+ .into(),
+ ElementName::Column => widget::Column::from_iter(
+ child_elements.into_iter().map(|el| el.into()),
+ )
+ .padding(20)
+ .into(),
+ };
+ iced_drop::droppable(content)
+ .id(value.get_id())
+ .drag_hide(true)
+ .on_drop(move |point, rect| {
+ Message::MoveElement(value.clone(), point, rect)
+ })
+ .into()
+ }
+}
+
#[derive(Debug, Clone)]
pub enum Action {
AddNew,
PushFront(Id),
InsertAfter(Id, Id),
+ Drop,
Stop,
}
@@ -317,12 +387,16 @@ impl Action {
if ids.len() == 1 {
if element_tree.is_none() {
action = Self::AddNew;
+ } else {
+ action = Self::Drop;
}
} else {
let id: Id = match source_id {
Some(id) if ids.contains(&id) => {
- let element_id = ids[ids.iter().position(|x| *x == id).unwrap()].clone();
- if ids.len() > 2 && ids[ids.clone().len() - 1] == element_id {
+ let element_id =
+ ids[ids.iter().position(|x| *x == id).unwrap()].clone();
+ if ids.len() > 2 && ids[ids.clone().len() - 1] == element_id
+ {
return Self::Stop;
}
element_id
@@ -337,7 +411,8 @@ impl Action {
// Element IS a parent but ISN'T a non-empty container
match element.is_parent()
- && !(element.name == ElementName::Container && !element.is_empty())
+ && !(element.name == ElementName::Container
+ && !element.is_empty())
{
true => {
action = Self::PushFront(id);
@@ -368,7 +443,7 @@ impl Action {
}
pub fn text(text: &str) -> RenderedElement {
- RenderedElement::new(ElementName::Text(text.to_owned())).preset_options(vec![
+ RenderedElement::new(ElementName::Text(text.to_owned())).preset_options(&[
"size",
"line_height",
"width",
@@ -400,5 +475,8 @@ pub fn row(child_elements: Option<Vec<RenderedElement>>) -> RenderedElement {
}
pub fn column(child_elements: Option<Vec<RenderedElement>>) -> RenderedElement {
- RenderedElement::with(ElementName::Column, child_elements.unwrap_or_default())
+ RenderedElement::with(
+ ElementName::Column,
+ child_elements.unwrap_or_default(),
+ )
}