summaryrefslogtreecommitdiff
path: root/iced_builder/src/types
diff options
context:
space:
mode:
authorPolesznyák Márk László <116908301+pml68@users.noreply.github.com>2025-01-11 23:13:07 +0100
committerGitHub <noreply@github.com>2025-01-11 23:13:07 +0100
commit103699beeb8bdce38bc5803cbe038e74cbc20e40 (patch)
treeb79e13b3decc778cc7c66af7187c647ae0a21a52 /iced_builder/src/types
parentMerge pull request #4 from pml68/feat/playground (diff)
parentrefactor: remove iced_drop & workspace (diff)
downloadiced-builder-103699beeb8bdce38bc5803cbe038e74cbc20e40.tar.gz
Merge pull request #5 from pml68/feat/config
Config done
Diffstat (limited to 'iced_builder/src/types')
-rw-r--r--iced_builder/src/types/element_name.rs86
-rw-r--r--iced_builder/src/types/project.rs142
-rwxr-xr-xiced_builder/src/types/rendered_element.rs482
3 files changed, 0 insertions, 710 deletions
diff --git a/iced_builder/src/types/element_name.rs b/iced_builder/src/types/element_name.rs
deleted file mode 100644
index e172227..0000000
--- a/iced_builder/src/types/element_name.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use serde::{Deserialize, Serialize};
-
-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 {
- 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>> {
- 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 => Ok(None),
- 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 f4dbcc4..0000000
--- a/iced_builder/src/types/project.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-use std::path::{Path, PathBuf};
-
-use iced::Theme;
-use rust_format::{Config, Edition, Formatter, RustFmt};
-use serde::{Deserialize, Serialize};
-
-use super::rendered_element::RenderedElement;
-use crate::{Error, Result};
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Project {
- pub title: Option<String>,
- pub theme: Option<String>,
- pub element_tree: Option<RenderedElement>,
-}
-
-impl Project {
- pub fn new() -> Self {
- Self {
- title: None,
- theme: None,
- element_tree: None,
- }
- }
-
- pub fn get_theme(&self) -> Theme {
- match &self.theme {
- Some(theme) => match theme.as_str() {
- "Light" => Theme::Light,
- "Dark" => Theme::Dark,
- "Dracula" => Theme::Dracula,
- "Nord" => Theme::Nord,
- "Solarized Light" => Theme::SolarizedLight,
- "Solarized Dark" => Theme::SolarizedDark,
- "Gruvbox Light" => Theme::GruvboxLight,
- "Gruvbox Dark" => Theme::GruvboxDark,
- "Catppuccin Latte" => Theme::CatppuccinLatte,
- "Catppuccin Frappé" => Theme::CatppuccinFrappe,
- "Catppuccin Macchiato" => Theme::CatppuccinMacchiato,
- "Catppuccin Mocha" => Theme::CatppuccinMocha,
- "Tokyo Night" => Theme::TokyoNight,
- "Tokyo Night Storm" => Theme::TokyoNightStorm,
- "Tokyo Night Light" => Theme::TokyoNightLight,
- "Kanagawa Wave" => Theme::KanagawaWave,
- "Kanagawa Dragon" => Theme::KanagawaDragon,
- "Kanagawa Lotus" => Theme::KanagawaLotus,
- "Moonfly" => Theme::Moonfly,
- "Nightfly" => Theme::Nightfly,
- "Oxocarbon" => Theme::Oxocarbon,
- "Ferra" => Theme::Ferra,
- _ => Theme::Dark,
- },
- None => Theme::Dark,
- }
- }
-
- 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"])
- .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> {
- 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(&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}};");
-
- app_code = format!(
- r#"// Automatically generated by iced Builder
- {app_code}
-
- 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",
- },
- self.get_theme().to_string().replace(" ", "")
- );
- let config = 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 d4d1a6c..0000000
--- a/iced_builder/src/types/rendered_element.rs
+++ /dev/null
@@ -1,482 +0,0 @@
-use std::collections::BTreeMap;
-
-use blob_uuid::random_blob;
-use iced::advanced::widget::Id;
-use iced::{widget, Element, Length};
-use serde::{Deserialize, Serialize};
-
-use super::ElementName;
-use crate::types::Message;
-use crate::Result;
-
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
-pub struct RenderedElement {
- id: String,
- child_elements: Option<Vec<RenderedElement>>,
- name: ElementName,
- options: BTreeMap<String, Option<String>>,
-}
-
-impl RenderedElement {
- fn new(name: ElementName) -> Self {
- Self {
- id: random_blob(),
- child_elements: None,
- name,
- options: BTreeMap::new(),
- }
- }
-
- fn with(name: ElementName, child_elements: Vec<RenderedElement>) -> Self {
- Self {
- id: random_blob(),
- child_elements: Some(child_elements),
- name,
- options: BTreeMap::new(),
- }
- }
-
- pub fn get_id(&self) -> Id {
- Id::new(self.id.clone())
- }
-
- pub fn find_by_id(&mut self, id: Id) -> Option<&mut Self> {
- if self.get_id() == id.clone() {
- 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;
- }
- }
-
- 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(vec![])
- .contains(child_element)
- {
- return Some(self);
- } else {
- 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;
- }
- }
- }
- return None;
- }
- } else {
- return 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<()> {
- 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<'a>(mut self, options: &[&'a 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 as_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().as_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_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,
-}
-
-impl Action {
- pub fn new(
- ids: Vec<Id>,
- element_tree: &mut 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()].clone();
- if ids.len() > 2 && ids[ids.clone().len() - 1] == element_id
- {
- return Self::Stop;
- }
- element_id
- }
- _ => ids.last().cloned().unwrap(),
- };
- let element = element_tree
- .as_mut()
- .unwrap()
- .find_by_id(id.clone())
- .unwrap();
-
- // Element IS a parent but ISN'T a non-empty container
- match element.is_parent()
- && !(element.name == ElementName::Container
- && !element.is_empty())
- {
- true => {
- action = Self::PushFront(id);
- }
- false if ids.len() > 2 => {
- let parent = element_tree
- .as_mut()
- .unwrap()
- .find_by_id(ids[&ids.len() - 2].clone())
- .unwrap();
-
- if parent.name == ElementName::Container
- && parent.child_elements != Some(vec![])
- {
- action = Self::Stop;
- } else {
- action = Self::InsertAfter(
- ids[&ids.len() - 2].clone(),
- ids[&ids.len() - 1].clone(),
- );
- }
- }
- _ => {}
- }
- }
- 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(),
- )
-}