diff options
| author | pml68 <contact@pml68.me> | 2024-10-30 03:00:17 +0100 |
|---|---|---|
| committer | pml68 <contact@pml68.me> | 2024-10-30 03:00:17 +0100 |
| commit | 87e745b8e60225a789b51d5011fa620051c4cfbe (patch) | |
| tree | 6bf3cede25ee428939500038439508415d636f45 /iced_builder | |
| parent | feat: implement very basic playground (diff) | |
| download | iced-builder-87e745b8e60225a789b51d5011fa620051c4cfbe.tar.gz | |
feat: add error dialogs, windows manifest
Diffstat (limited to '')
| -rw-r--r-- | iced_builder/Cargo.toml | 12 | ||||
| -rw-r--r-- | iced_builder/assets/windows/iced_builder.manifest | 8 | ||||
| -rw-r--r-- | iced_builder/assets/windows/iced_builder.rc | 3 | ||||
| -rw-r--r-- | iced_builder/build.rs | 7 | ||||
| -rw-r--r-- | iced_builder/src/error.rs | 61 | ||||
| -rw-r--r-- | iced_builder/src/lib.rs | 78 | ||||
| -rw-r--r-- | iced_builder/src/main.rs | 55 | ||||
| -rw-r--r-- | iced_builder/src/types/element_name.rs | 2 | ||||
| -rw-r--r-- | iced_builder/src/types/mod.rs | 33 | ||||
| -rw-r--r-- | iced_builder/src/types/project.rs | 14 | ||||
| -rwxr-xr-x | iced_builder/src/types/rendered_element.rs | 2 | ||||
| -rw-r--r-- | iced_builder/src/views/code_view.rs | 2 | ||||
| -rw-r--r-- | iced_builder/src/views/designer_view.rs | 5 | ||||
| -rw-r--r-- | iced_builder/src/views/element_list.rs | 2 |
14 files changed, 168 insertions, 116 deletions
diff --git a/iced_builder/Cargo.toml b/iced_builder/Cargo.toml index d08d485..e62f965 100644 --- a/iced_builder/Cargo.toml +++ b/iced_builder/Cargo.toml @@ -12,15 +12,19 @@ keywords = ["gui", "iced"] iced = { version = "0.13.1", features = [ "image","svg","canvas","qr_code","advanced","tokio","highlighter"] } iced_aw = { version = "0.11.0", default-features = false, features = ["menu","color_picker"] } iced_drop = { path = "../iced_drop" } -serde = { version = "1.0.210", features = ["derive"] } -serde_json = "1.0.128" -tokio = { version = "1.40.0", features = ["fs"] } -rfd = "0.15.0" +serde = { version = "1.0.214", features = ["derive"] } +serde_json = "1.0.132" +tokio = { version = "1.41.0", features = ["fs"] } +rfd = { version = "0.15.0", default-features = false, features = ["async-std", "gtk3"] } rust-format = "0.3.4" unique_id = "0.1.5" indexmap = { version = "2.6.0", features = ["serde"] } thiserror = "1.0.65" +[target.'cfg(windows)'.build-dependencies] +embed-resource = "2.5.0" +windows_exe_info = "0.4" + [[bin]] name = "iced-builder" path = "src/main.rs" diff --git a/iced_builder/assets/windows/iced_builder.manifest b/iced_builder/assets/windows/iced_builder.manifest new file mode 100644 index 0000000..82039bf --- /dev/null +++ b/iced_builder/assets/windows/iced_builder.manifest @@ -0,0 +1,8 @@ +<?xml version='1.0' encoding='UTF-8' standalone='yes'?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" > + <asmv3:application> + <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings"> + <dpiAwareness>PerMonitorV2, unaware</dpiAwareness> + </asmv3:windowsSettings> + </asmv3:application> +</assembly> diff --git a/iced_builder/assets/windows/iced_builder.rc b/iced_builder/assets/windows/iced_builder.rc new file mode 100644 index 0000000..7255b65 --- /dev/null +++ b/iced_builder/assets/windows/iced_builder.rc @@ -0,0 +1,3 @@ +#define RT_MANIFEST 24 + +1 RT_MANIFEST "iced_builder.manifest" diff --git a/iced_builder/build.rs b/iced_builder/build.rs new file mode 100644 index 0000000..75261f8 --- /dev/null +++ b/iced_builder/build.rs @@ -0,0 +1,7 @@ +fn main() { + #[cfg(windows)] + { + embed_resource::compile("assets/windows/iced_builder.rc", embed_resource::NONE); + windows_exe_info::versioninfo::link_cargo_env(); + } +} diff --git a/iced_builder/src/error.rs b/iced_builder/src/error.rs new file mode 100644 index 0000000..5bf41b1 --- /dev/null +++ b/iced_builder/src/error.rs @@ -0,0 +1,61 @@ +use rfd::{MessageButtons, MessageDialog, MessageLevel}; +use std::io; +use thiserror::Error; + +#[derive(Debug, Clone, Error)] +pub enum Error { + #[error("An I/O error accured: {0}")] + IOError(String), + #[error("A Serde error accured: {0}")] + SerdeError(String), + #[error("A RustFmt error accured: {0}")] + FormatError(String), + #[error("The element tree contains no matching element")] + NonExistentElement, + #[error("The file dialog has been closed without selecting a valid option")] + DialogClosed, + #[error("{0}")] + Other(String), +} + +impl From<io::Error> for Error { + fn from(value: io::Error) -> Self { + Self::IOError(value.to_string()) + } +} + +impl From<serde_json::Error> for Error { + fn from(value: serde_json::Error) -> Self { + Self::SerdeError(value.to_string()) + } +} + +impl From<rust_format::Error> for Error { + fn from(value: rust_format::Error) -> Self { + Self::FormatError(value.to_string()) + } +} + +impl From<&'static str> for Error { + fn from(value: &'static str) -> Self { + Self::Other(value.to_owned()) + } +} + +pub fn error_dialog(description: impl Into<String>) { + MessageDialog::new() + .set_level(MessageLevel::Error) + .set_buttons(MessageButtons::Ok) + .set_title("Oops! Something went wrong.") + .set_description(description) + .show(); +} + +pub fn warning_dialog(title: impl Into<String>, description: impl Into<String>) { + MessageDialog::new() + .set_level(MessageLevel::Warning) + .set_buttons(MessageButtons::Ok) + .set_title(title) + .set_description(description) + .show(); +} diff --git a/iced_builder/src/lib.rs b/iced_builder/src/lib.rs index c6f3616..ddb080c 100644 --- a/iced_builder/src/lib.rs +++ b/iced_builder/src/lib.rs @@ -1,79 +1,5 @@ +pub mod error; pub mod types; pub mod views; -use std::{io, path::PathBuf}; - -use iced::widget::{pane_grid, text_editor}; -use types::{ - element_name::ElementName, project::Project, rendered_element::RenderedElement, DesignerPage, -}; - -use thiserror::Error; - -#[derive(Debug, Clone, Error)] -pub enum Error { - #[error("an I/O error accured: {0}")] - IOError(String), - #[error("a Serde error accured: {0}")] - SerdeError(String), - #[error("an RustFmt error accured: {0}")] - FormatError(String), - #[error("the element tree contains no matching element")] - NonExistentElement, - #[error("the file dialog has been closed without selecting a valid option")] - DialogClosed, - #[error("{0}")] - Other(String), -} - -impl From<io::Error> for Error { - fn from(value: io::Error) -> Self { - Self::IOError(value.to_string()) - } -} - -impl From<serde_json::Error> for Error { - fn from(value: serde_json::Error) -> Self { - Self::SerdeError(value.to_string()) - } -} - -impl From<rust_format::Error> for Error { - fn from(value: rust_format::Error) -> Self { - Self::FormatError(value.to_string()) - } -} - -impl From<&'static str> for Error { - fn from(value: &'static str) -> Self { - Self::Other(value.to_owned()) - } -} - -#[derive(Debug, Clone)] -pub enum Message { - ToggleDarkMode, - CopyCode, - SwitchPage(DesignerPage), - EditorAction(text_editor::Action), - RefreshEditorContent, - DropNewElement(ElementName, iced::Point, iced::Rectangle), - HandleNew( - ElementName, - Vec<(iced::advanced::widget::Id, iced::Rectangle)>, - ), - MoveElement(RenderedElement, iced::Point, iced::Rectangle), - HandleMove( - RenderedElement, - Vec<(iced::advanced::widget::Id, iced::Rectangle)>, - ), - PaneResized(pane_grid::ResizeEvent), - PaneClicked(pane_grid::Pane), - PaneDragged(pane_grid::DragEvent), - NewFile, - OpenFile, - FileOpened(Result<(PathBuf, Project), Error>), - SaveFile, - SaveFileAs, - FileSaved(Result<PathBuf, Error>), -} +pub type Result<T> = std::result::Result<T, error::Error>; diff --git a/iced_builder/src/main.rs b/iced_builder/src/main.rs index d022f29..bbf01c5 100644 --- a/iced_builder/src/main.rs +++ b/iced_builder/src/main.rs @@ -11,9 +11,9 @@ use iced::{ Alignment, Element, Length, Settings, Task, Theme, }; use iced_builder::{ - types::{Action, DesignerPage, ElementName, Project}, + error::error_dialog, + types::{Action, DesignerPage, ElementName, Message, Project}, views::{code_view, designer_view, element_list}, - Message, }; fn main() -> iced::Result { @@ -109,14 +109,12 @@ impl App { self.editor_content.perform(action); } } - Message::RefreshEditorContent => { - let code = self - .project - .clone() - .app_code() - .unwrap_or_else(|err| err.to_string()); - self.editor_content = text_editor::Content::with_text(&code); - } + Message::RefreshEditorContent => match self.project.clone().app_code() { + Ok(code) => { + self.editor_content = text_editor::Content::with_text(&code); + } + Err(error) => error_dialog(error.to_string()), + }, Message::DropNewElement(name, point, _) => { return iced_drop::zones_on_point( move |zones| Message::HandleNew(name.clone(), zones), @@ -131,8 +129,10 @@ impl App { if ids.len() > 0 { let action = Action::new(ids, &mut self.project.element_tree.clone(), None); let result = name.handle_action(self.project.element_tree.as_mut(), action); - if let Ok(Some(ref element)) = result { - self.project.element_tree = Some(element.clone()); + match result { + Ok(Some(ref element)) => self.project.element_tree = Some(element.clone()), + Err(error) => error_dialog(error.to_string()), + _ => {} } self.is_dirty = true; @@ -157,7 +157,10 @@ impl App { &mut self.project.element_tree.clone(), Some(element.get_id()), ); - let _ = element.handle_action(self.project.element_tree.as_mut(), action); + let result = element.handle_action(self.project.element_tree.as_mut(), action); + if let Err(error) = result { + error_dialog(error.to_string()); + } self.is_dirty = true; } @@ -185,19 +188,22 @@ impl App { if !self.is_loading && !self.is_dirty { self.is_loading = true; - return Task::perform(Project::from_file(), Message::FileOpened); + return Task::perform(Project::from_path(), Message::FileOpened); } } Message::FileOpened(result) => { self.is_loading = false; self.is_dirty = false; - if let Ok((path, project)) = result { - self.project = project.clone(); - self.project_path = Some(path); - self.editor_content = text_editor::Content::with_text( - &project.app_code().unwrap_or_else(|err| err.to_string()), - ); + match result { + Ok((path, project)) => { + self.project = project.clone(); + self.project_path = Some(path); + self.editor_content = text_editor::Content::with_text( + &project.app_code().unwrap_or_else(|err| err.to_string()), + ); + } + Err(error) => error_dialog(error.to_string()), } } Message::SaveFile => { @@ -225,9 +231,12 @@ impl App { Message::FileSaved(result) => { self.is_loading = false; - if let Ok(path) = result { - self.project_path = Some(path); - self.is_dirty = false; + match result { + Ok(path) => { + self.project_path = Some(path); + self.is_dirty = false; + } + Err(error) => error_dialog(error.to_string()), } } } diff --git a/iced_builder/src/types/element_name.rs b/iced_builder/src/types/element_name.rs index bf38120..d71ae30 100644 --- a/iced_builder/src/types/element_name.rs +++ b/iced_builder/src/types/element_name.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::Error; +use crate::error::Error; use super::rendered_element::{ button, column, container, image, row, svg, text, Action, RenderedElement, diff --git a/iced_builder/src/types/mod.rs b/iced_builder/src/types/mod.rs index 0012905..841b255 100644 --- a/iced_builder/src/types/mod.rs +++ b/iced_builder/src/types/mod.rs @@ -6,6 +6,39 @@ pub use element_name::ElementName; pub use project::Project; pub use rendered_element::*; +use std::path::PathBuf; + +use crate::error::Error; +use iced::widget::{pane_grid, text_editor}; + +#[derive(Debug, Clone)] +pub enum Message { + ToggleDarkMode, + CopyCode, + SwitchPage(DesignerPage), + EditorAction(text_editor::Action), + RefreshEditorContent, + DropNewElement(ElementName, iced::Point, iced::Rectangle), + HandleNew( + ElementName, + Vec<(iced::advanced::widget::Id, iced::Rectangle)>, + ), + MoveElement(RenderedElement, iced::Point, iced::Rectangle), + HandleMove( + RenderedElement, + Vec<(iced::advanced::widget::Id, iced::Rectangle)>, + ), + PaneResized(pane_grid::ResizeEvent), + PaneClicked(pane_grid::Pane), + PaneDragged(pane_grid::DragEvent), + NewFile, + OpenFile, + FileOpened(Result<(PathBuf, Project), Error>), + SaveFile, + SaveFileAs, + FileSaved(Result<PathBuf, Error>), +} + #[derive(Debug, Clone)] pub enum DesignerPage { Designer, diff --git a/iced_builder/src/types/project.rs b/iced_builder/src/types/project.rs index 52da41c..8d24a75 100644 --- a/iced_builder/src/types/project.rs +++ b/iced_builder/src/types/project.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use iced::Theme; use serde::{Deserialize, Serialize}; -use crate::Error; +use crate::error::Error; use super::rendered_element::RenderedElement; @@ -55,10 +55,10 @@ impl Project { } } - pub async fn from_file() -> Result<(PathBuf, Self), Error> { + pub async fn from_path() -> Result<(PathBuf, Self), Error> { 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)?; @@ -77,7 +77,7 @@ impl Project { } 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() @@ -103,7 +103,7 @@ impl Project { {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 3dad8e7..58fd18d 100755 --- a/iced_builder/src/types/rendered_element.rs +++ b/iced_builder/src/types/rendered_element.rs @@ -5,7 +5,7 @@ use iced::{widget, Element, Length}; use serde::{Deserialize, Serialize}; use unique_id::{string::StringGenerator, Generator}; -use crate::{Error, Message}; +use crate::{error::Error, types::Message}; use super::ElementName; diff --git a/iced_builder/src/views/code_view.rs b/iced_builder/src/views/code_view.rs index 4515687..e872e3d 100644 --- a/iced_builder/src/views/code_view.rs +++ b/iced_builder/src/views/code_view.rs @@ -1,5 +1,5 @@ use super::style; -use crate::{types::DesignerPage, Message}; +use crate::types::{DesignerPage, Message}; use iced::{ highlighter, widget::{button, container, pane_grid, row, text, text_editor, tooltip, Space}, diff --git a/iced_builder/src/views/designer_view.rs b/iced_builder/src/views/designer_view.rs index 2d88493..1f7de88 100644 --- a/iced_builder/src/views/designer_view.rs +++ b/iced_builder/src/views/designer_view.rs @@ -1,8 +1,5 @@ use super::style; -use crate::{ - types::{DesignerPage, RenderedElement}, - Message, -}; +use crate::types::{DesignerPage, Message, RenderedElement}; use iced::{ widget::{button, container, pane_grid, row, text, themer, Space}, Alignment, Element, Length, diff --git a/iced_builder/src/views/element_list.rs b/iced_builder/src/views/element_list.rs index a9aeb1f..6e78ae0 100644 --- a/iced_builder/src/views/element_list.rs +++ b/iced_builder/src/views/element_list.rs @@ -1,5 +1,5 @@ use super::style; -use crate::{types::ElementName, Message}; +use crate::types::{ElementName, Message}; use iced::{ widget::{column, container, pane_grid, text, Column}, Alignment, Element, Length, |
