From df1a28851b3d8152e1a99f840cc7f31e0d958b32 Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Wed, 15 Jan 2025 14:09:39 +0800 Subject: [PATCH 01/12] :sparkles: Read from yaml --- Cargo.toml | 4 +++- config.yml | 3 +++ src/freeeta_yml.rs | 34 ++++++++++++++++++++++++++++ src/main.rs | 3 +++ src/main_menu.rs | 56 +++++++++++++++++----------------------------- 5 files changed, 63 insertions(+), 37 deletions(-) create mode 100644 config.yml create mode 100644 src/freeeta_yml.rs diff --git a/Cargo.toml b/Cargo.toml index c49c225..d3e5213 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,6 @@ repository = "https://github.com/Administroot/FreeEta" [dependencies] iced = {version = "0.13.1", features = ["image", "svg", "tokio", "advanced"] } -tokio = {version = "1.43.0", features = ["time", "full"]} \ No newline at end of file +tokio = {version = "1.43.0", features = ["time", "full"]} +serde = "1.0" +serde_yml = "0.0.11" \ No newline at end of file diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..01e213f --- /dev/null +++ b/config.yml @@ -0,0 +1,3 @@ +name: FreeEta +lang: zh-cn +theme: Light diff --git a/src/freeeta_yml.rs b/src/freeeta_yml.rs new file mode 100644 index 0000000..521615f --- /dev/null +++ b/src/freeeta_yml.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Serialize}; +use std::fs::{self, File}; + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct FreeEtaConfig { + /// Software name: typically "FreeEta" + name: String, + /// Language: ["zh-cn", "en-us"] + lang: String, + /// Theme: Default "Light"; Others see [iced::theme::Theme](https://docs.rs/iced/0.13.1/iced/theme/enum.Theme.html) + theme: String, +} + +/// Read FreeEta config from ./ +pub fn read_freeeta_config() -> Result<(), serde_yml::Error> { + let path = "config.yml"; + if !fs::exists(path).unwrap() { + // If config doesn't exist, create a default config. + File::create(path).unwrap(); + let default_config = FreeEtaConfig { + name: "FreeEta".to_string(), + lang: "zh-cn".to_string(), + theme: "Light".to_string(), + }; + let yaml = serde_yml::to_string(&default_config)?; + fs::write(path, yaml).expect("Cannot write config.yml"); + } else { + // If config exists, read from it. + let contents = fs::read_to_string(path).expect("Cannot read config.yml"); + let deserialized_config: FreeEtaConfig = serde_yml::from_str(&contents)?; + // println!("{:?}", deserialized_config); + } + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index f7af803..5b7aa58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,16 @@ mod freeeta_styles; +mod freeeta_yml; mod main_menu; use iced; fn main() -> iced::Result { + freeeta_yml::read_freeeta_config().expect("[ERROR] CONFIG ERROR"); iced::application( "FreeEta", main_menu::FreeEta::update, main_menu::FreeEta::view, ) + .theme(main_menu::FreeEta::theme) .run() } diff --git a/src/main_menu.rs b/src/main_menu.rs index c47155e..99fb59f 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -1,6 +1,8 @@ use iced::{ - widget::{column, container, horizontal_space, pick_list, row, svg, svg::Handle}, - ContentFit, Element, Task, + widget::{ + column, container, horizontal_space, pick_list, row, svg, svg::Handle, text::Shaping, + }, + ContentFit, Element, Length, Task, }; use crate::freeeta_styles; @@ -17,7 +19,7 @@ impl Default for FreeEta { #[derive(Debug, Clone)] pub enum MainMenuMessage { - DoNothing, + FilePicklistMsg(String), } impl FreeEta { @@ -30,7 +32,13 @@ impl FreeEta { ) } - pub fn update(&mut self, _message: MainMenuMessage) -> Task { + pub fn update(&mut self, message: MainMenuMessage) -> Task { + match message { + MainMenuMessage::FilePicklistMsg(s) => { + // TODO: Divide different sections + self.file_picklist = Some(s); + } + } Task::none() } @@ -44,39 +52,11 @@ impl FreeEta { .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), - |_| MainMenuMessage::DoNothing, + |s| MainMenuMessage::FilePicklistMsg(s), ) - .placeholder("File") - .style(freeeta_styles::pick_list_unselected), - // Graphics - pick_list( - ["Other choices 1", "Other choices 2"] - .map(|s| s.to_string()) - .to_vec(), - self.file_picklist.clone(), - |_| MainMenuMessage::DoNothing, - ) - .placeholder("Graphics") - .style(freeeta_styles::pick_list_unselected), - // Tools - pick_list( - ["Other choices 1", "Other choices 2"] - .map(|s| s.to_string()) - .to_vec(), - self.file_picklist.clone(), - |_| MainMenuMessage::DoNothing, - ) - .placeholder("Tools") - .style(freeeta_styles::pick_list_unselected), - // Helps - pick_list( - ["Other choices 1", "Other choices 2"] - .map(|s| s.to_string()) - .to_vec(), - self.file_picklist.clone(), - |_| MainMenuMessage::DoNothing, - ) - .placeholder("Helps") + .width(Length::Shrink) + .placeholder("๐Ÿ“ File") + .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), // Space[ ] horizontal_space(), @@ -93,4 +73,8 @@ impl FreeEta { ) .into() } + + pub fn theme(&self) -> iced::Theme { + iced::Theme::Light + } } From 56de9aee2359d1d5fcc921242ae320aac5621001 Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Wed, 15 Jan 2025 17:27:50 +0800 Subject: [PATCH 02/12] :dizzy: Improve user interface structure --- README.md | 5 +- src/freeeta_styles.rs | 28 +++------ src/freeeta_yml.rs | 8 +-- src/main.rs | 4 +- src/main_menu.rs | 64 +++++++++++++++++--- {assets => static/svg}/calculator.svg | 0 {assets => static/svg}/code-slash.svg | 0 {assets => static/svg}/file-add.svg | 0 static/svg/get_it_on_github.svg | 55 +++++++++++++++++ {assets => static/svg}/logo.svg | 0 {assets => static/svg}/menu-boxed.svg | 0 {assets => static/svg}/more-r.svg | 0 {assets => static/svg}/shape-hexagon.svg | 0 {assets => static/svg}/software-download.svg | 0 {assets => static/svg}/software-upload.svg | 0 {assets => static/svg}/view-comfortable.svg | 0 16 files changed, 130 insertions(+), 34 deletions(-) rename {assets => static/svg}/calculator.svg (100%) rename {assets => static/svg}/code-slash.svg (100%) rename {assets => static/svg}/file-add.svg (100%) create mode 100644 static/svg/get_it_on_github.svg rename {assets => static/svg}/logo.svg (100%) rename {assets => static/svg}/menu-boxed.svg (100%) rename {assets => static/svg}/more-r.svg (100%) rename {assets => static/svg}/shape-hexagon.svg (100%) rename {assets => static/svg}/software-download.svg (100%) rename {assets => static/svg}/software-upload.svg (100%) rename {assets => static/svg}/view-comfortable.svg (100%) diff --git a/README.md b/README.md index b9b7d61..931c0bc 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,13 @@ A fast, elegant & free ETA analysis utility powered by ๐Ÿฆ€ Rust, ๐ŸงŠ iced. Get it on Github -Support windows / linux / MacOS! Or use `cargo` to try it out: +Support windows / linux / MacOS! + +Or use `cargo` to try it out: ```bash cargo install --git https://github.com/administroot/FreeEta.git +``` ## Why "FreeEta"? diff --git a/src/freeeta_styles.rs b/src/freeeta_styles.rs index 97cebdd..70bbe6d 100644 --- a/src/freeeta_styles.rs +++ b/src/freeeta_styles.rs @@ -1,24 +1,4 @@ -use iced::{border::Radius, widget::pick_list, Background, Border, Color, Theme}; - -// pub fn radio_selected(_theme: &Theme, _status: radio::Status) -> radio::Style { -// radio::Style { -// text_color: Some(Color::from_rgb(0., 0., 1.)), -// background: Background::Color(Color::from_rgb(1., 1., 1.)), -// dot_color: Color::from_rgb(0., 0., 1.), -// border_width: 1.0, -// border_color: Color::from_rgb(0., 0., 1.), -// } -// } - -// pub fn radio_unselected(_theme: &Theme, _status: radio::Status) -> radio::Style { -// radio::Style { -// text_color: Some(Color::from_rgb(0.5, 0.5, 0.5)), -// background: Background::Color(Color::from_rgb(1., 1., 1.)), -// dot_color: Color::from_rgb(0., 0., 1.), -// border_width: 1.0, -// border_color: Color::from_rgb(0., 0., 1.), -// } -// } +use iced::{border::Radius, widget::{pick_list, text}, Background, Border, Color, Theme}; // TODO: Read Theme from const in the future. pub fn pick_list_unselected(_theme: &Theme, _status: pick_list::Status) -> pick_list::Style { @@ -39,3 +19,9 @@ pub fn pick_list_unselected(_theme: &Theme, _status: pick_list::Status) -> pick_ }, } } + +pub fn bottomline_text_unselected(_theme: &Theme) -> text::Style { + text::Style { + color: Some(Color::from_rgb(0.35, 0.35, 0.34)), + } +} \ No newline at end of file diff --git a/src/freeeta_yml.rs b/src/freeeta_yml.rs index 521615f..65fc34e 100644 --- a/src/freeeta_yml.rs +++ b/src/freeeta_yml.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use std::fs::{self, File}; #[derive(Debug, Serialize, Deserialize, PartialEq)] -struct FreeEtaConfig { +pub struct FreeEtaConfig { /// Software name: typically "FreeEta" name: String, /// Language: ["zh-cn", "en-us"] @@ -12,7 +12,7 @@ struct FreeEtaConfig { } /// Read FreeEta config from ./ -pub fn read_freeeta_config() -> Result<(), serde_yml::Error> { +pub fn read_freeeta_config() -> Result { let path = "config.yml"; if !fs::exists(path).unwrap() { // If config doesn't exist, create a default config. @@ -24,11 +24,11 @@ pub fn read_freeeta_config() -> Result<(), serde_yml::Error> { }; let yaml = serde_yml::to_string(&default_config)?; fs::write(path, yaml).expect("Cannot write config.yml"); + return Ok(default_config); } else { // If config exists, read from it. let contents = fs::read_to_string(path).expect("Cannot read config.yml"); let deserialized_config: FreeEtaConfig = serde_yml::from_str(&contents)?; - // println!("{:?}", deserialized_config); + return Ok(deserialized_config); } - Ok(()) } diff --git a/src/main.rs b/src/main.rs index 5b7aa58..0130958 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,9 @@ mod main_menu; use iced; fn main() -> iced::Result { - freeeta_yml::read_freeeta_config().expect("[ERROR] CONFIG ERROR"); + let freeeta_yml = freeeta_yml::read_freeeta_config().expect("[ERROR] CONFIG ERROR"); + // TODO: Deal with the config struct. + println!("{:?}", freeeta_yml); iced::application( "FreeEta", main_menu::FreeEta::update, diff --git a/src/main_menu.rs b/src/main_menu.rs index 99fb59f..1830bc8 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -1,8 +1,7 @@ use iced::{ - widget::{ - column, container, horizontal_space, pick_list, row, svg, svg::Handle, text::Shaping, - }, - ContentFit, Element, Length, Task, + alignment, widget::{ + column, container, horizontal_rule, horizontal_space, pick_list, row, svg::Handle, svg, text::Shaping, text, vertical_space + }, Color, ContentFit, Element, Length, Task }; use crate::freeeta_styles; @@ -48,7 +47,7 @@ impl FreeEta { row![ // File pick_list( - ["Other choices 1", "Other choices 2"] + ["๐Ÿ†• New.. ", "๐Ÿ“‚ Open..", "๐Ÿ”Ž Open Recent", "๐Ÿ’พ Save", "๐Ÿ“ค Export"] .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), @@ -58,18 +57,69 @@ impl FreeEta { .placeholder("๐Ÿ“ File") .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), + + // Graphics + pick_list( + // TODO: Please use container[svg/png] + ["โ›ฝ Pop", "๐ŸŒ€ Valve", "Add more..."] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::FilePicklistMsg(s), + ) + .width(Length::Shrink) + .placeholder("๐Ÿ’  Graphics") + .text_shaping(Shaping::Advanced) + .style(freeeta_styles::pick_list_unselected), + + // Analysis + pick_list( + ["๐ŸŒฒ Draw ETA Tree", "๐Ÿ“‰ Calculate Success & Failure Rates"] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::FilePicklistMsg(s), + ) + .width(Length::Shrink) + .placeholder("๐Ÿงญ Analysis") + .text_shaping(Shaping::Advanced) + .style(freeeta_styles::pick_list_unselected), + + // Help + pick_list( + ["๐Ÿ“” FreeEta Handbook", "๐Ÿ—ฃ๏ธ Language", "๐ŸŒ About FreeEta", "๐ŸงŠ About ICED"] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::FilePicklistMsg(s), + ) + .width(Length::Shrink) + .placeholder(" Help") + .text_shaping(Shaping::Advanced) + .style(freeeta_styles::pick_list_unselected), + // Space[ ] horizontal_space(), // FreeEta logo container( - svg(Handle::from_path("assets/logo.svg")) + svg(Handle::from_path("static/svg/logo.svg")) .width(32.) .height(32.) .content_fit(ContentFit::ScaleDown) ) .padding(0u16) .style(container::rounded_box) - ] + ], + horizontal_rule(0), + // TODO: Replace it with canvas view. + vertical_space(), + // Bottom row + horizontal_rule(0), + row![ + text(" Mouse Point:{x: 20, y: 30} ").color(Color::from_rgb(0.96, 0.31, 0.64)), + text("| Copyrightยฉ๏ธShanghai Justlinking Safety Technology co.,ltd. \ + Administroot ").style(freeeta_styles::bottomline_text_unselected).align_x(alignment::Horizontal::Center) + ].align_y(alignment::Vertical::Bottom) ) .into() } diff --git a/assets/calculator.svg b/static/svg/calculator.svg similarity index 100% rename from assets/calculator.svg rename to static/svg/calculator.svg diff --git a/assets/code-slash.svg b/static/svg/code-slash.svg similarity index 100% rename from assets/code-slash.svg rename to static/svg/code-slash.svg diff --git a/assets/file-add.svg b/static/svg/file-add.svg similarity index 100% rename from assets/file-add.svg rename to static/svg/file-add.svg diff --git a/static/svg/get_it_on_github.svg b/static/svg/get_it_on_github.svg new file mode 100644 index 0000000..5398824 --- /dev/null +++ b/static/svg/get_it_on_github.svg @@ -0,0 +1,55 @@ + + + + + + + + + + image/svg+xml + + + + + Andrew Nayenko + + + + + https://f-droid.org + + + + + + + + + + + + + + + + + + + + + + GET IT ON + GitHub + + + + + + + + + + + + diff --git a/assets/logo.svg b/static/svg/logo.svg similarity index 100% rename from assets/logo.svg rename to static/svg/logo.svg diff --git a/assets/menu-boxed.svg b/static/svg/menu-boxed.svg similarity index 100% rename from assets/menu-boxed.svg rename to static/svg/menu-boxed.svg diff --git a/assets/more-r.svg b/static/svg/more-r.svg similarity index 100% rename from assets/more-r.svg rename to static/svg/more-r.svg diff --git a/assets/shape-hexagon.svg b/static/svg/shape-hexagon.svg similarity index 100% rename from assets/shape-hexagon.svg rename to static/svg/shape-hexagon.svg diff --git a/assets/software-download.svg b/static/svg/software-download.svg similarity index 100% rename from assets/software-download.svg rename to static/svg/software-download.svg diff --git a/assets/software-upload.svg b/static/svg/software-upload.svg similarity index 100% rename from assets/software-upload.svg rename to static/svg/software-upload.svg diff --git a/assets/view-comfortable.svg b/static/svg/view-comfortable.svg similarity index 100% rename from assets/view-comfortable.svg rename to static/svg/view-comfortable.svg From 1d341b1e0b5ebc3917eaf9faa1d8a0abcb940963 Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Wed, 15 Jan 2025 21:37:51 +0800 Subject: [PATCH 03/12] :sparkles: Add point function --- src/freeeta_styles.rs | 8 +++-- src/main.rs | 1 + src/main_menu.rs | 72 +++++++++++++++++++++++++++++++++---------- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/freeeta_styles.rs b/src/freeeta_styles.rs index 70bbe6d..7d1bff7 100644 --- a/src/freeeta_styles.rs +++ b/src/freeeta_styles.rs @@ -1,4 +1,8 @@ -use iced::{border::Radius, widget::{pick_list, text}, Background, Border, Color, Theme}; +use iced::{ + border::Radius, + widget::{pick_list, text}, + Background, Border, Color, Theme, +}; // TODO: Read Theme from const in the future. pub fn pick_list_unselected(_theme: &Theme, _status: pick_list::Status) -> pick_list::Style { @@ -24,4 +28,4 @@ pub fn bottomline_text_unselected(_theme: &Theme) -> text::Style { text::Style { color: Some(Color::from_rgb(0.35, 0.35, 0.34)), } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 0130958..863b63f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,5 +14,6 @@ fn main() -> iced::Result { main_menu::FreeEta::view, ) .theme(main_menu::FreeEta::theme) + .subscription(main_menu::FreeEta::subscription) .run() } diff --git a/src/main_menu.rs b/src/main_menu.rs index 1830bc8..cde8fda 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -1,13 +1,20 @@ use iced::{ - alignment, widget::{ - column, container, horizontal_rule, horizontal_space, pick_list, row, svg::Handle, svg, text::Shaping, text, vertical_space - }, Color, ContentFit, Element, Length, Task + alignment, + event::{self, Status}, + mouse::Event::CursorMoved, + touch::Event::FingerMoved, + widget::{ + column, container, horizontal_rule, horizontal_space, pick_list, row, svg, svg::Handle, + text, text::Shaping, vertical_space, + }, + Color, ContentFit, Element, Event, Length, Point, Subscription, Task, }; use crate::freeeta_styles; pub struct FreeEta { file_picklist: Option, + mouse_point: Point, } impl Default for FreeEta { @@ -19,6 +26,7 @@ impl Default for FreeEta { #[derive(Debug, Clone)] pub enum MainMenuMessage { FilePicklistMsg(String), + PointUpdated(Point), } impl FreeEta { @@ -26,6 +34,7 @@ impl FreeEta { ( Self { file_picklist: None, + mouse_point: Point::ORIGIN, }, Task::none(), ) @@ -37,6 +46,9 @@ impl FreeEta { // TODO: Divide different sections self.file_picklist = Some(s); } + MainMenuMessage::PointUpdated(p) => { + self.mouse_point = p; + } } Task::none() } @@ -47,9 +59,15 @@ impl FreeEta { row![ // File pick_list( - ["๐Ÿ†• New.. ", "๐Ÿ“‚ Open..", "๐Ÿ”Ž Open Recent", "๐Ÿ’พ Save", "๐Ÿ“ค Export"] - .map(|s| s.to_string()) - .to_vec(), + [ + "๐Ÿ†• New.. ", + "๐Ÿ“‚ Open..", + "๐Ÿ”Ž Open Recent", + "๐Ÿ’พ Save", + "๐Ÿ“ค Export" + ] + .map(|s| s.to_string()) + .to_vec(), self.file_picklist.clone(), |s| MainMenuMessage::FilePicklistMsg(s), ) @@ -57,7 +75,6 @@ impl FreeEta { .placeholder("๐Ÿ“ File") .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), - // Graphics pick_list( // TODO: Please use container[svg/png] @@ -71,7 +88,6 @@ impl FreeEta { .placeholder("๐Ÿ’  Graphics") .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), - // Analysis pick_list( ["๐ŸŒฒ Draw ETA Tree", "๐Ÿ“‰ Calculate Success & Failure Rates"] @@ -84,12 +100,16 @@ impl FreeEta { .placeholder("๐Ÿงญ Analysis") .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), - // Help pick_list( - ["๐Ÿ“” FreeEta Handbook", "๐Ÿ—ฃ๏ธ Language", "๐ŸŒ About FreeEta", "๐ŸงŠ About ICED"] - .map(|s| s.to_string()) - .to_vec(), + [ + "๐Ÿ“” FreeEta Handbook", + "๐Ÿ—ฃ๏ธ Language", + "๐ŸŒ About FreeEta", + "๐ŸงŠ About ICED" + ] + .map(|s| s.to_string()) + .to_vec(), self.file_picklist.clone(), |s| MainMenuMessage::FilePicklistMsg(s), ) @@ -97,7 +117,6 @@ impl FreeEta { .placeholder(" Help") .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), - // Space[ ] horizontal_space(), // FreeEta logo @@ -116,10 +135,15 @@ impl FreeEta { // Bottom row horizontal_rule(0), row![ - text(" Mouse Point:{x: 20, y: 30} ").color(Color::from_rgb(0.96, 0.31, 0.64)), - text("| Copyrightยฉ๏ธShanghai Justlinking Safety Technology co.,ltd. \ - Administroot ").style(freeeta_styles::bottomline_text_unselected).align_x(alignment::Horizontal::Center) - ].align_y(alignment::Vertical::Bottom) + text(format!("{:?}", self.mouse_point)).color(Color::from_rgb(0.96, 0.31, 0.64)), + text( + "| CopyrightยฉShanghai Justlinking Safety Technology co.,ltd. \ + Administroot " + ) + .style(freeeta_styles::bottomline_text_unselected) + .align_x(alignment::Horizontal::Center) + ] + .align_y(alignment::Vertical::Bottom) ) .into() } @@ -127,4 +151,18 @@ impl FreeEta { pub fn theme(&self) -> iced::Theme { iced::Theme::Light } + + pub fn subscription(&self) -> Subscription { + event::listen_with(|event, status, _window| { + match (event, status) { + // Using mouse + (Event::Mouse(CursorMoved { position }), Status::Ignored) + // Or using touchboard + | (Event::Touch(FingerMoved {position, ..}), Status::Ignored) => { + Some(MainMenuMessage::PointUpdated(position)) + } + _ => None + } + }) + } } From fac7602c91bef2558c5a2517fd70188d03a5665f Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Fri, 17 Jan 2025 19:29:19 +0800 Subject: [PATCH 04/12] :lipstick: Add `Settings` module & try `bookmark` widgets --- .gitignore | 5 +++- src/bookmark.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/main_menu.rs | 51 ++++++++++++++++++++++++++++----- 4 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 src/bookmark.rs diff --git a/.gitignore b/.gitignore index d01bd1a..0b58c0b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,7 @@ Cargo.lock # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file +#.idea/ + +# Test binaries +*.exe \ No newline at end of file diff --git a/src/bookmark.rs b/src/bookmark.rs new file mode 100644 index 0000000..c9e891a --- /dev/null +++ b/src/bookmark.rs @@ -0,0 +1,73 @@ +use iced::advanced::layout::{self, Layout}; +use iced::advanced::renderer; +use iced::advanced::widget::{self, Widget}; +use iced::border; +use iced::mouse; +use iced::{Color, Element, Length, Rectangle, Size}; + +pub struct Bookmark { + color: Color, +} + +impl Bookmark { + pub fn new(color: Color) -> Self { + Self { color } + } +} + +pub fn custom_bookmark(color: Color) -> Bookmark { + Bookmark::new(color) +} + +impl Widget for Bookmark +where + Renderer: renderer::Renderer, +{ + fn size(&self) -> Size { + Size { + width: Length::Shrink, + height: Length::Shrink, + } + } + + fn layout( + &self, + _tree: &mut widget::Tree, + _renderer: &Renderer, + _limits: &layout::Limits, + ) -> layout::Node { + // widget{x: 120.0, y: 55.0} when screen{x: 1535.2, y: 191.2} + // TODO: pub fn get_size(id: Id) -> Task + layout::Node::new(Size::new(400., 400.)) + } + + fn draw( + &self, + _state: &widget::Tree, + renderer: &mut Renderer, + _theme: &Theme, + _style: &renderer::Style, + layout: Layout<'_>, + _cursor: mouse::Cursor, + _viewport: &Rectangle, + ) { + renderer.fill_quad( + renderer::Quad { + bounds: layout.bounds(), + border: border::rounded(200.), + ..renderer::Quad::default() + }, + self.color, + ); + } +} + +impl<'a, Message, Theme, Renderer> From + for Element<'a, Message, Theme, Renderer> +where + Renderer: renderer::Renderer, +{ + fn from(circle: Bookmark) -> Self { + Self::new(circle) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 863b63f..9124726 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod freeeta_styles; mod freeeta_yml; mod main_menu; +mod bookmark; use iced; diff --git a/src/main_menu.rs b/src/main_menu.rs index cde8fda..f85457a 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -5,14 +5,16 @@ use iced::{ touch::Event::FingerMoved, widget::{ column, container, horizontal_rule, horizontal_space, pick_list, row, svg, svg::Handle, - text, text::Shaping, vertical_space, + text, text::Shaping, vertical_space }, Color, ContentFit, Element, Event, Length, Point, Subscription, Task, }; use crate::freeeta_styles; +use crate::bookmark; pub struct FreeEta { + // TODO: Actually, I don't need this member. file_picklist: Option, mouse_point: Point, } @@ -26,6 +28,10 @@ impl Default for FreeEta { #[derive(Debug, Clone)] pub enum MainMenuMessage { FilePicklistMsg(String), + GraphicsPicklistMsg(String), + AnalysisPicklistMsg(String), + SettingsPicklistMsg(String), + HelpPicklistMsg(String), PointUpdated(Point), } @@ -49,6 +55,22 @@ impl FreeEta { MainMenuMessage::PointUpdated(p) => { self.mouse_point = p; } + MainMenuMessage::GraphicsPicklistMsg(s) => { + // TODO: Divide different sections + self.file_picklist = Some(s); + }, + MainMenuMessage::AnalysisPicklistMsg(s) => { + // TODO: Divide different sections + self.file_picklist = Some(s); + }, + MainMenuMessage::SettingsPicklistMsg(s) => { + // TODO: Divide different sections + self.file_picklist = Some(s); + }, + MainMenuMessage::HelpPicklistMsg(s) => { + // TODO: Divide different sections + self.file_picklist = Some(s); + }, } Task::none() } @@ -78,11 +100,11 @@ impl FreeEta { // Graphics pick_list( // TODO: Please use container[svg/png] - ["โ›ฝ Pop", "๐ŸŒ€ Valve", "Add more..."] + ["โ›ฝ Pop", "๐ŸŒ€ Valve", "โž• Add more..."] .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), - |s| MainMenuMessage::FilePicklistMsg(s), + |s| MainMenuMessage::GraphicsPicklistMsg(s), ) .width(Length::Shrink) .placeholder("๐Ÿ’  Graphics") @@ -94,27 +116,39 @@ impl FreeEta { .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), - |s| MainMenuMessage::FilePicklistMsg(s), + |s| MainMenuMessage::AnalysisPicklistMsg(s), ) .width(Length::Shrink) .placeholder("๐Ÿงญ Analysis") .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), + // Settings + pick_list( + ["๐Ÿ”ฎ Themes", "๐Ÿ—ฃ๏ธ Languages"] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::SettingsPicklistMsg(s), + ) + .width(Length::Shrink) + .placeholder("โš™๏ธ Settings") + .text_shaping(Shaping::Advanced) + .style(freeeta_styles::pick_list_unselected), + // Help pick_list( [ "๐Ÿ“” FreeEta Handbook", - "๐Ÿ—ฃ๏ธ Language", "๐ŸŒ About FreeEta", "๐ŸงŠ About ICED" ] .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), - |s| MainMenuMessage::FilePicklistMsg(s), + |s| MainMenuMessage::HelpPicklistMsg(s), ) .width(Length::Shrink) - .placeholder(" Help") + .placeholder("๐Ÿค Help") .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), // Space[ ] @@ -132,6 +166,9 @@ impl FreeEta { horizontal_rule(0), // TODO: Replace it with canvas view. vertical_space(), + row![bookmark::custom_bookmark(Color::BLACK)].align_y(alignment::Vertical::Center), + vertical_space(), + // Bottom row horizontal_rule(0), row![ From f046dabd6e7202a65070b943814c259d62b4ad0f Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Sun, 19 Jan 2025 22:38:13 +0800 Subject: [PATCH 05/12] :lipstick: Draw bookmark.svg & add them to view --- src/bookmark.rs | 8 +++---- src/freeeta_styles.rs | 19 ++++++++++++--- src/main.rs | 2 +- src/main_menu.rs | 44 +++++++++++++++++++++-------------- static/png/Bookmark_View.png | Bin 0 -> 3805 bytes 5 files changed, 47 insertions(+), 26 deletions(-) create mode 100644 static/png/Bookmark_View.png diff --git a/src/bookmark.rs b/src/bookmark.rs index c9e891a..9fc10de 100644 --- a/src/bookmark.rs +++ b/src/bookmark.rs @@ -15,6 +15,7 @@ impl Bookmark { } } +#[allow(dead_code)] pub fn custom_bookmark(color: Color) -> Bookmark { Bookmark::new(color) } @@ -25,6 +26,7 @@ where { fn size(&self) -> Size { Size { + // widget{x: 120.0, y: 55.0} when screen{x: 1535.2, y: 191.2} width: Length::Shrink, height: Length::Shrink, } @@ -36,7 +38,6 @@ where _renderer: &Renderer, _limits: &layout::Limits, ) -> layout::Node { - // widget{x: 120.0, y: 55.0} when screen{x: 1535.2, y: 191.2} // TODO: pub fn get_size(id: Id) -> Task layout::Node::new(Size::new(400., 400.)) } @@ -62,12 +63,11 @@ where } } -impl<'a, Message, Theme, Renderer> From - for Element<'a, Message, Theme, Renderer> +impl<'a, Message, Theme, Renderer> From for Element<'a, Message, Theme, Renderer> where Renderer: renderer::Renderer, { fn from(circle: Bookmark) -> Self { Self::new(circle) } -} \ No newline at end of file +} diff --git a/src/freeeta_styles.rs b/src/freeeta_styles.rs index 7d1bff7..41d0de4 100644 --- a/src/freeeta_styles.rs +++ b/src/freeeta_styles.rs @@ -1,7 +1,7 @@ use iced::{ - border::Radius, - widget::{pick_list, text}, - Background, Border, Color, Theme, + border::{rounded, Radius}, + widget::{container, pick_list, text}, + Background, Border, Color, Shadow, Theme, Vector, }; // TODO: Read Theme from const in the future. @@ -29,3 +29,16 @@ pub fn bottomline_text_unselected(_theme: &Theme) -> text::Style { color: Some(Color::from_rgb(0.35, 0.35, 0.34)), } } + +pub fn shadowed_container(_theme: &Theme) -> container::Style { + container::Style { + shadow: Shadow { + color: Color::from_rgb(0., 0., 0.), + offset: Vector { x: 0., y: 0. }, + blur_radius: 8., + }, + background: Some(Background::Color(Color::from_rgba(255., 255., 255., 0.))), + border: rounded(20.), + ..Default::default() + } +} diff --git a/src/main.rs b/src/main.rs index 9124726..a73b3bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ +mod bookmark; mod freeeta_styles; mod freeeta_yml; mod main_menu; -mod bookmark; use iced; diff --git a/src/main_menu.rs b/src/main_menu.rs index f85457a..26002b6 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -4,14 +4,13 @@ use iced::{ mouse::Event::CursorMoved, touch::Event::FingerMoved, widget::{ - column, container, horizontal_rule, horizontal_space, pick_list, row, svg, svg::Handle, - text, text::Shaping, vertical_space + column, container, horizontal_rule, horizontal_space, image, pick_list, row, svg, + svg::Handle, text, text::Shaping, vertical_space, }, Color, ContentFit, Element, Event, Length, Point, Subscription, Task, }; use crate::freeeta_styles; -use crate::bookmark; pub struct FreeEta { // TODO: Actually, I don't need this member. @@ -58,19 +57,19 @@ impl FreeEta { MainMenuMessage::GraphicsPicklistMsg(s) => { // TODO: Divide different sections self.file_picklist = Some(s); - }, + } MainMenuMessage::AnalysisPicklistMsg(s) => { // TODO: Divide different sections self.file_picklist = Some(s); - }, + } MainMenuMessage::SettingsPicklistMsg(s) => { // TODO: Divide different sections self.file_picklist = Some(s); - }, + } MainMenuMessage::HelpPicklistMsg(s) => { // TODO: Divide different sections self.file_picklist = Some(s); - }, + } } Task::none() } @@ -134,16 +133,11 @@ impl FreeEta { .placeholder("โš™๏ธ Settings") .text_shaping(Shaping::Advanced) .style(freeeta_styles::pick_list_unselected), - // Help pick_list( - [ - "๐Ÿ“” FreeEta Handbook", - "๐ŸŒ About FreeEta", - "๐ŸงŠ About ICED" - ] - .map(|s| s.to_string()) - .to_vec(), + ["๐Ÿ“” FreeEta Handbook", "๐ŸŒ About FreeEta", "๐ŸงŠ About ICED"] + .map(|s| s.to_string()) + .to_vec(), self.file_picklist.clone(), |s| MainMenuMessage::HelpPicklistMsg(s), ) @@ -164,11 +158,25 @@ impl FreeEta { .style(container::rounded_box) ], horizontal_rule(0), - // TODO: Replace it with canvas view. vertical_space(), - row![bookmark::custom_bookmark(Color::BLACK)].align_y(alignment::Vertical::Center), + // Body + // TODO: Replace it with canvas view. + container( + column![ + row![ + // FIXME: Need to define a custom widget! + image("static/png/Bookmark_View").content_fit(ContentFit::ScaleDown) + ], + // horizontal_space(), + // text("Middle"), + // horizontal_space(), + // text("Right"), + ] + .align_x(alignment::Horizontal::Left) + ) + .style(freeeta_styles::shadowed_container) + .align_x(alignment::Horizontal::Left), vertical_space(), - // Bottom row horizontal_rule(0), row![ diff --git a/static/png/Bookmark_View.png b/static/png/Bookmark_View.png new file mode 100644 index 0000000000000000000000000000000000000000..8114e52ace20ba6e1aa3010f29dd2c6da769cedc GIT binary patch literal 3805 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 TKbA$o00000NkvXXu0mjfJ<&s! literal 0 HcmV?d00001 From 749d92bd7bb6c032851400e838f8383f9ba2349c Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Wed, 22 Jan 2025 14:58:35 +0800 Subject: [PATCH 06/12] :art: Eliminate redundant code of widgets --- src/bookmark.rs | 73 ------------------------------------- src/freeeta_buttons.rs | 61 +++++++++++++++++++++++++++++++ src/freeeta_picklists.rs | 28 +++++++++++++++ src/freeeta_styles.rs | 43 +++++++++++++++++++--- src/main.rs | 3 +- src/main_menu.rs | 78 ++++++++++++++++++++-------------------- src/pages.rs | 67 ++++++++++++++++++++++++++++++++++ 7 files changed, 237 insertions(+), 116 deletions(-) delete mode 100644 src/bookmark.rs create mode 100644 src/freeeta_buttons.rs create mode 100644 src/freeeta_picklists.rs create mode 100644 src/pages.rs diff --git a/src/bookmark.rs b/src/bookmark.rs deleted file mode 100644 index 9fc10de..0000000 --- a/src/bookmark.rs +++ /dev/null @@ -1,73 +0,0 @@ -use iced::advanced::layout::{self, Layout}; -use iced::advanced::renderer; -use iced::advanced::widget::{self, Widget}; -use iced::border; -use iced::mouse; -use iced::{Color, Element, Length, Rectangle, Size}; - -pub struct Bookmark { - color: Color, -} - -impl Bookmark { - pub fn new(color: Color) -> Self { - Self { color } - } -} - -#[allow(dead_code)] -pub fn custom_bookmark(color: Color) -> Bookmark { - Bookmark::new(color) -} - -impl Widget for Bookmark -where - Renderer: renderer::Renderer, -{ - fn size(&self) -> Size { - Size { - // widget{x: 120.0, y: 55.0} when screen{x: 1535.2, y: 191.2} - width: Length::Shrink, - height: Length::Shrink, - } - } - - fn layout( - &self, - _tree: &mut widget::Tree, - _renderer: &Renderer, - _limits: &layout::Limits, - ) -> layout::Node { - // TODO: pub fn get_size(id: Id) -> Task - layout::Node::new(Size::new(400., 400.)) - } - - fn draw( - &self, - _state: &widget::Tree, - renderer: &mut Renderer, - _theme: &Theme, - _style: &renderer::Style, - layout: Layout<'_>, - _cursor: mouse::Cursor, - _viewport: &Rectangle, - ) { - renderer.fill_quad( - renderer::Quad { - bounds: layout.bounds(), - border: border::rounded(200.), - ..renderer::Quad::default() - }, - self.color, - ); - } -} - -impl<'a, Message, Theme, Renderer> From for Element<'a, Message, Theme, Renderer> -where - Renderer: renderer::Renderer, -{ - fn from(circle: Bookmark) -> Self { - Self::new(circle) - } -} diff --git a/src/freeeta_buttons.rs b/src/freeeta_buttons.rs new file mode 100644 index 0000000..6b6be50 --- /dev/null +++ b/src/freeeta_buttons.rs @@ -0,0 +1,61 @@ +use crate::freeeta_styles; +use crate::main_menu::MainMenuMessage; +use iced::widget::text::LineHeight; +use iced::widget::tooltip::Position; +use iced::widget::{button, Text, Tooltip}; +use iced::{Alignment, Color, Font, Pixels, Theme}; + +#[allow(dead_code)] +/// Button 'ร—' +pub fn button_hide<'a>( + message: MainMenuMessage, + font: Font, +) -> Tooltip<'a, MainMenuMessage, Theme> { + Tooltip::new( + button( + Text::new("ร—") + .font(font) + .align_y(Alignment::Center) + .align_x(Alignment::Center) + .size(15) + .line_height(LineHeight::Relative(1.0)), + ) + .padding(2) + .height(20) + .width(20) + .on_press(message), + Text::new("Cancel").font(font), + Position::Right, + ) + .gap(5) +} + +/// Bookmark +pub fn bookmark<'a>( + message: MainMenuMessage, + font: Font, + inner_text: &str, + color: Color, +) -> Tooltip<'a, MainMenuMessage, Theme> { + let bookmark = Tooltip::new( + button( + Text::new(inner_text.to_string()) + .font(font) + .align_y(Alignment::Center) + .align_x(Alignment::Center) + // .size(15) + .line_height(LineHeight::Relative(1.0)), + ) + .style(move |theme, status| freeeta_styles::bookmark_style(theme, status, color)) + .padding(2) + .height(40) + .width(80) + .on_press(message), + Text::new("Press to active / deactive") + .font(font) + .size(Pixels { 0: 15f32 }), + Position::Right, + ) + .gap(5); + return bookmark; +} diff --git a/src/freeeta_picklists.rs b/src/freeeta_picklists.rs new file mode 100644 index 0000000..796a2e9 --- /dev/null +++ b/src/freeeta_picklists.rs @@ -0,0 +1,28 @@ +use std::borrow::Borrow; + +use iced::widget::pick_list; +use iced::{ + widget::{text::Shaping, PickList}, + Length, +}; + +/// Picklist to select functions. +pub fn functional_picklist<'a, T, L, V, Message, Theme, Renderer>( + options: L, + selected: Option, + on_selected: impl Fn(T) -> Message + 'a, + placeholder: &str, +) -> PickList<'a, T, L, V, Message, Theme, Renderer> +where + T: ToString + PartialEq + Clone + 'a, + L: Borrow<[T]> + 'a, + V: Borrow + 'a, + Message: Clone, + Theme: iced::widget::pick_list::Catalog + iced::widget::overlay::menu::Catalog, + Renderer: iced::advanced::text::Renderer, +{ + pick_list::<'a, T, L, V, Message, Theme, Renderer>(options, selected, on_selected) + .width(Length::Shrink) + .placeholder(placeholder) + .text_shaping(Shaping::Advanced) +} diff --git a/src/freeeta_styles.rs b/src/freeeta_styles.rs index 41d0de4..85c2ddd 100644 --- a/src/freeeta_styles.rs +++ b/src/freeeta_styles.rs @@ -1,11 +1,11 @@ use iced::{ border::{rounded, Radius}, - widget::{container, pick_list, text}, + widget::{button, container, pick_list, text}, Background, Border, Color, Shadow, Theme, Vector, }; // TODO: Read Theme from const in the future. -pub fn pick_list_unselected(_theme: &Theme, _status: pick_list::Status) -> pick_list::Style { +pub fn functional_picklist_style(_theme: &Theme, _status: pick_list::Status) -> pick_list::Style { pick_list::Style { text_color: Color::from_rgb(0.09, 0.02, 0.08), placeholder_color: Color::from_rgb(0.09, 0.02, 0.08), @@ -33,12 +33,47 @@ pub fn bottomline_text_unselected(_theme: &Theme) -> text::Style { pub fn shadowed_container(_theme: &Theme) -> container::Style { container::Style { shadow: Shadow { - color: Color::from_rgb(0., 0., 0.), + color: Color::BLACK, offset: Vector { x: 0., y: 0. }, blur_radius: 8., }, - background: Some(Background::Color(Color::from_rgba(255., 255., 255., 0.))), + background: Some(Background::Color(Color::BLACK)), border: rounded(20.), ..Default::default() } } + +/// Returns the average of two colors; color intensity is fixed to 100% +fn mix_colors(color_1: Color, color_2: Color) -> Color { + Color { + r: (color_1.r + color_2.r) / 2.0, + g: (color_1.g + color_2.g) / 2.0, + b: (color_1.b + color_2.b) / 2.0, + a: 1.0, + } +} + +pub fn bookmark_style(_theme: &Theme, status: button::Status, color: Color) -> button::Style { + match status { + button::Status::Active => button::Style { + background: Some(Background::Color(color)), + text_color: Color::BLACK, + ..Default::default() + }, + button::Status::Hovered => button::Style { + background: Some(Background::Color(mix_colors(Color::WHITE, color))), + text_color: Color::BLACK, + ..Default::default() + }, + button::Status::Pressed => button::Style { + background: Some(Background::Color(color)), + text_color: Color::BLACK, + ..Default::default() + }, + button::Status::Disabled => button::Style { + background: Some(Background::Color(mix_colors(Color::TRANSPARENT, color))), + text_color: Color::BLACK, + ..Default::default() + }, + } +} diff --git a/src/main.rs b/src/main.rs index a73b3bd..7b6c43c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ -mod bookmark; +mod freeeta_buttons; +mod freeeta_picklists; mod freeeta_styles; mod freeeta_yml; mod main_menu; diff --git a/src/main_menu.rs b/src/main_menu.rs index 26002b6..845f884 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -1,16 +1,16 @@ +use iced::widget::{svg, text}; use iced::{ alignment, event::{self, Status}, mouse::Event::CursorMoved, touch::Event::FingerMoved, widget::{ - column, container, horizontal_rule, horizontal_space, image, pick_list, row, svg, - svg::Handle, text, text::Shaping, vertical_space, + column, container, horizontal_rule, horizontal_space, row, svg::Handle, vertical_space, }, - Color, ContentFit, Element, Event, Length, Point, Subscription, Task, + Color, ContentFit, Element, Event, Font, Point, Subscription, Task, }; -use crate::freeeta_styles; +use crate::{freeeta_buttons, freeeta_picklists::functional_picklist, freeeta_styles}; pub struct FreeEta { // TODO: Actually, I don't need this member. @@ -32,6 +32,7 @@ pub enum MainMenuMessage { SettingsPicklistMsg(String), HelpPicklistMsg(String), PointUpdated(Point), + DoNothing, } impl FreeEta { @@ -70,6 +71,7 @@ impl FreeEta { // TODO: Divide different sections self.file_picklist = Some(s); } + MainMenuMessage::DoNothing => {} } Task::none() } @@ -79,7 +81,7 @@ impl FreeEta { // Funtion row row![ // File - pick_list( + functional_picklist( [ "๐Ÿ†• New.. ", "๐Ÿ“‚ Open..", @@ -91,60 +93,50 @@ impl FreeEta { .to_vec(), self.file_picklist.clone(), |s| MainMenuMessage::FilePicklistMsg(s), + "๐Ÿ“ File" ) - .width(Length::Shrink) - .placeholder("๐Ÿ“ File") - .text_shaping(Shaping::Advanced) - .style(freeeta_styles::pick_list_unselected), + .style(freeeta_styles::functional_picklist_style), // Graphics - pick_list( - // TODO: Please use container[svg/png] + functional_picklist( + // FIXME: Better use container[svg/png] ["โ›ฝ Pop", "๐ŸŒ€ Valve", "โž• Add more..."] .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), |s| MainMenuMessage::GraphicsPicklistMsg(s), + "๐Ÿ’  Graphics" ) - .width(Length::Shrink) - .placeholder("๐Ÿ’  Graphics") - .text_shaping(Shaping::Advanced) - .style(freeeta_styles::pick_list_unselected), + .style(freeeta_styles::functional_picklist_style), // Analysis - pick_list( + functional_picklist( ["๐ŸŒฒ Draw ETA Tree", "๐Ÿ“‰ Calculate Success & Failure Rates"] .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), |s| MainMenuMessage::AnalysisPicklistMsg(s), + "๐Ÿงญ Analysis" ) - .width(Length::Shrink) - .placeholder("๐Ÿงญ Analysis") - .text_shaping(Shaping::Advanced) - .style(freeeta_styles::pick_list_unselected), + .style(freeeta_styles::functional_picklist_style), // Settings - pick_list( + functional_picklist( ["๐Ÿ”ฎ Themes", "๐Ÿ—ฃ๏ธ Languages"] .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), |s| MainMenuMessage::SettingsPicklistMsg(s), + "โš™๏ธ Settings" ) - .width(Length::Shrink) - .placeholder("โš™๏ธ Settings") - .text_shaping(Shaping::Advanced) - .style(freeeta_styles::pick_list_unselected), + .style(freeeta_styles::functional_picklist_style), // Help - pick_list( + functional_picklist( ["๐Ÿ“” FreeEta Handbook", "๐ŸŒ About FreeEta", "๐ŸงŠ About ICED"] .map(|s| s.to_string()) .to_vec(), self.file_picklist.clone(), |s| MainMenuMessage::HelpPicklistMsg(s), + "๐Ÿค Help" ) - .width(Length::Shrink) - .placeholder("๐Ÿค Help") - .text_shaping(Shaping::Advanced) - .style(freeeta_styles::pick_list_unselected), + .style(freeeta_styles::functional_picklist_style), // Space[ ] horizontal_space(), // FreeEta logo @@ -163,14 +155,24 @@ impl FreeEta { // TODO: Replace it with canvas view. container( column![ - row![ - // FIXME: Need to define a custom widget! - image("static/png/Bookmark_View").content_fit(ContentFit::ScaleDown) - ], - // horizontal_space(), - // text("Middle"), - // horizontal_space(), - // text("Right"), + freeeta_buttons::bookmark( + MainMenuMessage::DoNothing, + Font::default(), + "VIEW", + Color::from_rgb(0.92, 0.21, 0.36) + ), + freeeta_buttons::bookmark( + MainMenuMessage::DoNothing, + Font::default(), + "ETA", + Color::from_rgb(0., 0.64, 0.51) + ), + freeeta_buttons::bookmark( + MainMenuMessage::DoNothing, + Font::default(), + "Export", + Color::from_rgb(0.95, 0.6, 0.) + ), ] .align_x(alignment::Horizontal::Left) ) diff --git a/src/pages.rs b/src/pages.rs new file mode 100644 index 0000000..43312db --- /dev/null +++ b/src/pages.rs @@ -0,0 +1,67 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct Pages { + title: &'static str, + view: fn() -> Element<'static, Message>, +} + +impl Pages { + const LIST: &'static [Self] = &[ + Self { + title: "Centered", + view: centered, + }, + Self { + title: "Column", + view: column_, + }, + Self { + title: "Row", + view: row_, + }, + Self { + title: "Space", + view: space, + }, + Self { + title: "Application", + view: application, + }, + ]; + + fn is_first(self) -> bool { + Self::LIST.first() == Some(&self) + } + + fn is_last(self) -> bool { + Self::LIST.last() == Some(&self) + } + + fn previous(self) -> Self { + let Some(index) = Self::LIST.iter().position(|&Pages| Pages == self) else { + return self; + }; + + Self::LIST + .get(index.saturating_sub(1)) + .copied() + .unwrap_or(self) + } + + fn next(self) -> Self { + let Some(index) = Self::LIST.iter().position(|&Pages| Pages == self) else { + return self; + }; + + Self::LIST.get(index + 1).copied().unwrap_or(self) + } + + fn view(&self) -> Element { + (self.view)() + } +} + +impl Default for Pages { + fn default() -> Self { + Self::LIST[0] + } +} From 4e54afbeaf9527f652227ef28e1a0cc264ce5c34 Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Wed, 22 Jan 2025 16:37:52 +0800 Subject: [PATCH 07/12] :lipstick: Separate bookmarks --- src/freeeta_buttons.rs | 2 -- src/freeeta_styles.rs | 45 ++++++++++++++++++++++++++++++++++++++---- src/main_menu.rs | 2 +- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/freeeta_buttons.rs b/src/freeeta_buttons.rs index 6b6be50..3da15bf 100644 --- a/src/freeeta_buttons.rs +++ b/src/freeeta_buttons.rs @@ -43,11 +43,9 @@ pub fn bookmark<'a>( .font(font) .align_y(Alignment::Center) .align_x(Alignment::Center) - // .size(15) .line_height(LineHeight::Relative(1.0)), ) .style(move |theme, status| freeeta_styles::bookmark_style(theme, status, color)) - .padding(2) .height(40) .width(80) .on_press(message), diff --git a/src/freeeta_styles.rs b/src/freeeta_styles.rs index 85c2ddd..9043e0f 100644 --- a/src/freeeta_styles.rs +++ b/src/freeeta_styles.rs @@ -30,6 +30,7 @@ pub fn bottomline_text_unselected(_theme: &Theme) -> text::Style { } } +#[allow(dead_code)] pub fn shadowed_container(_theme: &Theme) -> container::Style { container::Style { shadow: Shadow { @@ -54,26 +55,62 @@ fn mix_colors(color_1: Color, color_2: Color) -> Color { } pub fn bookmark_style(_theme: &Theme, status: button::Status, color: Color) -> button::Style { + let text_color = Color::BLACK; + let border = Border { + color, + width: 2., + radius: Radius { + top_left: 0., + top_right: 5., + bottom_right: 5., + bottom_left: 0., + }, + }; + match status { button::Status::Active => button::Style { background: Some(Background::Color(color)), - text_color: Color::BLACK, + text_color, + border, ..Default::default() }, button::Status::Hovered => button::Style { background: Some(Background::Color(mix_colors(Color::WHITE, color))), - text_color: Color::BLACK, + text_color, + border, ..Default::default() }, button::Status::Pressed => button::Style { background: Some(Background::Color(color)), - text_color: Color::BLACK, + text_color, + border, ..Default::default() }, button::Status::Disabled => button::Style { background: Some(Background::Color(mix_colors(Color::TRANSPARENT, color))), - text_color: Color::BLACK, + text_color, + border, ..Default::default() }, } } + +#[allow(dead_code)] +// Container with right-side round border +pub fn half_rounded_container(_theme: &Theme, color: Color) -> container::Style { + container::Style { + shadow: Shadow::default(), + background: Some(Background::Color(Color::TRANSPARENT)), + border: Border { + color, + width: 2., + radius: Radius { + top_left: 0., + top_right: 5., + bottom_right: 5., + bottom_left: 0., + }, + }, + ..Default::default() + } +} diff --git a/src/main_menu.rs b/src/main_menu.rs index 845f884..8ca048e 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -174,9 +174,9 @@ impl FreeEta { Color::from_rgb(0.95, 0.6, 0.) ), ] + .spacing(10.) .align_x(alignment::Horizontal::Left) ) - .style(freeeta_styles::shadowed_container) .align_x(alignment::Horizontal::Left), vertical_space(), // Bottom row From 6fdd70117bd21c33648c5bc9e6e1c914277ea21d Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Wed, 22 Jan 2025 23:24:54 +0800 Subject: [PATCH 08/12] :art: :sparkles: Realize selected / unselected appression of bookmarks --- src/freeeta_buttons.rs | 30 ++++-- src/freeeta_styles.rs | 29 +++-- src/main_menu.rs | 236 ++++++++++++++++++++++++----------------- 3 files changed, 178 insertions(+), 117 deletions(-) diff --git a/src/freeeta_buttons.rs b/src/freeeta_buttons.rs index 3da15bf..a67ea5d 100644 --- a/src/freeeta_buttons.rs +++ b/src/freeeta_buttons.rs @@ -36,19 +36,27 @@ pub fn bookmark<'a>( font: Font, inner_text: &str, color: Color, + is_actived: bool, ) -> Tooltip<'a, MainMenuMessage, Theme> { + let mut button = button( + Text::new(inner_text.to_string()) + .font(font) + .align_y(Alignment::Center) + .align_x(Alignment::Center) + .line_height(LineHeight::Relative(1.0)), + ) + .style(move |theme, status| freeeta_styles::bookmark_style(theme, status, color, is_actived)) + .height(40) + .on_press(message); + + // Lengthen and hignlight the button when activated + button = match is_actived { + true => button.width(80), + false => button.width(60), + }; + let bookmark = Tooltip::new( - button( - Text::new(inner_text.to_string()) - .font(font) - .align_y(Alignment::Center) - .align_x(Alignment::Center) - .line_height(LineHeight::Relative(1.0)), - ) - .style(move |theme, status| freeeta_styles::bookmark_style(theme, status, color)) - .height(40) - .width(80) - .on_press(message), + button, Text::new("Press to active / deactive") .font(font) .size(Pixels { 0: 15f32 }), diff --git a/src/freeeta_styles.rs b/src/freeeta_styles.rs index 9043e0f..3c1d98f 100644 --- a/src/freeeta_styles.rs +++ b/src/freeeta_styles.rs @@ -54,7 +54,22 @@ fn mix_colors(color_1: Color, color_2: Color) -> Color { } } -pub fn bookmark_style(_theme: &Theme, status: button::Status, color: Color) -> button::Style { +/// Half transparency of the given color. +fn half_transparency(color: Color) -> Color { + Color { + r: color.r, + g: color.g, + b: color.b, + a: color.a / 2.0, + } +} + +pub fn bookmark_style( + _theme: &Theme, + status: button::Status, + color: Color, + is_actived: bool, +) -> button::Style { let text_color = Color::BLACK; let border = Border { color, @@ -67,27 +82,27 @@ pub fn bookmark_style(_theme: &Theme, status: button::Status, color: Color) -> b }, }; - match status { - button::Status::Active => button::Style { + match (status, is_actived) { + (button::Status::Active, true) => button::Style { background: Some(Background::Color(color)), text_color, border, ..Default::default() }, - button::Status::Hovered => button::Style { + (button::Status::Hovered, _) => button::Style { background: Some(Background::Color(mix_colors(Color::WHITE, color))), text_color, border, ..Default::default() }, - button::Status::Pressed => button::Style { + (button::Status::Pressed, _) => button::Style { background: Some(Background::Color(color)), text_color, border, ..Default::default() }, - button::Status::Disabled => button::Style { - background: Some(Background::Color(mix_colors(Color::TRANSPARENT, color))), + (_, _) => button::Style { + background: Some(Background::Color(half_transparency(color))), text_color, border, ..Default::default() diff --git a/src/main_menu.rs b/src/main_menu.rs index 8ca048e..177f383 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -16,6 +16,10 @@ pub struct FreeEta { // TODO: Actually, I don't need this member. file_picklist: Option, mouse_point: Point, + view_bookmark_status: bool, + eta_bookmark_status: bool, + developer_bookmark_status: bool, + export_bookmark_status: bool, } impl Default for FreeEta { @@ -32,7 +36,10 @@ pub enum MainMenuMessage { SettingsPicklistMsg(String), HelpPicklistMsg(String), PointUpdated(Point), - DoNothing, + ViewBookmarkMsg, + EtaBookmarkMsg, + DeveloperBookmarkMsg, + ExportBookmarkMsg, } impl FreeEta { @@ -41,6 +48,10 @@ impl FreeEta { Self { file_picklist: None, mouse_point: Point::ORIGIN, + view_bookmark_status: false, + eta_bookmark_status: false, + developer_bookmark_status: false, + export_bookmark_status: false, }, Task::none(), ) @@ -71,108 +82,143 @@ impl FreeEta { // TODO: Divide different sections self.file_picklist = Some(s); } - MainMenuMessage::DoNothing => {} + MainMenuMessage::ViewBookmarkMsg => { + self.view_bookmark_status = !self.view_bookmark_status; + } + MainMenuMessage::EtaBookmarkMsg => { + self.eta_bookmark_status = !self.eta_bookmark_status; + } + MainMenuMessage::DeveloperBookmarkMsg => { + self.developer_bookmark_status = !self.developer_bookmark_status; + } + MainMenuMessage::ExportBookmarkMsg => { + self.export_bookmark_status = !self.export_bookmark_status; + } } Task::none() } pub fn view(&self) -> Element { + let file_picklist = functional_picklist( + [ + "๐Ÿ†• New.. ", + "๐Ÿ“‚ Open..", + "๐Ÿ”Ž Open Recent", + "๐Ÿ’พ Save", + "๐Ÿ“ค Export", + ] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::FilePicklistMsg(s), + "๐Ÿ“ File", + ) + .style(freeeta_styles::functional_picklist_style); + let graphics_picklist = functional_picklist( + // FIXME: Better use container[svg/png] + ["โ›ฝ Pop", "๐ŸŒ€ Valve", "โž• Add more..."] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::GraphicsPicklistMsg(s), + "๐Ÿ’  Graphics", + ) + .style(freeeta_styles::functional_picklist_style); + let analysis_picklist = functional_picklist( + ["๐ŸŒฒ Draw ETA Tree", "๐Ÿ“‰ Calculate Success & Failure Rates"] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::AnalysisPicklistMsg(s), + "๐Ÿงญ Analysis", + ) + .style(freeeta_styles::functional_picklist_style); + let settings_picklist = functional_picklist( + ["๐Ÿ”ฎ Themes", "๐Ÿ—ฃ๏ธ Languages"] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::SettingsPicklistMsg(s), + "โš™๏ธ Settings", + ) + .style(freeeta_styles::functional_picklist_style); + let help_picklist = functional_picklist( + ["๐Ÿ“” FreeEta Handbook", "๐ŸŒ About FreeEta", "๐ŸงŠ About ICED"] + .map(|s| s.to_string()) + .to_vec(), + self.file_picklist.clone(), + |s| MainMenuMessage::HelpPicklistMsg(s), + "๐Ÿค Help", + ) + .style(freeeta_styles::functional_picklist_style); + + let view_bookmark = freeeta_buttons::bookmark( + MainMenuMessage::ViewBookmarkMsg, + Font::default(), + "View", + Color::from_rgb(0.92, 0.21, 0.36), + self.view_bookmark_status, + ); + let eta_bookmark = freeeta_buttons::bookmark( + MainMenuMessage::EtaBookmarkMsg, + Font::default(), + "ETA", + Color::from_rgb(0., 0.64, 0.51), + self.eta_bookmark_status, + ); + let developer_bookmark = freeeta_buttons::bookmark( + MainMenuMessage::DeveloperBookmarkMsg, + Font::default(), + "Developer", + Color::from_rgb(0.88, 0.6, 0.71), + self.developer_bookmark_status, + ); + let export_bookmark = freeeta_buttons::bookmark( + MainMenuMessage::ExportBookmarkMsg, + Font::default(), + "Export", + Color::from_rgb(0.95, 0.6, 0.), + self.export_bookmark_status, + ); + + let logo = container( + svg(Handle::from_path("static/svg/logo.svg")) + .width(32.) + .height(32.) + .content_fit(ContentFit::ScaleDown), + ) + .padding(0u16) + .style(container::rounded_box); + + let mouse_position = + text(format!("{:?}", self.mouse_point)).color(Color::from_rgb(0.96, 0.31, 0.64)); + let admonition = text( + "| CopyrightยฉShanghai Justlinking Safety Technology co.,ltd. \ + Administroot ", + ) + .style(freeeta_styles::bottomline_text_unselected) + .align_x(alignment::Horizontal::Center); + column!( - // Funtion row + // Functional row row![ - // File - functional_picklist( - [ - "๐Ÿ†• New.. ", - "๐Ÿ“‚ Open..", - "๐Ÿ”Ž Open Recent", - "๐Ÿ’พ Save", - "๐Ÿ“ค Export" - ] - .map(|s| s.to_string()) - .to_vec(), - self.file_picklist.clone(), - |s| MainMenuMessage::FilePicklistMsg(s), - "๐Ÿ“ File" - ) - .style(freeeta_styles::functional_picklist_style), - // Graphics - functional_picklist( - // FIXME: Better use container[svg/png] - ["โ›ฝ Pop", "๐ŸŒ€ Valve", "โž• Add more..."] - .map(|s| s.to_string()) - .to_vec(), - self.file_picklist.clone(), - |s| MainMenuMessage::GraphicsPicklistMsg(s), - "๐Ÿ’  Graphics" - ) - .style(freeeta_styles::functional_picklist_style), - // Analysis - functional_picklist( - ["๐ŸŒฒ Draw ETA Tree", "๐Ÿ“‰ Calculate Success & Failure Rates"] - .map(|s| s.to_string()) - .to_vec(), - self.file_picklist.clone(), - |s| MainMenuMessage::AnalysisPicklistMsg(s), - "๐Ÿงญ Analysis" - ) - .style(freeeta_styles::functional_picklist_style), - // Settings - functional_picklist( - ["๐Ÿ”ฎ Themes", "๐Ÿ—ฃ๏ธ Languages"] - .map(|s| s.to_string()) - .to_vec(), - self.file_picklist.clone(), - |s| MainMenuMessage::SettingsPicklistMsg(s), - "โš™๏ธ Settings" - ) - .style(freeeta_styles::functional_picklist_style), - // Help - functional_picklist( - ["๐Ÿ“” FreeEta Handbook", "๐ŸŒ About FreeEta", "๐ŸงŠ About ICED"] - .map(|s| s.to_string()) - .to_vec(), - self.file_picklist.clone(), - |s| MainMenuMessage::HelpPicklistMsg(s), - "๐Ÿค Help" - ) - .style(freeeta_styles::functional_picklist_style), - // Space[ ] + file_picklist, + graphics_picklist, + analysis_picklist, + settings_picklist, + help_picklist, horizontal_space(), - // FreeEta logo - container( - svg(Handle::from_path("static/svg/logo.svg")) - .width(32.) - .height(32.) - .content_fit(ContentFit::ScaleDown) - ) - .padding(0u16) - .style(container::rounded_box) + logo, ], horizontal_rule(0), vertical_space(), // Body - // TODO: Replace it with canvas view. container( column![ - freeeta_buttons::bookmark( - MainMenuMessage::DoNothing, - Font::default(), - "VIEW", - Color::from_rgb(0.92, 0.21, 0.36) - ), - freeeta_buttons::bookmark( - MainMenuMessage::DoNothing, - Font::default(), - "ETA", - Color::from_rgb(0., 0.64, 0.51) - ), - freeeta_buttons::bookmark( - MainMenuMessage::DoNothing, - Font::default(), - "Export", - Color::from_rgb(0.95, 0.6, 0.) - ), + view_bookmark, + eta_bookmark, + developer_bookmark, + export_bookmark, ] .spacing(10.) .align_x(alignment::Horizontal::Left) @@ -181,21 +227,13 @@ impl FreeEta { vertical_space(), // Bottom row horizontal_rule(0), - row![ - text(format!("{:?}", self.mouse_point)).color(Color::from_rgb(0.96, 0.31, 0.64)), - text( - "| CopyrightยฉShanghai Justlinking Safety Technology co.,ltd. \ - Administroot " - ) - .style(freeeta_styles::bottomline_text_unselected) - .align_x(alignment::Horizontal::Center) - ] - .align_y(alignment::Vertical::Bottom) + row![mouse_position, admonition].align_y(alignment::Vertical::Bottom) ) .into() } pub fn theme(&self) -> iced::Theme { + // TODO: Read from config struct var. iced::Theme::Light } From 99a7a0760e89574a39a3e73fba9d1773aafc4f78 Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Thu, 23 Jan 2025 14:07:57 +0800 Subject: [PATCH 09/12] :sparkles: When specify a bookmark, deactive others --- src/main_menu.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main_menu.rs b/src/main_menu.rs index 177f383..b71ff0c 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -84,15 +84,35 @@ impl FreeEta { } MainMenuMessage::ViewBookmarkMsg => { self.view_bookmark_status = !self.view_bookmark_status; + if self.view_bookmark_status { + self.eta_bookmark_status = false; + self.developer_bookmark_status = false; + self.export_bookmark_status = false; + } } MainMenuMessage::EtaBookmarkMsg => { self.eta_bookmark_status = !self.eta_bookmark_status; + if self.eta_bookmark_status { + self.view_bookmark_status = false; + self.developer_bookmark_status = false; + self.export_bookmark_status = false; + } } MainMenuMessage::DeveloperBookmarkMsg => { self.developer_bookmark_status = !self.developer_bookmark_status; + if self.developer_bookmark_status { + self.view_bookmark_status = false; + self.eta_bookmark_status = false; + self.export_bookmark_status = false; + } } MainMenuMessage::ExportBookmarkMsg => { self.export_bookmark_status = !self.export_bookmark_status; + if self.export_bookmark_status { + self.view_bookmark_status = false; + self.eta_bookmark_status = false; + self.developer_bookmark_status = false; + } } } Task::none() From 9f3c1b6970e1c64992419f193ea69eaef78b3fba Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Thu, 23 Jan 2025 15:11:30 +0800 Subject: [PATCH 10/12] :sparkles: Switch Pages on_press bookmarks --- src/freeeta_styles.rs | 42 ++------------------ src/main.rs | 1 + src/main_menu.rs | 45 ++++++++++++++++++---- src/pages.rs | 90 ++++++++++++++++--------------------------- 4 files changed, 76 insertions(+), 102 deletions(-) diff --git a/src/freeeta_styles.rs b/src/freeeta_styles.rs index 3c1d98f..f4c9ee9 100644 --- a/src/freeeta_styles.rs +++ b/src/freeeta_styles.rs @@ -1,7 +1,7 @@ use iced::{ - border::{rounded, Radius}, - widget::{button, container, pick_list, text}, - Background, Border, Color, Shadow, Theme, Vector, + border::Radius, + widget::{button, pick_list, text}, + Background, Border, Color, Theme, }; // TODO: Read Theme from const in the future. @@ -30,20 +30,6 @@ pub fn bottomline_text_unselected(_theme: &Theme) -> text::Style { } } -#[allow(dead_code)] -pub fn shadowed_container(_theme: &Theme) -> container::Style { - container::Style { - shadow: Shadow { - color: Color::BLACK, - offset: Vector { x: 0., y: 0. }, - blur_radius: 8., - }, - background: Some(Background::Color(Color::BLACK)), - border: rounded(20.), - ..Default::default() - } -} - /// Returns the average of two colors; color intensity is fixed to 100% fn mix_colors(color_1: Color, color_2: Color) -> Color { Color { @@ -108,24 +94,4 @@ pub fn bookmark_style( ..Default::default() }, } -} - -#[allow(dead_code)] -// Container with right-side round border -pub fn half_rounded_container(_theme: &Theme, color: Color) -> container::Style { - container::Style { - shadow: Shadow::default(), - background: Some(Background::Color(Color::TRANSPARENT)), - border: Border { - color, - width: 2., - radius: Radius { - top_left: 0., - top_right: 5., - bottom_right: 5., - bottom_left: 0., - }, - }, - ..Default::default() - } -} +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 7b6c43c..a88bc23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod freeeta_picklists; mod freeeta_styles; mod freeeta_yml; mod main_menu; +mod pages; use iced; diff --git a/src/main_menu.rs b/src/main_menu.rs index b71ff0c..183cf65 100644 --- a/src/main_menu.rs +++ b/src/main_menu.rs @@ -11,6 +11,7 @@ use iced::{ }; use crate::{freeeta_buttons, freeeta_picklists::functional_picklist, freeeta_styles}; +use crate::pages::Pages; pub struct FreeEta { // TODO: Actually, I don't need this member. @@ -20,6 +21,7 @@ pub struct FreeEta { eta_bookmark_status: bool, developer_bookmark_status: bool, export_bookmark_status: bool, + page: Pages, } impl Default for FreeEta { @@ -52,6 +54,7 @@ impl FreeEta { eta_bookmark_status: false, developer_bookmark_status: false, export_bookmark_status: false, + page: Pages::MainMenuPage, }, Task::none(), ) @@ -85,33 +88,45 @@ impl FreeEta { MainMenuMessage::ViewBookmarkMsg => { self.view_bookmark_status = !self.view_bookmark_status; if self.view_bookmark_status { + // Close other bookmarks self.eta_bookmark_status = false; self.developer_bookmark_status = false; self.export_bookmark_status = false; + // Open corresponding page + self.page = Pages::InterfacePage; } } MainMenuMessage::EtaBookmarkMsg => { self.eta_bookmark_status = !self.eta_bookmark_status; if self.eta_bookmark_status { + // Close other bookmarks self.view_bookmark_status = false; self.developer_bookmark_status = false; self.export_bookmark_status = false; + // Open corresponding page + self.page = Pages::ChartPage; } } MainMenuMessage::DeveloperBookmarkMsg => { self.developer_bookmark_status = !self.developer_bookmark_status; if self.developer_bookmark_status { + // Close other bookmarks self.view_bookmark_status = false; self.eta_bookmark_status = false; self.export_bookmark_status = false; + // Open corresponding page + self.page = Pages::DeveloperPage; } } MainMenuMessage::ExportBookmarkMsg => { self.export_bookmark_status = !self.export_bookmark_status; if self.export_bookmark_status { + // Close other bookmarks self.view_bookmark_status = false; self.eta_bookmark_status = false; self.developer_bookmark_status = false; + // Open corresponding page + self.page = Pages::ExportPage; } } } @@ -219,6 +234,14 @@ impl FreeEta { .style(freeeta_styles::bottomline_text_unselected) .align_x(alignment::Horizontal::Center); + let screen = match self.page { + Pages::MainMenuPage => self.main_menu_page(), + Pages::InterfacePage => self.interface_page(), + Pages::ChartPage => self.chart_page(), + Pages::DeveloperPage => self.developer_page(), + Pages::ExportPage => self.export_page(), + }; + column!( // Functional row row![ @@ -234,14 +257,20 @@ impl FreeEta { vertical_space(), // Body container( - column![ - view_bookmark, - eta_bookmark, - developer_bookmark, - export_bookmark, - ] - .spacing(10.) - .align_x(alignment::Horizontal::Left) + row![ + // Bookmarks + column![ + view_bookmark, + eta_bookmark, + developer_bookmark, + export_bookmark, + ] + .spacing(10.) + .align_x(alignment::Horizontal::Left), + + // Canvas + screen + ].spacing(10) ) .align_x(alignment::Horizontal::Left), vertical_space(), diff --git a/src/pages.rs b/src/pages.rs index 43312db..ac9afa4 100644 --- a/src/pages.rs +++ b/src/pages.rs @@ -1,67 +1,45 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct Pages { - title: &'static str, - view: fn() -> Element<'static, Message>, +use iced::{alignment, widget::{container, text, Container}}; + +use crate::main_menu::{FreeEta, MainMenuMessage}; + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +pub enum Pages { + #[default] + MainMenuPage, + InterfacePage, + ChartPage, + DeveloperPage, + ExportPage, } -impl Pages { - const LIST: &'static [Self] = &[ - Self { - title: "Centered", - view: centered, - }, - Self { - title: "Column", - view: column_, - }, - Self { - title: "Row", - view: row_, - }, - Self { - title: "Space", - view: space, - }, - Self { - title: "Application", - view: application, - }, - ]; - - fn is_first(self) -> bool { - Self::LIST.first() == Some(&self) +impl FreeEta { + pub fn main_menu_page(&self) -> Container{ + container( + text("Hello, FreeEta!").size(80), + ).align_x(alignment::Horizontal::Center).align_y(alignment::Vertical::Center).into() } - fn is_last(self) -> bool { - Self::LIST.last() == Some(&self) + pub fn interface_page(&self) -> Container{ + container( + text("Hello, interface page!").size(70), + ).align_x(alignment::Horizontal::Center).align_y(alignment::Vertical::Center).into() } - fn previous(self) -> Self { - let Some(index) = Self::LIST.iter().position(|&Pages| Pages == self) else { - return self; - }; - - Self::LIST - .get(index.saturating_sub(1)) - .copied() - .unwrap_or(self) + pub fn chart_page(&self) -> Container{ + container( + text("Hello, chart page!").size(65), + ).align_x(alignment::Horizontal::Center).align_y(alignment::Vertical::Center).into() } - fn next(self) -> Self { - let Some(index) = Self::LIST.iter().position(|&Pages| Pages == self) else { - return self; - }; - - Self::LIST.get(index + 1).copied().unwrap_or(self) + pub fn developer_page(&self) -> Container{ + container( + text("Hello, developer page!").size(60), + ).align_x(alignment::Horizontal::Center).align_y(alignment::Vertical::Center).into() } - fn view(&self) -> Element { - (self.view)() + pub fn export_page(&self) -> Container{ + container( + text("Hello, export page!").size(50), + ).align_x(alignment::Horizontal::Center).align_y(alignment::Vertical::Center).into() } -} - -impl Default for Pages { - fn default() -> Self { - Self::LIST[0] - } -} +} \ No newline at end of file From 236bc6b79300ac1321e752c3590338ad045b16c4 Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Thu, 23 Jan 2025 15:24:24 +0800 Subject: [PATCH 11/12] :memo: Update Readme.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 931c0bc..65f7488 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-# FreeEta +# ![LOGO](static/svg/logo.svg) FreeEta [![Crates.io](https://img.shields.io/crates/v/FreeEta.svg)](https://crates.io/crates/FreeEta) [![License](https://img.shields.io/crates/l/FreeEta.svg)](https://github.com/Administroot/FreeEta/blob/main/LICENSE) @@ -14,7 +14,9 @@ A fast, elegant & free ETA analysis utility powered by ๐Ÿฆ€ Rust, ๐ŸงŠ iced.
-> โ—โ—โ—Main functions are not yet! +> [!danger]+ +> Freeeta is on flight๐Ÿ›ซ +> ## Installation From 9b8232e69729eaf4238936ab1a9a643e201c62f5 Mon Sep 17 00:00:00 2001 From: administroot <1474668090@qq.com> Date: Thu, 23 Jan 2025 15:44:11 +0800 Subject: [PATCH 12/12] :memo: Update shields --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 65f7488..5ae42d9 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ # ![LOGO](static/svg/logo.svg) FreeEta [![Crates.io](https://img.shields.io/crates/v/FreeEta.svg)](https://crates.io/crates/FreeEta) -[![License](https://img.shields.io/crates/l/FreeEta.svg)](https://github.com/Administroot/FreeEta/blob/main/LICENSE) +![GitHub License](https://img.shields.io/github/license/Administroot/FreeEta) [![Downloads](https://img.shields.io/crates/d/FreeEta.svg)](https://github.com/Administroot/FreeEta/releases/latest) -[![Test Status](https://img.shields.io/github/actions/workflow/status/administroot/FreeEta/test.yml?branch=master&event=push&label=test)](https://github.com/administroot/FreeEta/actions) +![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/Administroot/FreeEta/rust.yml) [![Made with iced](https://iced.rs/badge.svg)](https://github.com/iced-rs/iced) A fast, elegant & free ETA analysis utility powered by ๐Ÿฆ€ Rust, ๐ŸงŠ iced.