diff --git a/crates/ui/assets/code_sample.rb b/assets/ruby/code_sample.rb similarity index 100% rename from crates/ui/assets/code_sample.rb rename to assets/ruby/code_sample.rb diff --git a/crates/ui/assets/preset_catppuccin_frappe.ron b/assets/themes/catppuccin_frappe.ron similarity index 100% rename from crates/ui/assets/preset_catppuccin_frappe.ron rename to assets/themes/catppuccin_frappe.ron diff --git a/crates/ui/assets/preset_catppuccin_latte.ron b/assets/themes/catppuccin_latte.ron similarity index 100% rename from crates/ui/assets/preset_catppuccin_latte.ron rename to assets/themes/catppuccin_latte.ron diff --git a/crates/ui/assets/preset_catppuccin_macchiato.ron b/assets/themes/catppuccin_macchiato.ron similarity index 100% rename from crates/ui/assets/preset_catppuccin_macchiato.ron rename to assets/themes/catppuccin_macchiato.ron diff --git a/crates/ui/assets/preset_catppuccin_mocha.ron b/assets/themes/catppuccin_mocha.ron similarity index 100% rename from crates/ui/assets/preset_catppuccin_mocha.ron rename to assets/themes/catppuccin_mocha.ron diff --git a/crates/config/src/terminal/mod.rs b/crates/config/src/terminal/mod.rs index d68ff121..cc7cb795 100644 --- a/crates/config/src/terminal/mod.rs +++ b/crates/config/src/terminal/mod.rs @@ -57,126 +57,6 @@ impl Default for Config { } } -// pub struct ConfigUi { -// font_family: FontFamily, -// font_size: f32, -// } - -// #[derive(PartialEq, Eq)] -// #[derive(strum::EnumIter, strum::Display)] -// enum FontFamily { -// Proportional, -// Monospace, -// Custom(String), -// } - -// impl ConfigUi { -// pub fn new(config: &Config) -> Self { -// Self { -// font_family: match &config.font.family { -// egui::FontFamily::Monospace => FontFamily::Monospace, -// egui::FontFamily::Proportional => FontFamily::Proportional, -// egui::FontFamily::Name(n) => FontFamily::Custom(n.to_string()), -// }, -// font_size: config.font.size, -// } -// } - -// pub fn ui(&mut self, config: &mut Config, ui: &mut egui::Ui) { -// ui.horizontal(|ui| { -// ui.label("Initial terminal size:"); - -// egui::DragValue::new(&mut config.initial_size.0) -// .clamp_range(1..=999) -// .ui(ui); -// ui.label("column(s)"); - -// egui::DragValue::new(&mut config.initial_size.1) -// .clamp_range(1..=999) -// .ui(ui); -// ui.label("rows(s)"); -// }); - -// ui.horizontal(|ui| { -// ui.label("Font family"); -// luminol_components::EnumMenuButton::new( -// &mut self.font_family, -// "luminol_term_config_ui_font_family", -// ) -// .ui(ui); - -// let is_custom = matches!(self.font_family, FontFamily::Custom(_)); -// ui.add_enabled_ui(is_custom, |ui| { -// let mut dummy_text = String::new(); // this doesn't allocate so this is fine, for display purposes - -// let text = match &mut self.font_family { -// FontFamily::Custom(t) => t, -// _ => &mut dummy_text, -// }; -// ui.text_edit_singleline(text); -// }); - -// ui.label("Font size"); -// egui::DragValue::new(&mut self.font_size) -// .clamp_range(1..=80) -// .update_while_editing(false) -// .ui(ui); - -// if ui.button("Apply").clicked() { -// config.font.family = match &self.font_family { -// FontFamily::Monospace => egui::FontFamily::Monospace, -// FontFamily::Proportional => egui::FontFamily::Proportional, -// FontFamily::Custom(name) => egui::FontFamily::Name(name.as_str().into()), // FIXME doesn't properly handle missing fonts -// }; -// config.font.size = self.font_size; -// } -// }); - -// luminol_components::Field::new( -// "Cursor blinking", -// luminol_components::EnumComboBox::new( -// "luminol_term_config_ui_cursor_blinking", -// &mut config.cursor_blinking, -// ) -// .max_width(12.), -// ) -// .ui(ui); - -// ui.add_space(6.); -// ui.label("Ui colors"); -// ui.separator(); - -// ui.columns(2, |cols| { -// let [left, right] = cols else { -// unreachable!(); -// }; - -// left.label("Cursor"); -// let mut arr = color_to_rgb(config.theme.cursor_color); -// left.color_edit_button_srgb(&mut arr); -// config.theme.cursor_color = color_from_rgb(arr); - -// right.label("Background"); -// let mut arr = color_to_rgb(config.theme.background_color); -// right.color_edit_button_srgb(&mut arr); -// config.theme.background_color = color_from_rgb(arr); -// }); - -// ui.add_space(6.); -// ui.label("Pallette"); - -// for colors in config.theme.color_pallette.chunks_mut(8) { -// ui.horizontal(|ui| { -// for color in colors { -// let mut arr = color_to_rgb(*color); -// ui.color_edit_button_srgb(&mut arr); -// *color = color_from_rgb(arr); -// } -// }); -// } -// } -// } - impl Config { pub fn default_font() -> egui::FontId { egui::FontId { @@ -185,12 +65,3 @@ impl Config { } } } - -// fn color_to_rgb(color: egui::Color32) -> [u8; 3] { -// let [r, g, b, _] = color.to_array(); -// [r, g, b] -// } - -// fn color_from_rgb([r, g, b]: [u8; 3]) -> egui::Color32 { -// egui::Color32::from_rgb(r, g, b) -// } diff --git a/crates/proc-macros/src/lib.rs b/crates/proc-macros/src/lib.rs index 7445b759..2344913b 100644 --- a/crates/proc-macros/src/lib.rs +++ b/crates/proc-macros/src/lib.rs @@ -21,3 +21,23 @@ pub fn include_asset(input: TokenStream) -> TokenStream { }; tokens.into() } + +#[proc_macro] +pub fn include_asset_str(input: TokenStream) -> TokenStream { + let path: syn::LitStr = syn::parse(input).expect("Not a string literal"); + let path = path.value(); + + // asset path + let path = path.strip_prefix("assets/").unwrap_or(&path); + + let assets_path = std::env::var("LUMINOL_ASSETS_PATH").expect("luminol asset path not present"); + let assets_path = std::path::PathBuf::from(assets_path); + + let asset_path = assets_path.join(path); + let asset_path_str = asset_path.to_string_lossy(); + + let tokens = quote::quote! { + include_str!(#asset_path_str) + }; + tokens.into() +} diff --git a/crates/ui/src/windows/preferences.rs b/crates/ui/src/windows/preferences.rs index 570b6829..91237839 100644 --- a/crates/ui/src/windows/preferences.rs +++ b/crates/ui/src/windows/preferences.rs @@ -21,6 +21,7 @@ // it with Steamworks API by Valve Corporation, containing parts covered by // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. +use egui::Widget; use std::ops::Not; use strum::IntoEnumIterator; @@ -37,31 +38,38 @@ pub struct Window { #[derive(strum::EnumIter, strum::Display)] enum AppearanceMode { #[default] + #[strum(to_string = "Editor Settings")] + EditorSettings, #[strum(to_string = "Egui Visuals")] EguiVisuals, #[strum(to_string = "Preset Visuals")] PresetVisuals, #[strum(to_string = "Code Theme")] CodeTheme, + Terminal, } -const CODE_SAMPLE: &str = include_str!("../../assets/code_sample.rb"); +const CODE_SAMPLE: &str = luminol_macros::include_asset_str!("assets/ruby/code_sample.rb"); static PRESET_VISUALS: once_cell::sync::Lazy<[(&str, egui::Visuals); 6]> = once_cell::sync::Lazy::new(|| { // - let catppuccin_frappe = - ron::from_str(include_str!("../../assets/preset_catppuccin_frappe.ron")) - .expect("failed to load catpuccin frappe preset theme"); - let catppuccin_latte = - ron::from_str(include_str!("../../assets/preset_catppuccin_latte.ron")) - .expect("failed to load catpuccin frappe preset theme"); - let catppuccin_macchiato = - ron::from_str(include_str!("../../assets/preset_catppuccin_macchiato.ron")) - .expect("failed to load catpuccin frappe preset theme"); - let catppuccin_mocha = - ron::from_str(include_str!("../../assets/preset_catppuccin_mocha.ron")) - .expect("failed to load catpuccin frappe preset theme"); + let catppuccin_frappe = ron::from_str(luminol_macros::include_asset_str!( + "assets/themes/catppuccin_frappe.ron" + )) + .expect("failed to load catpuccin frappe preset theme"); + let catppuccin_latte = ron::from_str(luminol_macros::include_asset_str!( + "assets/themes/catppuccin_latte.ron" + )) + .expect("failed to load catpuccin frappe preset theme"); + let catppuccin_macchiato = ron::from_str(luminol_macros::include_asset_str!( + "assets/themes/catppuccin_macchiato.ron" + )) + .expect("failed to load catpuccin frappe preset theme"); + let catppuccin_mocha = ron::from_str(luminol_macros::include_asset_str!( + "assets/themes/catppuccin_mocha.ron" + )) + .expect("failed to load catpuccin frappe preset theme"); let egui_dark = egui::Visuals::dark(); let egui_light = egui::Visuals::light(); @@ -92,52 +100,9 @@ impl luminol_core::Window for Window { update_state: &mut luminol_core::UpdateState<'_>, ) { egui::Window::new(self.name()).open(open).show(ctx, |ui| { - ui.label("RTP Paths"); - ui.separator(); - - ui.columns(2, |columns| { - let mut new_rtp_paths = update_state - .global_config - .rtp_paths - .drain() - .filter_map(|(mut rtp_name, mut rtp_path)| { - columns[0].text_edit_singleline(&mut rtp_name); - columns[1] - .horizontal(|ui| { - ui.text_edit_singleline(&mut rtp_path); - ui.button(egui::RichText::new("-").color(egui::Color32::RED)) - .clicked() - .not() - .then_some((rtp_name, rtp_path)) - }) - .inner - }) - .collect::>(); - - columns[0].text_edit_singleline(&mut self.edit_rtp_path_name); - columns[1].horizontal(|ui| { - ui.text_edit_singleline(&mut self.edit_rtp_path_path); - - if ui - .button(egui::RichText::new("+").color(egui::Color32::GREEN)) - .clicked() - { - new_rtp_paths.insert( - std::mem::take(&mut self.edit_rtp_path_name), - std::mem::take(&mut self.edit_rtp_path_path), - ); - } - }); - - update_state.global_config.rtp_paths = new_rtp_paths; - }); - - ui.separator(); - ui.horizontal(|ui| { for mode in AppearanceMode::iter() { ui.selectable_value(&mut self.appearance_mode, mode, mode.to_string()); - ui.separator(); } }); ui.separator(); @@ -149,10 +114,13 @@ impl luminol_core::Window for Window { visuals.ui(ui); ctx.set_visuals(visuals); } - AppearanceMode::PresetVisuals => { + AppearanceMode::PresetVisuals => ui.columns(2, |cols| { + let [left, right] = cols else { unreachable!() }; + + left.visuals_mut().button_frame = false; let mut hover_visual = None; for (name, visual) in PRESET_VISUALS.iter().cloned() { - let response = ui.button(name); + let response = left.button(name); if response.hovered() { hover_visual = Some(visual.clone()); } @@ -162,13 +130,21 @@ impl luminol_core::Window for Window { } if let Some(hover_visual) = hover_visual { - let original_visual = ctx.style().visuals.clone(); + *right.visuals_mut() = hover_visual; + }; - ctx.set_visuals(hover_visual); - egui::Window::new("Preset Theme Demo Window").show(ctx, |ui| {}); - ctx.set_visuals(original_visual); - } - } + let panel_rect = right.available_rect_before_wrap(); + let mut panel_ui = + right.child_ui(panel_rect, egui::Layout::top_down(egui::Align::Min)); + + let frame = egui::Frame { + shadow: egui::epaint::Shadow::NONE, + ..egui::Frame::window(right.style()) + }; + frame.show(&mut panel_ui, |ui| { + ui.button("daskdjhvasjddahj"); + }); + }), AppearanceMode::CodeTheme => { ui.horizontal(|ui| { ui.vertical(|ui| { @@ -192,7 +168,140 @@ impl luminol_core::Window for Window { }); }); } + AppearanceMode::EditorSettings => { + ui.label("RTP Paths"); + ui.separator(); + + ui.columns(2, |columns| { + let mut new_rtp_paths = update_state + .global_config + .rtp_paths + .drain() + .filter_map(|(mut rtp_name, mut rtp_path)| { + columns[0].text_edit_singleline(&mut rtp_name); + columns[1] + .horizontal(|ui| { + ui.text_edit_singleline(&mut rtp_path); + ui.button( + egui::RichText::new("-").color(egui::Color32::RED), + ) + .clicked() + .not() + .then_some((rtp_name, rtp_path)) + }) + .inner + }) + .collect::>(); + + columns[0].text_edit_singleline(&mut self.edit_rtp_path_name); + columns[1].horizontal(|ui| { + ui.text_edit_singleline(&mut self.edit_rtp_path_path); + + if ui + .button(egui::RichText::new("+").color(egui::Color32::GREEN)) + .clicked() + { + new_rtp_paths.insert( + std::mem::take(&mut self.edit_rtp_path_name), + std::mem::take(&mut self.edit_rtp_path_path), + ); + } + }); + + update_state.global_config.rtp_paths = new_rtp_paths; + }); + } + AppearanceMode::Terminal => { + let config = &mut update_state.global_config.terminal; + ui.horizontal(|ui| { + ui.label("Initial terminal size:"); + egui::DragValue::new(&mut config.initial_size.0) + .clamp_range(1..=999) + .ui(ui); + ui.label("column(s)"); + egui::DragValue::new(&mut config.initial_size.1) + .clamp_range(1..=999) + .ui(ui); + ui.label("rows(s)"); + }); + // ui.horizontal(|ui| { + // ui.label("Font family"); + // luminol_components::EnumMenuButton::new( + // &mut self.font_family, + // "luminol_term_config_ui_font_family", + // ) + // .ui(ui); + // let is_custom = matches!(self.font_family, FontFamily::Custom(_)); + // ui.add_enabled_ui(is_custom, |ui| { + // let mut dummy_text = String::new(); // this doesn't allocate so this is fine, for display purposes + // let text = match &mut self.font_family { + // FontFamily::Custom(t) => t, + // _ => &mut dummy_text, + // }; + // ui.text_edit_singleline(text); + // }); + // ui.label("Font size"); + // egui::DragValue::new(&mut self.font_size) + // .clamp_range(1..=80) + // .update_while_editing(false) + // .ui(ui); + // if ui.button("Apply").clicked() { + // config.font.family = match &self.font_family { + // FontFamily::Monospace => egui::FontFamily::Monospace, + // FontFamily::Proportional => egui::FontFamily::Proportional, + // FontFamily::Custom(name) => { + // egui::FontFamily::Name(name.as_str().into()) + // } // FIXME doesn't properly handle missing fonts + // }; + // config.font.size = self.font_size; + // } + // }); + luminol_components::Field::new( + "Cursor blinking", + luminol_components::EnumComboBox::new( + "luminol_term_config_ui_cursor_blinking", + &mut config.cursor_blinking, + ) + .max_width(12.), + ) + .ui(ui); + ui.add_space(6.); + ui.label("Ui colors"); + ui.separator(); + ui.columns(2, |cols| { + let [left, right] = cols else { + unreachable!(); + }; + left.label("Cursor"); + let mut arr = color_to_rgb(config.theme.cursor_color); + left.color_edit_button_srgb(&mut arr); + config.theme.cursor_color = color_from_rgb(arr); + right.label("Background"); + let mut arr = color_to_rgb(config.theme.background_color); + right.color_edit_button_srgb(&mut arr); + config.theme.background_color = color_from_rgb(arr); + }); + ui.add_space(6.); + ui.label("Pallette"); + for colors in config.theme.color_pallette.chunks_mut(8) { + ui.horizontal(|ui| { + for color in colors { + let mut arr = color_to_rgb(*color); + ui.color_edit_button_srgb(&mut arr); + *color = color_from_rgb(arr); + } + }); + } + } } }); } } + +fn color_to_rgb(color: egui::Color32) -> [u8; 3] { + let [r, g, b, _] = color.to_array(); + [r, g, b] +} +fn color_from_rgb([r, g, b]: [u8; 3]) -> egui::Color32 { + egui::Color32::from_rgb(r, g, b) +}