2025-06-23 21:52:45 +08:00
|
|
|
use crate::ui::db_browser::DbBrowserMsg;
|
2025-06-23 23:25:37 +08:00
|
|
|
use crate::ui::home_page::HomePage;
|
2025-06-23 21:52:45 +08:00
|
|
|
use crate::ui::home_page::HomePageMsg;
|
|
|
|
|
use crate::ui::jlc_downloader::JlcDownloaderMsg;
|
|
|
|
|
use crate::ui::part_viewer::PartViewerMsg;
|
2025-06-28 16:43:09 +08:00
|
|
|
use iced::Subscription;
|
|
|
|
|
use iced::Task;
|
2025-07-04 13:18:41 +08:00
|
|
|
use iced::color;
|
2025-06-28 19:54:11 +08:00
|
|
|
use tracing::info;
|
|
|
|
|
use tracing::warn;
|
2025-07-04 13:18:41 +08:00
|
|
|
use crate::widgets::toast;
|
2025-06-23 21:52:45 +08:00
|
|
|
|
|
|
|
|
#[allow(unused_imports)]
|
2025-06-20 11:03:06 +08:00
|
|
|
use super::db_browser;
|
2025-06-23 21:52:45 +08:00
|
|
|
#[allow(unused_imports)]
|
2025-06-20 11:03:06 +08:00
|
|
|
use super::home_page;
|
2025-06-23 21:52:45 +08:00
|
|
|
#[allow(unused_imports)]
|
2025-06-20 11:03:06 +08:00
|
|
|
use super::jlc_downloader;
|
2025-06-23 21:52:45 +08:00
|
|
|
#[allow(unused_imports)]
|
2025-06-20 11:03:06 +08:00
|
|
|
use super::part_viewer;
|
2025-07-04 13:18:41 +08:00
|
|
|
use iced::Theme;
|
2025-06-23 21:52:45 +08:00
|
|
|
#[allow(unused_imports)]
|
2025-06-20 11:03:06 +08:00
|
|
|
use iced::widget as w;
|
2025-06-23 21:52:45 +08:00
|
|
|
use iced::widget::button;
|
|
|
|
|
use iced::widget::row;
|
|
|
|
|
#[allow(unused_imports)]
|
2025-06-20 11:03:06 +08:00
|
|
|
use iced::{
|
2025-07-04 13:18:41 +08:00
|
|
|
Element, Length,
|
|
|
|
|
alignment::{Horizontal, Vertical},
|
|
|
|
|
widget::{Column, Container, Text, column},
|
2025-06-20 11:03:06 +08:00
|
|
|
};
|
2025-06-23 21:52:45 +08:00
|
|
|
use std::fmt::Display;
|
2025-06-19 18:58:30 +08:00
|
|
|
|
2025-06-23 21:52:45 +08:00
|
|
|
#[allow(dead_code)]
|
2025-06-20 11:03:06 +08:00
|
|
|
struct MainWindow {
|
|
|
|
|
title: String,
|
|
|
|
|
theme: iced::Theme,
|
|
|
|
|
curr_tab: TabId,
|
2025-06-23 21:52:45 +08:00
|
|
|
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,
|
2025-07-02 21:26:19 +08:00
|
|
|
explain: bool,
|
2025-07-04 13:18:41 +08:00
|
|
|
toasts:Vec<toast::Toast>,
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|
|
|
|
|
impl Default for MainWindow {
|
|
|
|
|
fn default() -> Self {
|
2025-06-23 23:25:37 +08:00
|
|
|
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();
|
|
|
|
|
}
|
2025-07-02 21:26:19 +08:00
|
|
|
let mut jlc_downloader = crate::ui::jlc_downloader::JlcDownloader::default();
|
|
|
|
|
jlc_downloader.set_theme(theme.clone());
|
2025-07-04 13:18:41 +08:00
|
|
|
jlc_downloader.step_save_dir = home_page.step_dir.clone();
|
2025-06-20 11:03:06 +08:00
|
|
|
Self {
|
2025-06-23 21:52:45 +08:00
|
|
|
title: "HardwareToolkit".into(),
|
2025-06-23 23:25:37 +08:00
|
|
|
theme,
|
2025-06-20 11:03:06 +08:00
|
|
|
curr_tab: Default::default(),
|
2025-06-23 23:25:37 +08:00
|
|
|
home_page,
|
2025-07-02 21:26:19 +08:00
|
|
|
jlc_downloader,
|
2025-06-23 21:52:45 +08:00
|
|
|
db_browser: Default::default(),
|
|
|
|
|
part_viewer: Default::default(),
|
2025-07-02 21:26:19 +08:00
|
|
|
explain: false,
|
2025-07-04 13:18:41 +08:00
|
|
|
toasts:Default::default(),
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-28 16:43:09 +08:00
|
|
|
impl MainWindow {
|
|
|
|
|
pub fn new() -> (Self, Task<MainWindowMsg>) {
|
2025-07-02 21:26:19 +08:00
|
|
|
(Self::default(), Task::batch([iced::widget::focus_next()]))
|
2025-06-28 16:43:09 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-06-20 11:03:06 +08:00
|
|
|
|
|
|
|
|
pub fn main_window() {
|
2025-06-28 16:43:09 +08:00
|
|
|
let _ = iced::application(MainWindow::new, MainWindow::update, MainWindow::view)
|
2025-06-23 23:25:37 +08:00
|
|
|
.theme(MainWindow::theme)
|
2025-06-23 21:52:45 +08:00
|
|
|
.default_font(iced::Font::with_name("微软雅黑"))
|
2025-06-20 11:03:06 +08:00
|
|
|
.title(MainWindow::title)
|
2025-06-28 16:43:09 +08:00
|
|
|
.subscription(MainWindow::subscription)
|
2025-06-20 11:03:06 +08:00
|
|
|
.run();
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-23 21:52:45 +08:00
|
|
|
#[allow(dead_code)]
|
2025-06-20 11:03:06 +08:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum MainWindowMsg {
|
|
|
|
|
ThemeChanged(iced::Theme),
|
2025-06-28 16:43:09 +08:00
|
|
|
SearchKeywordChanged(String),
|
2025-06-20 11:03:06 +08:00
|
|
|
TitleChanged(String),
|
2025-06-23 21:52:45 +08:00
|
|
|
TabSelected(TabId),
|
|
|
|
|
HomePage(HomePageMsg),
|
|
|
|
|
JlcDownloader(JlcDownloaderMsg),
|
|
|
|
|
DbBrowser(DbBrowserMsg),
|
|
|
|
|
PartViewer(PartViewerMsg),
|
2025-07-02 21:26:19 +08:00
|
|
|
Explain(bool),
|
2025-07-04 13:18:41 +08:00
|
|
|
Toast(toast::Toast),
|
|
|
|
|
CloseToast(usize),
|
2025-06-20 11:03:06 +08:00
|
|
|
Nothing,
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-28 16:43:09 +08:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
2025-06-23 21:52:45 +08:00
|
|
|
pub(crate) enum TabId {
|
2025-06-20 11:03:06 +08:00
|
|
|
HomePage,
|
|
|
|
|
JlcDownloader,
|
|
|
|
|
DbBrowser,
|
|
|
|
|
PartViewer,
|
|
|
|
|
}
|
2025-06-28 16:43:09 +08:00
|
|
|
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.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-23 21:52:45 +08:00
|
|
|
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 => "元件查看",
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-28 16:43:09 +08:00
|
|
|
impl From<TabId> for u32 {
|
|
|
|
|
fn from(val: TabId) -> Self {
|
|
|
|
|
match val {
|
|
|
|
|
TabId::HomePage => 0,
|
|
|
|
|
TabId::JlcDownloader => 1,
|
|
|
|
|
TabId::DbBrowser => 2,
|
|
|
|
|
TabId::PartViewer => 3,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl From<u32> for TabId {
|
|
|
|
|
fn from(value: u32) -> Self {
|
|
|
|
|
match value {
|
|
|
|
|
0 => Self::HomePage,
|
|
|
|
|
1 => Self::JlcDownloader,
|
|
|
|
|
2 => Self::DbBrowser,
|
|
|
|
|
3 => Self::PartViewer,
|
|
|
|
|
_ => Self::HomePage,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-20 11:03:06 +08:00
|
|
|
impl MainWindow {
|
|
|
|
|
fn title(&self) -> String {
|
|
|
|
|
self.title.clone()
|
|
|
|
|
}
|
2025-06-23 23:25:37 +08:00
|
|
|
fn theme(&self) -> Theme {
|
|
|
|
|
self.theme.clone()
|
|
|
|
|
}
|
2025-06-28 16:43:09 +08:00
|
|
|
|
|
|
|
|
fn subscription(&self) -> Subscription<MainWindowMsg> {
|
|
|
|
|
info!("subscription run once.");
|
2025-06-28 23:53:40 +08:00
|
|
|
iced::keyboard::on_key_press(|key, modifiers| {
|
|
|
|
|
info!("Press the key: {key:?}");
|
|
|
|
|
info!("The modifiers: {modifiers:?}");
|
|
|
|
|
Some(MainWindowMsg::Nothing)
|
|
|
|
|
})
|
2025-06-28 16:43:09 +08:00
|
|
|
}
|
2025-06-23 21:52:45 +08:00
|
|
|
fn create_tab_btn(&self, tab: TabId) -> Element<'_, MainWindowMsg> {
|
2025-06-28 23:53:40 +08:00
|
|
|
let btn_style = if self.curr_tab == tab {
|
2025-06-23 23:25:37 +08:00
|
|
|
button::danger
|
2025-06-23 21:52:45 +08:00
|
|
|
} else {
|
2025-06-23 23:25:37 +08:00
|
|
|
button::primary
|
2025-06-23 21:52:45 +08:00
|
|
|
};
|
|
|
|
|
let txt = format!("{tab}");
|
|
|
|
|
let txt = iced::widget::text(txt);
|
2025-06-28 23:53:40 +08:00
|
|
|
let btn = button(txt).style(btn_style);
|
2025-06-28 16:43:09 +08:00
|
|
|
btn.on_press(MainWindowMsg::TabSelected(tab)).into()
|
2025-06-23 21:52:45 +08:00
|
|
|
}
|
2025-06-28 19:54:11 +08:00
|
|
|
fn update(&mut self, msg: MainWindowMsg) -> Task<MainWindowMsg> {
|
2025-06-20 11:03:06 +08:00
|
|
|
match msg {
|
|
|
|
|
MainWindowMsg::ThemeChanged(theme) => {
|
2025-06-23 23:25:37 +08:00
|
|
|
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();
|
|
|
|
|
}
|
2025-07-02 21:26:19 +08:00
|
|
|
self.home_page.set_theme(theme);
|
|
|
|
|
self.home_page.update(HomePageMsg::Nothing)
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|
|
|
|
|
MainWindowMsg::TitleChanged(title) => {
|
|
|
|
|
self.title = title;
|
2025-06-28 19:54:11 +08:00
|
|
|
Task::none()
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|
|
|
|
|
MainWindowMsg::Nothing => {
|
2025-06-28 16:43:09 +08:00
|
|
|
info!("Nothing");
|
2025-06-20 11:03:06 +08:00
|
|
|
iced::debug::time("Test".to_owned());
|
2025-06-28 19:54:11 +08:00
|
|
|
Task::none()
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|
2025-06-23 21:52:45 +08:00
|
|
|
MainWindowMsg::TabSelected(i) => {
|
|
|
|
|
self.curr_tab = i;
|
2025-06-28 16:43:09 +08:00
|
|
|
self.curr_tab.save();
|
2025-06-28 19:54:11 +08:00
|
|
|
Task::none()
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|
2025-06-23 21:52:45 +08:00
|
|
|
MainWindowMsg::HomePage(msg) => {
|
2025-06-28 16:43:09 +08:00
|
|
|
info!("update HomePage");
|
2025-06-28 19:54:11 +08:00
|
|
|
self.home_page.update(msg)
|
2025-06-28 16:43:09 +08:00
|
|
|
}
|
2025-06-28 19:54:11 +08:00
|
|
|
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)),
|
2025-07-02 21:26:19 +08:00
|
|
|
MainWindowMsg::Explain(explain) => {
|
|
|
|
|
self.explain = explain;
|
|
|
|
|
Task::none()
|
|
|
|
|
}
|
2025-07-04 13:18:41 +08:00
|
|
|
MainWindowMsg::Toast(t)=>{
|
|
|
|
|
self.toasts.push(t.clone());
|
|
|
|
|
Task::none()
|
|
|
|
|
}
|
|
|
|
|
MainWindowMsg::CloseToast(i)=>{
|
|
|
|
|
self.toasts.remove(i);
|
|
|
|
|
Task::none()
|
|
|
|
|
}
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fn view(&self) -> Element<'_, MainWindowMsg> {
|
2025-06-23 21:52:45 +08:00
|
|
|
let h = row![
|
|
|
|
|
self.create_tab_btn(TabId::HomePage),
|
|
|
|
|
self.create_tab_btn(TabId::JlcDownloader),
|
|
|
|
|
self.create_tab_btn(TabId::DbBrowser),
|
2025-07-02 21:26:19 +08:00
|
|
|
self.create_tab_btn(TabId::PartViewer),
|
|
|
|
|
iced::widget::horizontal_space().width(Length::Fill),
|
|
|
|
|
iced::widget::checkbox("Explain", self.explain).on_toggle(MainWindowMsg::Explain),
|
2025-06-23 21:52:45 +08:00
|
|
|
];
|
|
|
|
|
let v = match self.curr_tab {
|
2025-07-02 21:26:19 +08:00
|
|
|
TabId::HomePage => {
|
|
|
|
|
if self.explain {
|
|
|
|
|
self.home_page.view().explain(color!(0xff0000))
|
|
|
|
|
} else {
|
|
|
|
|
self.home_page.view()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TabId::JlcDownloader => {
|
|
|
|
|
if self.explain {
|
|
|
|
|
self.jlc_downloader.view().explain(color!(0xff0000))
|
|
|
|
|
} else {
|
|
|
|
|
self.jlc_downloader.view()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TabId::DbBrowser => {
|
|
|
|
|
if self.explain {
|
|
|
|
|
self.db_browser.view().explain(color!(0xff0000))
|
|
|
|
|
} else {
|
|
|
|
|
self.db_browser.view()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TabId::PartViewer => {
|
|
|
|
|
if self.explain {
|
|
|
|
|
self.part_viewer.view().explain(color!(0xff0000))
|
|
|
|
|
} else {
|
|
|
|
|
self.part_viewer.view()
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-23 21:52:45 +08:00
|
|
|
};
|
|
|
|
|
// let content = iced::widget::Button::new("Click").on_press(MainWindowMsg::Nothing);
|
2025-07-04 13:18:41 +08:00
|
|
|
|
|
|
|
|
//let content = column![h, v].into();
|
|
|
|
|
toast::Manager::new(column![h,v], &self.toasts, MainWindowMsg::CloseToast).timeout(8).into()
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-23 21:52:45 +08:00
|
|
|
pub trait TabContent {
|
|
|
|
|
type TabMessage;
|
2025-06-28 19:54:11 +08:00
|
|
|
fn update(&mut self, msg: Self::TabMessage) -> Task<MainWindowMsg>;
|
2025-06-23 21:52:45 +08:00
|
|
|
fn view(&self) -> Element<'_, MainWindowMsg> {
|
|
|
|
|
iced::widget::Container::new(self.content())
|
2025-06-20 11:03:06 +08:00
|
|
|
.width(Length::Fill)
|
|
|
|
|
.height(Length::Fill)
|
|
|
|
|
.align_x(Horizontal::Left)
|
|
|
|
|
.align_y(Vertical::Top)
|
2025-06-23 21:52:45 +08:00
|
|
|
.padding(16.0)
|
2025-06-20 11:03:06 +08:00
|
|
|
.into()
|
|
|
|
|
}
|
2025-06-23 21:52:45 +08:00
|
|
|
fn content(&self) -> Element<'_, MainWindowMsg>;
|
2025-06-20 11:03:06 +08:00
|
|
|
}
|