summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpml68 <contact@pml68.dev>2025-04-28 10:59:52 +0200
committerpml68 <contact@pml68.dev>2025-04-28 23:45:43 +0200
commite17ce59fa4c907511f38795c342b2232a7bba26d (patch)
tree0bbeddd19696de817a97f2109bae316e3a564f3a
parentfeat: switch to modified `iced_fontello` for custom Theme support (diff)
downloadiced-builder-e17ce59fa4c907511f38795c342b2232a7bba26d.tar.gz
feat: switch to fully custom, Material3-based theme
Diffstat (limited to '')
-rw-r--r--assets/themes/rose_pine.toml41
-rw-r--r--src/appearance.rs46
-rw-r--r--src/config.rs41
-rw-r--r--src/dialogs.rs4
-rw-r--r--src/main.rs23
-rw-r--r--src/options.rs2
-rw-r--r--src/panes/code_view.rs46
-rw-r--r--src/panes/designer_view.rs7
-rw-r--r--src/panes/element_list.rs7
-rw-r--r--src/panes/style.rs23
-rw-r--r--src/theme.rs357
-rw-r--r--src/types.rs6
-rw-r--r--src/types/project.rs18
-rwxr-xr-xsrc/types/rendered_element.rs30
-rw-r--r--src/widget.rs18
-rw-r--r--theme_test/src/main.rs2
16 files changed, 155 insertions, 516 deletions
diff --git a/assets/themes/rose_pine.toml b/assets/themes/rose_pine.toml
deleted file mode 100644
index e4540fb..0000000
--- a/assets/themes/rose_pine.toml
+++ /dev/null
@@ -1,41 +0,0 @@
-name = "Rosé Pine"
-
-dark = true
-
-[palette]
-background = "#26233a"
-text = "#e0def4"
-primary = "#9ccfd8"
-success = "#f6c177"
-danger = "#eb6f92"
-warning = "#e4b363"
-
-[background]
-base = { color = "#191724", text = "#e0def4" }
-weak = { color = "#1f1d2e", text = "#e0def4" }
-strong = { color = "#26233a", text = "#f4ebd3" }
-
-[primary]
-base = { color = "#eb6f92", text = "#000000" }
-weak = { color = "#f6c177", text = "#000000" }
-strong = { color = "#ebbcba", text = "#000000" }
-
-[secondary]
-base = { color = "#31748f", text = "#ffffff" }
-weak = { color = "#9ccfd8", text = "#000000" }
-strong = { color = "#c4a7e7", text = "#000000" }
-
-[success]
-base = { color = "#9ccfd8", text = "#000000" }
-weak = { color = "#6e6a86", text = "#ffffff" }
-strong = { color = "#908caa", text = "#000000" }
-
-[danger]
-base = { color = "#eb6f92", text = "#ffffff" }
-weak = { color = "#f6c177", text = "#ffffff" }
-strong = { color = "#524f67", text = "#ffffff" }
-
-[warning]
-base = { color = "#e4b363", text = "#ffffff" }
-weak = { color = "#f4e1a1", text = "#000000" }
-strong = { color = "#d8a343", text = "#ffffff" }
diff --git a/src/appearance.rs b/src/appearance.rs
new file mode 100644
index 0000000..78e782d
--- /dev/null
+++ b/src/appearance.rs
@@ -0,0 +1,46 @@
+use std::sync::Arc;
+
+use material_theme::Theme;
+
+pub fn iced_theme_from_str(theme_name: &str) -> iced::Theme {
+ match theme_name {
+ "Light" => iced::Theme::Light,
+ "Dark" => iced::Theme::Dark,
+ "Dracula" => iced::Theme::Dracula,
+ "Nord" => iced::Theme::Nord,
+ "Solarized Light" => iced::Theme::SolarizedLight,
+ "Solarized Dark" => iced::Theme::SolarizedDark,
+ "Gruvbox Light" => iced::Theme::GruvboxLight,
+ "Gruvbox Dark" => iced::Theme::GruvboxDark,
+ "Catppuccin Latte" => iced::Theme::CatppuccinLatte,
+ "Catppuccin Frappé" => iced::Theme::CatppuccinFrappe,
+ "Catppuccin Macchiato" => iced::Theme::CatppuccinMacchiato,
+ "Catppuccin Mocha" => iced::Theme::CatppuccinMocha,
+ "Tokyo Night" => iced::Theme::TokyoNight,
+ "Tokyo Night Storm" => iced::Theme::TokyoNightStorm,
+ "Tokyo Night Light" => iced::Theme::TokyoNightLight,
+ "Kanagawa Wave" => iced::Theme::KanagawaWave,
+ "Kanagawa Dragon" => iced::Theme::KanagawaDragon,
+ "Kanagawa Lotus" => iced::Theme::KanagawaLotus,
+ "Moonfly" => iced::Theme::Moonfly,
+ "Nightfly" => iced::Theme::Nightfly,
+ "Oxocarbon" => iced::Theme::Oxocarbon,
+ "Ferra" => iced::Theme::Ferra,
+ _ => iced::Theme::default(),
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct Appearance {
+ pub selected: Theme,
+ pub all: Arc<[Theme]>,
+}
+
+impl Default for Appearance {
+ fn default() -> Self {
+ Self {
+ selected: Theme::default(),
+ all: Theme::ALL.into(),
+ }
+ }
+}
diff --git a/src/config.rs b/src/config.rs
index 1da1239..7f6f8ce 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,26 +1,36 @@
// (c) 2022-2024 Cory Forsstrom, Casper Rogild Storm, Calvin Lee, Andrew Baldwin, Reza Alizadeh Majd
// (c) 2024-2025 Polesznyák Márk László
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
+use material_theme::Theme;
use serde::Deserialize;
use tokio_stream::StreamExt;
use tokio_stream::wrappers::ReadDirStream;
-use crate::theme::{Appearance, Theme, theme_from_str, theme_index};
+use crate::appearance::Appearance;
use crate::{Error, environment};
#[derive(Debug, Clone, Default)]
pub struct Config {
- pub theme: Appearance,
- pub last_project: Option<PathBuf>,
+ theme: Appearance,
+ last_project: Option<PathBuf>,
}
impl Config {
- pub fn selected_theme(&self) -> iced::Theme {
+ pub fn selected_theme(&self) -> Theme {
self.theme.selected.clone()
}
+ pub fn themes(&self) -> Arc<[Theme]> {
+ self.theme.all.clone()
+ }
+
+ pub fn last_project(&self) -> Option<&Path> {
+ self.last_project.as_deref()
+ }
+
pub fn config_dir() -> PathBuf {
let dir = environment::config_dir();
@@ -67,7 +77,7 @@ impl Config {
last_project,
} = toml::from_str(content.as_ref())?;
- let theme = Self::load_theme(theme).await.unwrap_or_default();
+ let theme = Self::load_appearance(&theme).await.unwrap_or_default();
Ok(Self {
theme,
@@ -75,7 +85,9 @@ impl Config {
})
}
- pub async fn load_theme(theme_name: String) -> Result<Appearance, Error> {
+ pub async fn load_appearance(
+ theme_name: &str,
+ ) -> Result<Appearance, Error> {
use tokio::fs;
let read_entry = async move |entry: fs::DirEntry| {
@@ -83,15 +95,16 @@ impl Config {
let theme: Theme = toml::from_str(content.as_ref()).ok()?;
- Some(iced::Theme::from(theme))
+ Some(theme)
};
- let mut selected = Theme::default().into();
- let mut all = iced::Theme::ALL.to_owned();
- all.push(Theme::default().into());
+ let mut selected = Theme::default();
+ let mut all = Theme::ALL.to_owned();
- if theme_index(&theme_name, iced::Theme::ALL).is_some() {
- selected = theme_from_str(None, &theme_name);
+ if let Some(index) =
+ Theme::ALL.iter().position(|t| t.name() == theme_name)
+ {
+ selected = Theme::ALL[index].clone();
}
let mut stream =
@@ -102,7 +115,7 @@ impl Config {
};
if let Some(theme) = read_entry(entry).await {
- if theme.to_string() == theme_name {
+ if theme.name() == theme_name {
selected = theme.clone();
}
all.push(theme);
diff --git a/src/dialogs.rs b/src/dialogs.rs
index a623f35..c1933ec 100644
--- a/src/dialogs.rs
+++ b/src/dialogs.rs
@@ -1,8 +1,8 @@
-use iced::{Element, Task};
+use iced::Task;
use iced_dialog::button;
use crate::Message;
-use crate::types::{DialogAction, DialogButtons};
+use crate::types::{DialogAction, DialogButtons, Element};
pub const UNSAVED_CHANGES_TITLE: &str = "Unsaved changes";
pub const WARNING_TITLE: &str = "Heads up!";
diff --git a/src/main.rs b/src/main.rs
index 5014077..1ac1d67 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
+mod appearance;
mod config;
mod dialogs;
mod environment;
@@ -6,7 +7,6 @@ mod error;
mod icon;
mod options;
mod panes;
-mod theme;
mod types;
mod values;
mod widget;
@@ -24,13 +24,15 @@ use iced::advanced::widget::Id;
use iced::widget::{
Column, container, pane_grid, pick_list, row, text, text_editor,
};
-use iced::{Alignment, Element, Length, Task, Theme, clipboard, keyboard};
+use iced::{Alignment, Length, Task, clipboard, keyboard};
use iced_anim::transition::Easing;
use iced_anim::{Animated, Animation};
use iced_dialog::dialog::Dialog;
+use material_theme::Theme;
use panes::{code_view, designer_view, element_list};
use types::{
- Action, DesignerPane, DialogAction, DialogButtons, Message, Project,
+ Action, DesignerPane, DialogAction, DialogButtons, Element, Message,
+ Project,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -148,11 +150,10 @@ impl IcedBuilder {
self.config = Arc::new(config);
self.theme.update(self.config.selected_theme().into());
- return if let Some(path) = self.config.last_project.clone()
- {
+ return if let Some(path) = self.config.last_project() {
if path.exists() && path.is_file() {
Task::perform(
- Project::from_path(path),
+ Project::from_path(path.to_owned()),
Message::FileOpened,
)
} else {
@@ -394,7 +395,7 @@ impl IcedBuilder {
fn view(&self) -> Element<'_, Message> {
let header = row![pick_list(
- self.config.theme.all.clone(),
+ self.config.themes(),
Some(self.theme.target()),
|theme| Message::SwitchTheme(theme.into())
)]
@@ -442,13 +443,7 @@ impl IcedBuilder {
DialogButtons::OkCancel => vec![ok_button(), cancel_button()],
},
)
- .title(self.dialog_title)
- .container_style(|theme| container::Style {
- background: Some(
- theme.extended_palette().background.strong.color.into(),
- ),
- ..Default::default()
- });
+ .title(self.dialog_title);
Animation::new(&self.theme, content)
.on_update(Message::SwitchTheme)
diff --git a/src/options.rs b/src/options.rs
index 2dc25d7..931182a 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -258,7 +258,7 @@ impl<Message> ApplyOptions for Row<'_, Message> {
}
}
-impl<Handle> ApplyOptions for Image<Handle> {
+impl<Handle> ApplyOptions for Image<'_, Handle> {
fn apply_options(self, options: BTreeMap<String, Option<String>>) -> Self {
let mut image = self;
diff --git a/src/panes/code_view.rs b/src/panes/code_view.rs
index 890af8a..5999b8f 100644
--- a/src/panes/code_view.rs
+++ b/src/panes/code_view.rs
@@ -1,27 +1,36 @@
use iced::advanced::text::highlighter::Format;
-use iced::widget::{Space, button, pane_grid, row, text, text_editor};
-use iced::{Alignment, Background, Border, Font, Length, Theme};
+use iced::border::Radius;
+use iced::widget::{button, pane_grid, row, text, text_editor};
+use iced::{Alignment, Border, Font, Length};
use iced_custom_highlighter::{Highlight, Highlighter, Scope, Settings};
+use material_theme::Theme;
use super::style;
use crate::icon;
use crate::types::{DesignerPane, Message};
use crate::widget::tip;
+// TODO: implement a highlight style for the material theme
fn highlight_style(theme: &Theme, scope: &Scope) -> Format<Font> {
+ let theme = if theme.is_dark() {
+ iced::Theme::SolarizedDark
+ } else {
+ iced::Theme::SolarizedLight
+ };
+
match scope {
Scope::Custom { .. } | Scope::Other => Format {
color: Some(theme.extended_palette().primary.strong.color),
font: None,
},
- _ => Highlight::default_style(theme, scope),
+ _ => Highlight::default_style(&theme, scope),
}
}
pub fn view(
editor_content: &text_editor::Content,
is_focused: bool,
-) -> pane_grid::Content<'_, Message> {
+) -> pane_grid::Content<'_, Message, Theme> {
let title_bar = pane_grid::TitleBar::new(text("Generated Code").center())
.controls(pane_grid::Controls::dynamic(
row![
@@ -29,28 +38,28 @@ pub fn view(
button(icon::copy())
.on_press(Message::CopyCode)
.padding([2, 7])
- .style(button::text),
+ .style(material_theme::button::text),
"Copy",
tip::Position::FollowCursor
),
- Space::with_width(20),
button("Switch to Designer view")
.on_press(Message::SwitchPage(DesignerPane::DesignerView))
]
+ .spacing(20)
.align_y(Alignment::Center),
row![
tip(
button(icon::copy())
.on_press(Message::CopyCode)
.padding([2, 7])
- .style(button::text),
+ .style(material_theme::button::text),
"Copy",
tip::Position::FollowCursor
),
- Space::with_width(20),
button(icon::switch())
.on_press(Message::SwitchPage(DesignerPane::DesignerView))
]
+ .spacing(20)
.align_y(Alignment::Center),
))
.padding(10)
@@ -60,25 +69,22 @@ pub fn view(
text_editor(editor_content)
.on_action(Message::EditorAction)
.font(Font::MONOSPACE)
- .highlight_with::<Highlighter>(
+ .highlight_with::<Highlighter<Theme>>(
Settings::new(vec![], highlight_style, "rs"),
Highlight::to_format,
)
.style(|theme, _| {
- let palette = theme.extended_palette();
+ let style = material_theme::text_editor::default(
+ theme,
+ text_editor::Status::Active,
+ );
+
text_editor::Style {
- background: Background::Color(
- palette.background.base.color,
- ),
border: Border {
- radius: 2.into(),
- width: 1.0,
- color: palette.background.strong.color,
+ radius: Radius::default(),
+ ..style.border
},
- icon: palette.background.weak.text,
- placeholder: palette.background.strong.color,
- value: palette.background.base.text,
- selection: palette.primary.weak.color,
+ ..style
}
})
.height(Length::Fill)
diff --git a/src/panes/designer_view.rs b/src/panes/designer_view.rs
index af72022..0255b40 100644
--- a/src/panes/designer_view.rs
+++ b/src/panes/designer_view.rs
@@ -1,7 +1,8 @@
use iced::widget::{
button, center, container, pane_grid, responsive, row, text, themer,
};
-use iced::{Alignment, Element, Length};
+use iced::{Alignment, Length};
+use material_theme::Theme;
use super::style;
use crate::icon;
@@ -11,8 +12,8 @@ pub fn view<'a>(
element_tree: Option<&'a RenderedElement>,
designer_theme: iced::Theme,
is_focused: bool,
-) -> pane_grid::Content<'a, Message> {
- let el_tree: Element<'a, Message> = match element_tree {
+) -> pane_grid::Content<'a, Message, Theme> {
+ let el_tree: iced::Element<'a, Message> = match element_tree {
Some(tree) => responsive(|size| {
center(
container(tree.clone())
diff --git a/src/panes/element_list.rs b/src/panes/element_list.rs
index 594c203..0e5dbfe 100644
--- a/src/panes/element_list.rs
+++ b/src/panes/element_list.rs
@@ -1,9 +1,10 @@
use iced::widget::{Column, column, container, pane_grid, text};
-use iced::{Alignment, Element, Length};
+use iced::{Alignment, Length};
use iced_drop::droppable;
+use material_theme::Theme;
use super::style;
-use crate::types::{ElementName, Message};
+use crate::types::{Element, ElementName, Message};
fn items_list_view<'a>() -> Element<'a, Message> {
let mut column = Column::new()
@@ -25,7 +26,7 @@ fn items_list_view<'a>() -> Element<'a, Message> {
.into()
}
-pub fn view<'a>(is_focused: bool) -> pane_grid::Content<'a, Message> {
+pub fn view<'a>(is_focused: bool) -> pane_grid::Content<'a, Message, Theme> {
let items_list = items_list_view();
let content = column![items_list]
.align_x(Alignment::Center)
diff --git a/src/panes/style.rs b/src/panes/style.rs
index 1eefb2d..acca6f9 100644
--- a/src/panes/style.rs
+++ b/src/panes/style.rs
@@ -1,24 +1,25 @@
use iced::widget::container::Style;
-use iced::{Border, Theme};
+use iced::{Background, Border};
+use material_theme::Theme;
pub fn title_bar(theme: &Theme) -> Style {
- let palette = theme.extended_palette();
+ let surface = theme.colors().surface;
Style {
- text_color: Some(palette.background.strong.text),
- background: Some(palette.background.strong.color.into()),
+ text_color: Some(surface.on_surface),
+ background: Some(Background::Color(surface.surface_container.high)),
..Default::default()
}
}
pub fn pane_active(theme: &Theme) -> Style {
- let palette = theme.extended_palette();
+ let surface = theme.colors().surface;
Style {
- background: Some(palette.background.weak.color.into()),
+ background: Some(Background::Color(surface.surface_container.low)),
border: Border {
width: 1.0,
- color: palette.background.strong.color,
+ color: surface.surface_container.high,
..Border::default()
},
..Default::default()
@@ -26,13 +27,13 @@ pub fn pane_active(theme: &Theme) -> Style {
}
pub fn pane_focused(theme: &Theme) -> Style {
- let palette = theme.extended_palette();
+ let surface = theme.colors().surface;
Style {
- background: Some(palette.background.weak.color.into()),
+ background: Some(Background::Color(surface.surface_container.low)),
border: Border {
- width: 4.0,
- color: palette.background.strong.color,
+ width: 2.0,
+ color: surface.surface_container.high,
..Border::default()
},
..Default::default()
diff --git a/src/theme.rs b/src/theme.rs
deleted file mode 100644
index b721ddc..0000000
--- a/src/theme.rs
+++ /dev/null
@@ -1,357 +0,0 @@
-use std::sync::Arc;
-
-use iced::Color;
-use iced::theme::palette::Extended;
-use serde::Deserialize;
-
-use crate::config::Config;
-
-const DEFAULT_THEME_CONTENT: &str =
- include_str!("../assets/themes/rose_pine.toml");
-
-pub fn theme_index(theme_name: &str, slice: &[iced::Theme]) -> Option<usize> {
- slice
- .iter()
- .position(|theme| theme.to_string() == theme_name)
-}
-
-pub fn theme_from_str(
- config: Option<&Config>,
- theme_name: &str,
-) -> iced::Theme {
- match theme_name {
- "Light" => iced::Theme::Light,
- "Dark" => iced::Theme::Dark,
- "Dracula" => iced::Theme::Dracula,
- "Nord" => iced::Theme::Nord,
- "Solarized Light" => iced::Theme::SolarizedLight,
- "Solarized Dark" => iced::Theme::SolarizedDark,
- "Gruvbox Light" => iced::Theme::GruvboxLight,
- "Gruvbox Dark" => iced::Theme::GruvboxDark,
- "Catppuccin Latte" => iced::Theme::CatppuccinLatte,
- "Catppuccin Frappé" => iced::Theme::CatppuccinFrappe,
- "Catppuccin Macchiato" => iced::Theme::CatppuccinMacchiato,
- "Catppuccin Mocha" => iced::Theme::CatppuccinMocha,
- "Tokyo Night" => iced::Theme::TokyoNight,
- "Tokyo Night Storm" => iced::Theme::TokyoNightStorm,
- "Tokyo Night Light" => iced::Theme::TokyoNightLight,
- "Kanagawa Wave" => iced::Theme::KanagawaWave,
- "Kanagawa Dragon" => iced::Theme::KanagawaDragon,
- "Kanagawa Lotus" => iced::Theme::KanagawaLotus,
- "Moonfly" => iced::Theme::Moonfly,
- "Nightfly" => iced::Theme::Nightfly,
- "Oxocarbon" => iced::Theme::Oxocarbon,
- "Ferra" => iced::Theme::Ferra,
- _ => {
- if let Some(config) = config {
- if theme_name == config.theme.selected.to_string() {
- config.theme.selected.clone()
- } else if let Some(index) =
- theme_index(theme_name, &config.theme.all)
- {
- config.theme.all[index].clone()
- } else {
- iced::Theme::default()
- }
- } else {
- iced::Theme::default()
- }
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct Appearance {
- pub selected: iced::Theme,
- pub all: Arc<[iced::Theme]>,
-}
-
-impl Default for Appearance {
- fn default() -> Self {
- Self {
- selected: Theme::default().into(),
- all: {
- let mut themes = iced::Theme::ALL.to_owned();
- themes.push(Theme::default().into());
- themes.into()
- },
- }
- }
-}
-
-#[derive(Debug, Deserialize)]
-pub struct Theme {
- name: String,
- palette: ThemePalette,
- dark: Option<bool>,
- #[serde(flatten)]
- extended: Option<ExtendedThemePalette>,
-}
-
-impl From<Theme> for iced::Theme {
- fn from(value: Theme) -> Self {
- iced::Theme::custom_with_fn(
- value.name.clone(),
- value.palette.into(),
- |_| value.into(),
- )
- }
-}
-
-impl Default for Theme {
- fn default() -> Self {
- toml::from_str(DEFAULT_THEME_CONTENT).expect("parse default theme")
- }
-}
-
-#[derive(Debug, Clone, Copy, Deserialize)]
-pub struct ThemePalette {
- #[serde(with = "color_serde")]
- background: Color,
- #[serde(with = "color_serde")]
- text: Color,
- #[serde(with = "color_serde")]
- primary: Color,
- #[serde(with = "color_serde")]
- success: Color,
- #[serde(with = "color_serde")]
- danger: Color,
- #[serde(with = "color_serde")]
- warning: Color,
-}
-
-impl Default for ThemePalette {
- fn default() -> Self {
- let palette = iced::Theme::default().palette();
- Self {
- background: palette.background,
- text: palette.text,
- primary: palette.primary,
- success: palette.success,
- danger: palette.danger,
- warning: palette.warning,
- }
- }
-}
-
-impl From<ThemePalette> for iced::theme::Palette {
- fn from(palette: ThemePalette) -> Self {
- iced::theme::Palette {
- background: palette.background,
- text: palette.text,
- primary: palette.primary,
- success: palette.success,
- danger: palette.danger,
- warning: palette.warning,
- }
- }
-}
-
-impl From<Theme> for Extended {
- fn from(theme: Theme) -> Self {
- let mut extended = Extended::generate(theme.palette.into());
-
- if let Some(is_dark) = theme.dark {
- extended.is_dark = is_dark;
- }
-
- if let Some(extended_palette) = theme.extended {
- if let Some(background) = extended_palette.background {
- if let Some(base) = background.base {
- extended.background.base = base.into();
- }
- if let Some(weak) = background.weak {
- extended.background.weak = weak.into();
- }
- if let Some(strong) = background.strong {
- extended.background.strong = strong.into();
- }
- }
-
- if let Some(primary) = extended_palette.primary {
- if let Some(base) = primary.base {
- extended.primary.base = base.into();
- }
- if let Some(weak) = primary.weak {
- extended.primary.weak = weak.into();
- }
- if let Some(strong) = primary.strong {
- extended.primary.strong = strong.into();
- }
- }
-
- if let Some(secondary) = extended_palette.secondary {
- if let Some(base) = secondary.base {
- extended.secondary.base = base.into();
- }
- if let Some(weak) = secondary.weak {
- extended.secondary.weak = weak.into();
- }
- if let Some(strong) = secondary.strong {
- extended.secondary.strong = strong.into();
- }
- }
-
- if let Some(success) = extended_palette.success {
- if let Some(base) = success.base {
- extended.success.base = base.into();
- }
- if let Some(weak) = success.weak {
- extended.success.weak = weak.into();
- }
- if let Some(strong) = success.strong {
- extended.success.strong = strong.into();
- }
- }
-
- if let Some(danger) = extended_palette.danger {
- if let Some(base) = danger.base {
- extended.danger.base = base.into();
- }
- if let Some(weak) = danger.weak {
- extended.danger.weak = weak.into();
- }
- if let Some(strong) = danger.strong {
- extended.danger.strong = strong.into();
- }
- }
-
- if let Some(warning) = extended_palette.warning {
- if let Some(base) = warning.base {
- extended.warning.base = base.into();
- }
- if let Some(weak) = warning.weak {
- extended.warning.weak = weak.into();
- }
- if let Some(strong) = warning.strong {
- extended.warning.strong = strong.into();
- }
- }
- }
-
- extended
- }
-}
-
-#[derive(Debug, Clone, Copy, Default, Deserialize)]
-struct ExtendedThemePalette {
- background: Option<ThemeBackground>,
- primary: Option<ThemePrimary>,
- secondary: Option<ThemeSecondary>,
- success: Option<ThemeSuccess>,
- danger: Option<ThemeDanger>,
- warning: Option<ThemeWarning>,
-}
-
-#[derive(Debug, Clone, Copy, Default, Deserialize)]
-struct ThemeBackground {
- base: Option<ThemePair>,
- weak: Option<ThemePair>,
- strong: Option<ThemePair>,
-}
-
-#[derive(Debug, Clone, Copy, Default, Deserialize)]
-struct ThemePrimary {
- base: Option<ThemePair>,
- weak: Option<ThemePair>,
- strong: Option<ThemePair>,
-}
-
-#[derive(Debug, Clone, Copy, Default, Deserialize)]
-struct ThemeSecondary {
- base: Option<ThemePair>,
- weak: Option<ThemePair>,
- strong: Option<ThemePair>,
-}
-
-#[derive(Debug, Clone, Copy, Default, Deserialize)]
-struct ThemeSuccess {
- base: Option<ThemePair>,
- weak: Option<ThemePair>,
- strong: Option<ThemePair>,
-}
-
-#[derive(Debug, Clone, Copy, Default, Deserialize)]
-struct ThemeDanger {
- base: Option<ThemePair>,
- weak: Option<ThemePair>,
- strong: Option<ThemePair>,
-}
-
-#[derive(Debug, Clone, Copy, Default, Deserialize)]
-struct ThemeWarning {
- base: Option<ThemePair>,
- weak: Option<ThemePair>,
- strong: Option<ThemePair>,
-}
-
-#[derive(Debug, Clone, Copy, Default, Deserialize)]
-struct ThemePair {
- #[serde(with = "color_serde")]
- color: Color,
- #[serde(with = "color_serde")]
- text: Color,
-}
-
-impl From<ThemePair> for iced::theme::palette::Pair {
- fn from(pair: ThemePair) -> Self {
- Self {
- color: pair.color,
- text: pair.text,
- }
- }
-}
-
-pub fn parse_argb(s: &str) -> Option<Color> {
- let hex = s.strip_prefix('#').unwrap_or(s);
-
- let parse_channel = |from: usize, to: usize| {
- let num =
- usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0;
-
- // If we only got half a byte (one letter), expand it into a full byte (two letters)
- Some(if from == to { num + num * 16.0 } else { num })
- };
-
- Some(match hex.len() {
- 3 => Color::from_rgb(
- parse_channel(0, 0)?,
- parse_channel(1, 1)?,
- parse_channel(2, 2)?,
- ),
- 4 => Color::from_rgba(
- parse_channel(1, 1)?,
- parse_channel(2, 2)?,
- parse_channel(3, 3)?,
- parse_channel(0, 0)?,
- ),
- 6 => Color::from_rgb(
- parse_channel(0, 1)?,
- parse_channel(2, 3)?,
- parse_channel(4, 5)?,
- ),
- 8 => Color::from_rgba(
- parse_channel(2, 3)?,
- parse_channel(4, 5)?,
- parse_channel(6, 7)?,
- parse_channel(0, 1)?,
- ),
- _ => None?,
- })
-}
-
-mod color_serde {
- use iced::Color;
- use serde::{Deserialize, Deserializer};
-
- use super::parse_argb;
-
- pub fn deserialize<'de, D>(deserializer: D) -> Result<Color, D::Error>
- where
- D: Deserializer<'de>,
- {
- Ok(String::deserialize(deserializer)
- .map(|hex| parse_argb(&hex))?
- .unwrap_or(Color::TRANSPARENT))
- }
-}
diff --git a/src/types.rs b/src/types.rs
index adb788e..608f285 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -8,16 +8,20 @@ pub use element_name::ElementName;
use iced::advanced::widget::Id;
use iced::widget::{pane_grid, text_editor};
use iced_anim::Event;
+use material_theme::Theme;
pub use project::Project;
pub use rendered_element::*;
use crate::Error;
use crate::config::Config;
+pub type Element<'a, Message> = iced::Element<'a, Message, Theme>;
+
+#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone)]
pub enum Message {
ConfigLoad(Result<Config, Error>),
- SwitchTheme(Event<iced::Theme>),
+ SwitchTheme(Event<Theme>),
CopyCode,
SwitchPage(DesignerPane),
EditorAction(text_editor::Action),
diff --git a/src/types/project.rs b/src/types/project.rs
index 91b2bb1..11789ac 100644
--- a/src/types/project.rs
+++ b/src/types/project.rs
@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use super::rendered_element::RenderedElement;
use crate::Error;
-use crate::theme::{theme_from_str, theme_index};
+use crate::appearance::iced_theme_from_str;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Project {
@@ -33,8 +33,8 @@ impl Project {
pub fn get_theme(&self) -> Theme {
match &self.theme {
- Some(theme) => theme_from_str(None, theme),
- None => Theme::default(),
+ Some(theme) => iced_theme_from_str(theme),
+ None => iced::Theme::default(),
}
}
@@ -90,20 +90,10 @@ impl Project {
Some(ref element_tree) => {
let (imports, view) = element_tree.codegen();
let theme = self.get_theme();
- let theme_code = theme.to_string().replace(" ", "");
- let mut theme_imports = "";
- if theme_index(&theme.to_string(), Theme::ALL).is_none() {
- if theme_code.contains("Extended") {
- theme_imports = "use iced::{{color,theme::{{Palette,palette::{{Extended,Background,Primary,Secondary,Success,Danger,Warning,Pair}}}}}};\n";
- } else {
- theme_imports = "use iced::{{color,theme::Palette}};\n";
- }
- }
let app_code = format!(
r#"// Automatically generated by iced Builder
use iced::{{widget::{{{imports}}},Element}};
-{theme_imports}
fn main() -> iced::Result {{
iced::application(State::default, State::update, State::view).title("{}").theme(State::theme).run()
@@ -130,7 +120,7 @@ impl State {{
Some(ref t) => t,
None => "New app",
},
- theme_code
+ theme.to_string().replace(" ", "")
);
let config = rust_format::Config::new_str()
.edition(Edition::Rust2021)
diff --git a/src/types/rendered_element.rs b/src/types/rendered_element.rs
index 9639299..020aa46 100755
--- a/src/types/rendered_element.rs
+++ b/src/types/rendered_element.rs
@@ -1,7 +1,7 @@
use std::collections::BTreeMap;
use iced::advanced::widget::Id;
-use iced::{Element, Length, widget};
+use iced::{Element, widget};
use serde::{Deserialize, Serialize};
use crate::Error;
@@ -171,34 +171,6 @@ impl RenderedElement {
self
}
- pub fn text_view<'a>(self) -> Element<'a, Message> {
- let mut children = widget::column![];
-
- if let Some(els) = self.child_elements.clone() {
- for el in els {
- children = children.push(el.clone().text_view());
- }
- }
- iced_drop::droppable(
- widget::container(
- widget::column![
- widget::text(self.name.clone().to_string()),
- children
- ]
- .width(Length::Fill)
- .spacing(10),
- )
- .padding(10)
- .style(widget::container::bordered_box),
- )
- .id(self.id().clone())
- .drag_hide(true)
- .on_drop(move |point, rect| {
- Message::MoveElement(self.clone(), point, rect)
- })
- .into()
- }
-
pub fn codegen(&self) -> (String, String) {
let mut imports = String::new();
let mut view = String::new();
diff --git a/src/widget.rs b/src/widget.rs
index f1eb0f3..859d25e 100644
--- a/src/widget.rs
+++ b/src/widget.rs
@@ -1,5 +1,7 @@
-use iced::Element;
-use iced::widget::{container, text, tooltip};
+use iced::widget::{self, container, text, tooltip};
+use material_theme::Theme;
+
+use crate::types::Element;
pub mod tip {
pub use super::tooltip::Position;
@@ -12,10 +14,16 @@ pub fn tip<'a, Message: 'a>(
) -> Element<'a, Message> {
tooltip(
target,
- container(text(tip).size(14))
- .padding(5)
- .style(container::rounded_box),
+ container(text(tip).size(14)).padding(5).style(|theme| {
+ let base = material_theme::container::surface_container_low(theme);
+ container::Style {
+ border: iced::border::rounded(4),
+ ..base
+ }
+ }),
position,
)
.into()
}
+
+pub type Text<'a> = widget::Text<'a, Theme>;
diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs
index b4a7731..cba4377 100644
--- a/theme_test/src/main.rs
+++ b/theme_test/src/main.rs
@@ -18,7 +18,7 @@ use material_theme::text::surface_variant;
fn main() -> iced::Result {
iced::application(State::default, State::update, State::view)
- .theme(|state| *state.theme.value())
+ .theme(|state| state.theme.value().clone())
.run()
}