summaryrefslogtreecommitdiff
path: root/iced_builder/src/types
diff options
context:
space:
mode:
Diffstat (limited to 'iced_builder/src/types')
-rw-r--r--iced_builder/src/types/element_name.rs85
-rw-r--r--iced_builder/src/types/project.rs165
-rwxr-xr-xiced_builder/src/types/rendered_element.rs468
3 files changed, 0 insertions, 718 deletions
diff --git a/iced_builder/src/types/element_name.rs b/iced_builder/src/types/element_name.rs
deleted file mode 100644
index 2687673..0000000
--- a/iced_builder/src/types/element_name.rs
+++ /dev/null
@@ -1,85 +0,0 @@
-use serde::{Deserialize, Serialize};
-
-use super::rendered_element::{
- button, column, container, image, row, svg, text, Action, RenderedElement,
-};
-use crate::Error;
-
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
-pub enum ElementName {
- Text(String),
- Button(String),
- Svg(String),
- Image(String),
- Container,
- Row,
- Column,
-}
-
-impl ElementName {
- pub const ALL: &'static [Self; 7] = &[
- Self::Text(String::new()),
- Self::Button(String::new()),
- Self::Svg(String::new()),
- Self::Image(String::new()),
- Self::Container,
- Self::Row,
- Self::Column,
- ];
-
- pub fn handle_action(
- &self,
- element_tree: Option<&mut RenderedElement>,
- action: Action,
- ) -> Result<Option<RenderedElement>, Error> {
- let element = match self {
- Self::Text(_) => text(""),
- Self::Button(_) => button(""),
- Self::Svg(_) => svg(""),
- Self::Image(_) => image(""),
- Self::Container => container(None),
- Self::Row => row(None),
- Self::Column => column(None),
- };
- match action {
- Action::Stop | Action::Drop => Ok(None),
- Action::AddNew => Ok(Some(element)),
- Action::PushFront(id) => {
- element_tree
- .ok_or("the action was of kind `PushFront`, but no element tree was provided.")?
- .find_by_id(id)
- .ok_or(Error::NonExistentElement)?
- .push_front(&element);
- Ok(None)
- }
- Action::InsertAfter(parent_id, child_id) => {
- element_tree
- .ok_or(
- "the action was of kind `InsertAfter`, but no element tree was provided.",
- )?
- .find_by_id(parent_id)
- .ok_or(Error::NonExistentElement)?
- .insert_after(child_id, &element);
- Ok(None)
- }
- }
- }
-}
-
-impl std::fmt::Display for ElementName {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(
- f,
- "{}",
- match self {
- Self::Text(_) => "Text",
- Self::Button(_) => "Button",
- Self::Svg(_) => "SVG",
- Self::Image(_) => "Image",
- Self::Container => "Container",
- Self::Row => "Row",
- Self::Column => "Column",
- }
- )
- }
-}
diff --git a/iced_builder/src/types/project.rs b/iced_builder/src/types/project.rs
deleted file mode 100644
index 27c576b..0000000
--- a/iced_builder/src/types/project.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-use std::path::{Path, PathBuf};
-
-extern crate fxhash;
-use fxhash::FxHashMap;
-use iced::Theme;
-use rust_format::{Edition, Formatter, RustFmt};
-use serde::{Deserialize, Serialize};
-
-use super::rendered_element::RenderedElement;
-use crate::config::Config;
-use crate::theme::{theme_from_str, theme_index, theme_to_string};
-use crate::Error;
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Project {
- pub title: Option<String>,
- pub theme: Option<String>,
- pub element_tree: Option<RenderedElement>,
- #[serde(skip)]
- theme_cache: FxHashMap<String, String>,
-}
-
-impl Default for Project {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl Project {
- pub fn new() -> Self {
- Self {
- title: None,
- theme: None,
- element_tree: None,
- theme_cache: FxHashMap::default(),
- }
- }
-
- pub fn get_theme(&self, config: &Config) -> Theme {
- match &self.theme {
- Some(theme) => theme_from_str(Some(config), theme),
- None => Theme::default(),
- }
- }
-
- fn theme_code(&mut self, theme: &Theme) -> String {
- let theme_name = theme.to_string();
- if theme_index(&theme_name, Theme::ALL).is_none() {
- (*self
- .theme_cache
- .entry(theme_name)
- .or_insert(theme_to_string(theme)))
- .to_string()
- } else {
- theme_name.replace(" ", "")
- }
- }
-
- pub async fn from_path(
- path: PathBuf,
- config: Config,
- ) -> Result<(PathBuf, Self), Error> {
- let contents = tokio::fs::read_to_string(&path).await?;
- let mut project: Self = serde_json::from_str(&contents)?;
-
- let _ = project.theme_code(&project.get_theme(&config));
-
- Ok((path, project))
- }
-
- pub async fn from_file(config: Config) -> 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();
-
- Self::from_path(path, config).await
- }
-
- 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)?;
- tokio::fs::write(&path, contents).await?;
-
- Ok(path)
- }
-
- pub fn app_code(&mut self, config: &Config) -> Result<String, Error> {
- match self.element_tree {
- Some(ref element_tree) => {
- let (imports, view) = element_tree.codegen();
- let theme = self.get_theme(config);
- let theme_code = self.theme_code(&theme);
- let mut theme_imports = "";
- if theme_index(&theme.to_string(), Theme::ALL).is_none() {
- if theme_code.contains("Extended") {
- theme_imports = "use iced::{{color,theme::{{Palette,palette::{{Extended,Background,Primary,Secondary,Success,Danger,Pair}}}}}};\n";
- } else {
- theme_imports = "use iced::{{color,theme::Palette}};\n";
- }
- }
-
- let app_code = format!(
- r#"// Automatically generated by iced Builder
- use iced::{{widget::{{{imports}}},Element}};
- {theme_imports}
-
- fn main() -> iced::Result {{
- iced::application("{}", State::update, State::view).theme(State::theme).run()
- }}
-
- #[derive(Default)]
- struct State;
-
- #[derive(Debug, Clone)]
- enum Message {{}}
-
- impl State {{
- fn update(&mut self, _message: Message) {{}}
-
- fn theme(&self) -> iced::Theme {{
- iced::Theme::{}
- }}
-
- fn view(&self) -> Element<Message> {{
- {view}.into()
- }}
- }}"#,
- match self.title {
- Some(ref t) => t,
- None => "New app",
- },
- theme_code
- );
- let config = rust_format::Config::new_str()
- .edition(Edition::Rust2021)
- .option("trailing_comma", "Never")
- .option("imports_granularity", "Crate");
- let rustfmt = RustFmt::from_config(config);
- Ok(rustfmt.format_str(app_code)?)
- }
- None => Err("No element tree present".into()),
- }
- }
-}
diff --git a/iced_builder/src/types/rendered_element.rs b/iced_builder/src/types/rendered_element.rs
deleted file mode 100755
index b001556..0000000
--- a/iced_builder/src/types/rendered_element.rs
+++ /dev/null
@@ -1,468 +0,0 @@
-use std::collections::BTreeMap;
-
-use iced::advanced::widget::Id;
-use iced::{widget, Element, Length};
-use serde::{Deserialize, Serialize};
-use uuid::Uuid;
-
-use super::ElementName;
-use crate::types::Message;
-use crate::Error;
-
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
-pub struct RenderedElement {
- #[serde(skip, default = "Uuid::new_v4")]
- id: Uuid,
- child_elements: Option<Vec<RenderedElement>>,
- name: ElementName,
- options: BTreeMap<String, Option<String>>,
-}
-
-impl RenderedElement {
- fn new(name: ElementName) -> Self {
- Self {
- id: Uuid::new_v4(),
- child_elements: None,
- name,
- options: BTreeMap::new(),
- }
- }
-
- fn with(name: ElementName, child_elements: Vec<RenderedElement>) -> Self {
- Self {
- id: Uuid::new_v4(),
- child_elements: Some(child_elements),
- name,
- options: BTreeMap::new(),
- }
- }
-
- pub fn get_id(&self) -> Id {
- Id::new(self.id.to_string())
- }
-
- pub fn find_by_id(&mut self, id: &Id) -> Option<&mut Self> {
- if &self.get_id() == id {
- 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);
- if element.is_some() {
- return element;
- }
- }
- None
- } else {
- None
- }
- }
-
- 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()
- .unwrap_or_default()
- .contains(child_element)
- {
- return Some(self);
- }
- if let Some(child_elements) = self.child_elements.as_mut() {
- for element in child_elements {
- let element = element.find_parent(child_element);
- if element.is_some() {
- return element;
- }
- }
- }
- }
- None
- }
-
- pub fn is_parent(&self) -> bool {
- self.child_elements.is_some()
- }
-
- pub fn is_empty(&self) -> bool {
- self.child_elements == Some(vec![])
- }
-
- pub fn remove(&mut self, element: &RenderedElement) {
- 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);
- }
- }
- }
-
- pub fn push_front(&mut self, element: &RenderedElement) {
- if let Some(child_elements) = self.child_elements.as_mut() {
- child_elements.insert(0, element.clone());
- }
- }
-
- 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)
- {
- child_elements.insert(index + 1, element.clone());
- } else {
- child_elements.push(element.clone());
- }
- }
- }
-
- pub fn handle_action(
- &self,
- element_tree: Option<&mut RenderedElement>,
- action: Action,
- ) -> Result<(), Error> {
- 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) => {
- element_tree.remove(self);
-
- let new_parent = element_tree.find_by_id(id).unwrap();
- new_parent.push_front(self);
-
- Ok(())
- }
- Action::InsertAfter(parent_id, target_id) => {
- element_tree.remove(self);
-
- let new_parent = element_tree.find_by_id(parent_id).unwrap();
- new_parent.insert_after(target_id, self);
-
- Ok(())
- }
- }
- }
-
- fn preset_options(mut self, options: &[&str]) -> Self {
- for opt in options {
- let _ = self.options.insert(opt.to_string(), None);
- }
- self
- }
-
- 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
- }
-
- pub fn into_element<'a>(self) -> Element<'a, Message> {
- let mut children = widget::column![];
-
- if let Some(els) = self.child_elements.clone() {
- for el in els {
- children = children.push(el.clone().into_element());
- }
- }
- iced_drop::droppable(
- widget::container(
- 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)
- })
- .into()
- }
-
- pub fn codegen(&self) -> (String, String) {
- let mut imports = String::new();
- let mut view = String::new();
- let mut options = String::new();
-
- for (k, v) in self.options.clone() {
- if let Some(v) = v {
- options = format!("{options}.{k}({v})");
- }
- }
-
- let mut elements = String::new();
-
- if let Some(els) = &self.child_elements {
- for element in els {
- let (c_imports, children) = element.codegen();
- imports = format!("{imports}{c_imports}");
- elements = format!("{elements}{children},");
- }
- }
-
- match &self.name {
- ElementName::Container => {
- imports = format!("{imports}container,");
- view = format!("{view}\ncontainer({elements}){options}");
- }
- ElementName::Row => {
- imports = format!("{imports}row,");
- view = format!("{view}\nrow![{elements}]{options}");
- }
- ElementName::Column => {
- imports = format!("{imports}column,");
- view = format!("{view}\ncolumn![{elements}]{options}");
- }
- ElementName::Text(string) => {
- imports = format!("{imports}text,");
- view = format!(
- "{view}\ntext(\"{}\"){options}",
- if *string == String::new() {
- "New Text"
- } else {
- string
- }
- );
- }
- ElementName::Button(string) => {
- imports = format!("{imports}button,");
- view = format!(
- "{view}\nbutton(\"{}\"){options}",
- if *string == String::new() {
- "New Button"
- } else {
- string
- }
- );
- }
- ElementName::Image(path) => {
- imports = format!("{imports}image,");
- view = format!("{view}\nimage(\"{path}\"){options}");
- }
- ElementName::Svg(path) => {
- imports = format!("{imports}svg,");
- view = format!("{view}\nsvg(\"{path}\"){options}");
- }
- }
-
- (imports, view)
- }
-}
-
-impl std::fmt::Display for RenderedElement {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let mut has_options = false;
- f.pad("")?;
- f.write_fmt(format_args!("{:?}\n", self.name))?;
- f.pad("")?;
- f.write_str("Options: (")?;
- for (k, v) in &self.options {
- if let Some(value) = v {
- has_options = true;
- f.write_fmt(format_args!(
- "\n{:width$.precision$}{}: {}",
- "",
- k,
- value,
- width = f.width().unwrap_or(0) + f.precision().unwrap_or(0),
- precision = f.precision().unwrap_or(0)
- ))?;
- }
- }
- if has_options {
- f.write_str("\n")?;
- f.pad("")?;
- }
- f.write_str(")")?;
- if let Some(els) = &self.child_elements {
- f.write_str(" {\n")?;
- for el in els {
- f.write_fmt(format_args!(
- "\n{:width$.precision$}\n",
- el,
- width = f.width().unwrap_or(0) + f.precision().unwrap_or(0),
- precision = f.precision().unwrap_or(0)
- ))?;
- }
- f.pad("")?;
- f.write_str("}")?;
- }
- Ok(())
- }
-}
-
-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_vec(
- child_elements.into_iter().map(Into::into).collect(),
- )
- .padding(20)
- .into(),
- ElementName::Column => widget::Column::from_vec(
- child_elements.into_iter().map(Into::into).collect(),
- )
- .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<'a> {
- AddNew,
- PushFront(&'a Id),
- InsertAfter(&'a Id, &'a Id),
- Drop,
- Stop,
-}
-
-impl<'a> Action<'a> {
- pub fn new(
- ids: &'a [Id],
- element_tree: &'a Option<RenderedElement>,
- source_id: Option<Id>,
- ) -> Self {
- let mut action = Self::Stop;
- 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()];
- if ids.len() > 2 && &ids[ids.len() - 1] == element_id {
- return Self::Stop;
- }
- element_id
- }
- _ => ids.last().unwrap(),
- };
- let mut element_tree = element_tree.clone().unwrap();
- let element = element_tree.find_by_id(id).unwrap();
-
- // Element is a parent and isn't a non-empty container
- if (element.is_empty() || !(element.name == ElementName::Container))
- && element.is_parent()
- {
- action = Self::PushFront(id);
- } else if ids.len() > 2 {
- let parent =
- element_tree.find_by_id(&ids[ids.len() - 2]).unwrap();
-
- if parent.name == ElementName::Container
- && parent.child_elements != Some(vec![])
- {
- action = Self::Stop;
- } else {
- action = Self::InsertAfter(
- &ids[ids.len() - 2],
- &ids[ids.len() - 1],
- );
- }
- }
- }
- action
- }
-}
-
-pub fn text(text: &str) -> RenderedElement {
- RenderedElement::new(ElementName::Text(text.to_owned())).preset_options(&[
- "size",
- "line_height",
- "width",
- "height",
- ])
-}
-
-pub fn button(text: &str) -> RenderedElement {
- RenderedElement::new(ElementName::Button(text.to_owned()))
-}
-
-pub fn svg(path: &str) -> RenderedElement {
- RenderedElement::new(ElementName::Svg(path.to_owned()))
-}
-
-pub fn image(path: &str) -> RenderedElement {
- RenderedElement::new(ElementName::Image(path.to_owned()))
-}
-
-pub fn container(content: Option<RenderedElement>) -> RenderedElement {
- match content {
- Some(el) => RenderedElement::with(ElementName::Container, vec![el]),
- None => RenderedElement::with(ElementName::Container, vec![]),
- }
-}
-
-pub fn row(child_elements: Option<Vec<RenderedElement>>) -> RenderedElement {
- RenderedElement::with(ElementName::Row, child_elements.unwrap_or_default())
-}
-
-pub fn column(child_elements: Option<Vec<RenderedElement>>) -> RenderedElement {
- RenderedElement::with(
- ElementName::Column,
- child_elements.unwrap_or_default(),
- )
-}