diff options
| author | Polesznyák Márk László <116908301+pml68@users.noreply.github.com> | 2025-04-29 23:35:39 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-29 23:35:39 +0200 |
| commit | ca50c308f0058af80e9125ba00a1349877169968 (patch) | |
| tree | 38fbd5c78c90487e5b641f635d01c4a614ddfd44 /src/types | |
| parent | Merge pull request #14 from pml68/dependabot/cargo/windows_exe_info-0.5.1 (diff) | |
| parent | style: `theme` -> `appearance` (diff) | |
| download | iced-builder-ca50c308f0058af80e9125ba00a1349877169968.tar.gz | |
Merge pull request #20 from pml68/feat/custom-theme
Diffstat (limited to 'src/types')
| -rw-r--r-- | src/types/project.rs | 70 | ||||
| -rwxr-xr-x | src/types/rendered_element.rs | 158 |
2 files changed, 111 insertions, 117 deletions
diff --git a/src/types/project.rs b/src/types/project.rs index 721783e..11789ac 100644 --- a/src/types/project.rs +++ b/src/types/project.rs @@ -1,24 +1,19 @@ use std::path::{Path, PathBuf}; -use std::sync::Arc; 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::Error; -use crate::config::Config; -use crate::theme::{theme_from_str, theme_index, theme_to_string}; +use crate::appearance::iced_theme_from_str; #[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 { @@ -33,45 +28,24 @@ impl Project { title: None, theme: None, element_tree: None, - theme_cache: FxHashMap::default(), } } - pub fn get_theme(&self, config: &Config) -> Theme { + pub fn get_theme(&self) -> Theme { match &self.theme { - Some(theme) => theme_from_str(Some(config), theme), - None => Theme::default(), + Some(theme) => iced_theme_from_str(theme), + None => iced::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: Arc<Config>, - ) -> Result<(PathBuf, Self), Error> { + pub async fn from_path(path: PathBuf) -> 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)); + let project: Self = serde_json::from_str(&contents)?; Ok((path, project)) } - pub async fn from_file( - config: Arc<Config>, - ) -> Result<(PathBuf, Self), Error> { + 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"]) @@ -81,7 +55,7 @@ impl Project { let path = picked_file.path().to_owned(); - Self::from_path(path, config).await + Self::from_path(path).await } pub async fn write_to_file( @@ -108,28 +82,21 @@ impl Project { Ok(path) } - pub fn app_code(&mut self, config: &Config) -> Result<String, Error> { - match self.element_tree { + pub fn app_code(&mut self) -> Result<String, Error> { + use iced::debug; + let codegen = debug::time("Code Generation"); + + let result = 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,Warning,Pair}}}}}};\n"; - } else { - theme_imports = "use iced::{{color,theme::Palette}};\n"; - } - } + let theme = self.get_theme(); 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() + iced::application(State::default, State::update, State::view).title("{}").theme(State::theme).run() }} #[derive(Default)] @@ -153,7 +120,7 @@ impl State {{ Some(ref t) => t, None => "New app", }, - theme_code + theme.to_string().replace(" ", "") ); let config = rust_format::Config::new_str() .edition(Edition::Rust2021) @@ -163,6 +130,9 @@ impl State {{ Ok(rustfmt.format_str(app_code)?) } None => Err("No element tree present".into()), - } + }; + + codegen.finish(); + result } } diff --git a/src/types/rendered_element.rs b/src/types/rendered_element.rs index 0a78dcd..020aa46 100755 --- a/src/types/rendered_element.rs +++ b/src/types/rendered_element.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use iced::advanced::widget::Id; -use iced::{Element, Length, widget}; +use iced::{Element, widget}; use serde::{Deserialize, Serialize}; use crate::Error; @@ -171,34 +171,6 @@ impl RenderedElement { self } - pub fn text_view<'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().text_view()); - } - } - 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.id().clone()) - .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(); @@ -223,7 +195,14 @@ impl RenderedElement { match &self.name { ElementName::Container => { imports = format!("{imports}container,"); - view = format!("{view}\ncontainer({elements}){options}"); + view = format!( + "{view}\ncontainer({}){options}", + if elements.is_empty() { + String::from("\"\"") + } else { + elements.to_string() + } + ); } ElementName::Row => { imports = format!("{imports}row,"); @@ -237,7 +216,7 @@ impl RenderedElement { imports = format!("{imports}text,"); view = format!( "{view}\ntext(\"{}\"){options}", - if *string == String::new() { + if string.is_empty() { "New Text" } else { string @@ -248,7 +227,7 @@ impl RenderedElement { imports = format!("{imports}button,"); view = format!( "{view}\nbutton(\"{}\"){options}", - if *string == String::new() { + if string.is_empty() { "New Button" } else { string @@ -317,53 +296,98 @@ impl<'a> From<RenderedElement> for Element<'a, Message> { let child_elements = copy.child_elements.unwrap_or_default(); let content: Element<'a, Message> = match copy.name { - ElementName::Text(s) => { - if s.is_empty() { - widget::text("New Text").apply_options(copy.options).into() - } else { - widget::text(s).apply_options(copy.options).into() - } - } - ElementName::Button(s) => { - if s.is_empty() { - widget::button(widget::text("New Button")) - .apply_options(copy.options) - .into() - } else { - widget::button(widget::text(s)) - .apply_options(copy.options) - .into() - } + ElementName::Text(s) => if s.is_empty() { + widget::text("New Text") + } else { + widget::text(s) } + .apply_options(copy.options) + .into(), + ElementName::Button(s) => widget::button(if s.is_empty() { + widget::text("New Button") + } else { + widget::text(s) + }) + .apply_options(copy.options) + .into(), ElementName::Svg(p) => { widget::svg(p).apply_options(copy.options).into() } ElementName::Image(p) => { widget::image(p).apply_options(copy.options).into() } - ElementName::Container => { - widget::container(if child_elements.len() == 1 { - child_elements[0].clone().into() - } else { - Element::from("") - }) - .apply_options(copy.options) - .padding(20) - .into() + ElementName::Container => if child_elements.len() == 1 { + widget::container(child_elements[0].clone()) + } else { + widget::container("New Container").style( + |theme: &iced::Theme| widget::container::Style { + border: iced::Border { + color: theme.palette().text, + + width: 2.0, + radius: 4.into(), + }, + ..Default::default() + }, + ) } - ElementName::Row => widget::Row::from_vec( - child_elements.into_iter().map(Into::into).collect(), - ) - .padding(20) - .apply_options(copy.options) - .into(), - ElementName::Column => widget::Column::from_vec( - child_elements.into_iter().map(Into::into).collect(), - ) .padding(20) .apply_options(copy.options) .into(), + ElementName::Row => { + if !child_elements.is_empty() { + widget::Row::with_children( + child_elements.into_iter().map(Into::into), + ) + .padding(20) + .apply_options(copy.options) + .into() + } else { + widget::container( + widget::row!["New Row"] + .padding(20) + .apply_options(copy.options), + ) + .style(|theme: &iced::Theme| widget::container::Style { + border: iced::Border { + color: theme.palette().text, + + width: 2.0, + radius: 4.into(), + }, + ..Default::default() + }) + .into() + } + } + ElementName::Column => { + if !child_elements.is_empty() { + widget::Column::with_children( + child_elements.into_iter().map(Into::into), + ) + .padding(20) + .apply_options(copy.options) + .into() + } else { + widget::container( + widget::column!["New Column"] + .padding(20) + .apply_options(copy.options), + ) + .style(|theme: &iced::Theme| widget::container::Style { + border: iced::Border { + color: theme.palette().text, + + width: 2.0, + radius: 4.into(), + }, + ..Default::default() + }) + .into() + } + } }; + iced_drop::droppable(content) .id(value.id().clone()) .drag_hide(true) |
