use egui::{Context, Window};
use super::SettingsUI;
impl SettingsUI {
pub(super) fn show_create_shader_dialog_window(&mut self, ctx: &Context) {
if !self.show_create_shader_dialog {
return;
}
let mut close_dialog = false;
let mut create_shader = false;
Window::new("Create New Shader")
.collapsible(false)
.resizable(false)
.default_width(400.0)
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
.show(ctx, |ui| {
ui.label("Enter a name for the new shader file:");
ui.label("(will be saved as .glsl in the shaders folder)");
ui.add_space(8.0);
ui.horizontal(|ui| {
ui.label("Name:");
let response = ui.text_edit_singleline(&mut self.new_shader_name);
if response.lost_focus()
&& ui.input(|i| i.key_pressed(egui::Key::Enter))
&& !self.new_shader_name.is_empty()
{
create_shader = true;
}
});
ui.add_space(8.0);
ui.horizontal(|ui| {
if ui.button("Create").clicked() && !self.new_shader_name.is_empty() {
create_shader = true;
}
if ui.button("Cancel").clicked() {
close_dialog = true;
}
});
});
if create_shader {
close_dialog = self.create_shader_file();
}
if close_dialog {
self.show_create_shader_dialog = false;
self.new_shader_name.clear();
}
}
fn create_shader_file(&mut self) -> bool {
let mut filename = self.new_shader_name.clone();
if !filename.ends_with(".glsl")
&& !filename.ends_with(".frag")
&& !filename.ends_with(".shader")
{
filename.push_str(".glsl");
}
let shader_path = par_term_config::Config::shaders_dir().join(&filename);
if shader_path.exists() {
self.shader_editor_error = Some(format!("Shader '{}' already exists!", filename));
return false;
}
let template = r#"// Custom shader for par-term
// Available uniforms:
// iTime - Time in seconds (when animation enabled)
// iResolution - Viewport resolution (vec2)
// iChannel0-3 - User texture channels (sampler2D, Shadertoy compatible)
// iChannel4 - Terminal content texture (sampler2D)
// iOpacity - Window opacity (float)
// iTextOpacity - Text opacity (float)
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
// Sample terminal content
vec4 terminal = texture(iChannel4, uv);
// Example: simple color tint based on position
vec3 tint = vec3(0.8, 0.9, 1.0);
// Mix terminal content with effect
vec3 color = terminal.rgb * tint;
fragColor = vec4(color, terminal.a);
}
"#;
match std::fs::write(&shader_path, template) {
Ok(()) => {
log::info!("Created new shader: {}", shader_path.display());
self.refresh_shaders();
self.temp_custom_shader = filename.clone();
self.config.shader.custom_shader = Some(filename);
self.has_changes = true;
self.shader_editor_source = template.to_string();
self.shader_editor_original = template.to_string();
self.shader_editor_error = None;
self.shader_editor_visible = true;
true
}
Err(e) => {
self.shader_editor_error = Some(format!("Failed to create shader: {}", e));
false
}
}
}
pub(super) fn show_delete_shader_dialog_window(&mut self, ctx: &Context) {
if !self.show_delete_shader_dialog {
return;
}
let mut close_dialog = false;
let mut delete_shader = false;
let shader_name = self.temp_custom_shader.clone();
Window::new("Delete Shader")
.collapsible(false)
.resizable(false)
.default_width(350.0)
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
.show(ctx, |ui| {
ui.label(format!(
"Are you sure you want to delete '{}'?",
shader_name
));
ui.label("This action cannot be undone.");
ui.add_space(12.0);
ui.horizontal(|ui| {
if ui.button("Delete").clicked() {
delete_shader = true;
}
if ui.button("Cancel").clicked() {
close_dialog = true;
}
});
});
if delete_shader {
let shader_path = par_term_config::Config::shader_path(&shader_name);
match std::fs::remove_file(&shader_path) {
Ok(()) => {
log::info!("Deleted shader: {}", shader_path.display());
self.temp_custom_shader.clear();
self.config.shader.custom_shader = None;
self.has_changes = true;
self.refresh_shaders();
close_dialog = true;
}
Err(e) => {
self.shader_editor_error = Some(format!("Failed to delete shader: {}", e));
close_dialog = true;
}
}
}
if close_dialog {
self.show_delete_shader_dialog = false;
}
}
}