use crate::ui::db_browser::DbBrowserMsg; use crate::ui::home_page::HomePage; use crate::ui::home_page::HomePageMsg; use crate::ui::jlc_downloader::JlcDownloader; use crate::ui::jlc_downloader::JlcDownloaderMsg; use crate::ui::part_viewer::PartViewerMsg; use crate::utils::step_downloader; use iced::Subscription; use iced::Task; use tracing::info; use tracing::warn; #[allow(unused_imports)] use super::db_browser; #[allow(unused_imports)] use super::home_page; #[allow(unused_imports)] use super::jlc_downloader; #[allow(unused_imports)] use super::part_viewer; use iced::Theme; #[allow(unused_imports)] use iced::widget as w; use iced::widget::button; use iced::widget::row; #[allow(unused_imports)] use iced::{ Element, Length, alignment::{Horizontal, Vertical}, widget::{Column, Container, Text, column}, }; use std::fmt::Display; #[allow(dead_code)] struct MainWindow { title: String, theme: iced::Theme, curr_tab: TabId, home_page: crate::ui::home_page::HomePage, jlc_downloader: crate::ui::jlc_downloader::JlcDownloader, db_browser: crate::ui::db_browser::DbBrowser, part_viewer: crate::ui::part_viewer::PartViewer, } impl Default for MainWindow { fn default() -> Self { let mut home_page = HomePage::default(); let mut theme = Theme::default(); if let Ok(saved_theme) = crate::utils::app_settings::get_curr_theme() { theme = Theme::ALL[saved_theme as usize % Theme::ALL.len()].clone(); home_page.theme = theme.clone(); } Self { title: "HardwareToolkit".into(), theme, curr_tab: Default::default(), home_page, jlc_downloader: Default::default(), db_browser: Default::default(), part_viewer: Default::default(), } } } impl MainWindow { pub fn new() -> (Self, Task) { ( Self::default(), Task::batch([ Task::perform(JlcDownloader::search_keyword(""), |x| match x { Ok(v) => MainWindowMsg::JlcDownloader(JlcDownloaderMsg::KeywordSearchResult(v)), Err(e) => MainWindowMsg::JlcDownloader(JlcDownloaderMsg::KeywordSearchError( format!("{e:?}"), )), }), iced::widget::focus_next(), ]), ) } } pub fn main_window() { let _ = iced::application(MainWindow::new, MainWindow::update, MainWindow::view) .theme(MainWindow::theme) .default_font(iced::Font::with_name("微软雅黑")) .title(MainWindow::title) .subscription(MainWindow::subscription) .run(); } #[allow(dead_code)] #[derive(Debug, Clone)] pub enum MainWindowMsg { ThemeChanged(iced::Theme), SearchKeywordChanged(String), TitleChanged(String), TabSelected(TabId), HomePage(HomePageMsg), JlcDownloader(JlcDownloaderMsg), DbBrowser(DbBrowserMsg), PartViewer(PartViewerMsg), Nothing, StepDownloader(step_downloader::StepDownloaderEvent), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum TabId { HomePage, JlcDownloader, DbBrowser, PartViewer, } impl Default for TabId { fn default() -> Self { if let Ok(tab) = crate::utils::app_settings::get_curr_page() { Self::from(tab) } else { Self::HomePage } } } impl TabId { pub fn save(&self) { let v = *self; match crate::utils::app_settings::set_curr_page(v.into()) { Ok(_) => {} Err(_) => { warn!("Failed to save the current page."); } } } } impl Display for TabId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}", match self { TabId::HomePage => "主页", TabId::JlcDownloader => "3D模型下载", TabId::DbBrowser => "数据库浏览", TabId::PartViewer => "元件查看", } ) } } impl From for u32 { fn from(val: TabId) -> Self { match val { TabId::HomePage => 0, TabId::JlcDownloader => 1, TabId::DbBrowser => 2, TabId::PartViewer => 3, } } } impl From for TabId { fn from(value: u32) -> Self { match value { 0 => Self::HomePage, 1 => Self::JlcDownloader, 2 => Self::DbBrowser, 3 => Self::PartViewer, _ => Self::HomePage, } } } impl MainWindow { fn title(&self) -> String { self.title.clone() } fn theme(&self) -> Theme { self.theme.clone() } fn subscription(&self) -> Subscription { info!("subscription run once."); Subscription::run(step_downloader::StepDownloader::create_process) .map(MainWindowMsg::StepDownloader) // iced::keyboard::on_key_press(|key, modifiers| { // info!("Press the key: {key:?}"); // info!("The modifiers: {modifiers:?}"); // Some(MainWindowMsg::Nothing) // }) } fn create_tab_btn(&self, tab: TabId) -> Element<'_, MainWindowMsg> { let bstyle = if self.curr_tab == tab { button::danger } else { button::primary }; let txt = format!("{tab}"); let txt = iced::widget::text(txt); let btn = button(txt).style(bstyle); btn.on_press(MainWindowMsg::TabSelected(tab)).into() } fn update(&mut self, msg: MainWindowMsg) -> Task { info!("Process the msg: {msg:?}"); match msg { MainWindowMsg::ThemeChanged(theme) => { self.theme = theme.clone(); if let Some(idx) = Theme::ALL.iter().position(|x| x == &theme) { crate::utils::app_settings::set_curr_theme(idx as u32).unwrap(); } Task::none() } MainWindowMsg::TitleChanged(title) => { self.title = title; Task::none() } MainWindowMsg::Nothing => { info!("Nothing"); iced::debug::time("Test".to_owned()); Task::none() } MainWindowMsg::TabSelected(i) => { self.curr_tab = i; self.curr_tab.save(); Task::none() } MainWindowMsg::HomePage(msg) => { info!("update HomePage"); self.home_page.update(msg) } MainWindowMsg::JlcDownloader(msg) => self.jlc_downloader.update(msg), MainWindowMsg::DbBrowser(msg) => self.db_browser.update(msg), MainWindowMsg::PartViewer(part_viewer_msg) => self.part_viewer.update(part_viewer_msg), MainWindowMsg::SearchKeywordChanged(k) => self .jlc_downloader .update(JlcDownloaderMsg::KeywordChanged(k)), MainWindowMsg::StepDownloader(msg) => { info!("StepDownloaderEvent: {msg:?}"); Task::none() } } } fn view(&self) -> Element<'_, MainWindowMsg> { let h = row![ self.create_tab_btn(TabId::HomePage), self.create_tab_btn(TabId::JlcDownloader), self.create_tab_btn(TabId::DbBrowser), self.create_tab_btn(TabId::PartViewer) ]; let v = match self.curr_tab { TabId::HomePage => self.home_page.view(), TabId::JlcDownloader => self.jlc_downloader.view(), TabId::DbBrowser => self.db_browser.view(), TabId::PartViewer => self.part_viewer.view(), }; // let content = iced::widget::Button::new("Click").on_press(MainWindowMsg::Nothing); column![h, v].into() } } pub trait TabContent { type TabMessage; fn update(&mut self, msg: Self::TabMessage) -> Task; fn view(&self) -> Element<'_, MainWindowMsg> { iced::widget::Container::new(self.content()) .width(Length::Fill) .height(Length::Fill) .align_x(Horizontal::Left) .align_y(Vertical::Top) .padding(16.0) .into() } fn content(&self) -> Element<'_, MainWindowMsg>; }