feat(iced): add filter instant preview

This commit is contained in:
2026-07-15 16:17:43 +03:00
parent c7082046aa
commit f2b03265ba
3 changed files with 53 additions and 5 deletions
@@ -350,6 +350,9 @@ pub enum Message {
FilterApply,
FilterReset,
FilterParamChanged(String, serde_json::Value),
FilterPreviewToggle(bool),
FilterPreviewApply,
FilterPreviewRestore,
// ── Dialogs ─────────────────────────────────────────
DialogOpen(ActiveDialog),
@@ -1768,6 +1771,46 @@ impl HcieIcedApp {
self.filter_params = serde_json::json!({});
}
Message::FilterPreviewToggle(enabled) => {
self.filter_preview_active = enabled;
if enabled {
// Start a new preview snapshot so restore can undo it
self.documents[self.active_doc].engine.filter_preview_begin();
// Apply the current filter with current params to show live preview
if let Some(filter) = self.selected_filter {
let filter_id = filter_type_to_id(filter);
self.documents[self.active_doc].engine.apply_filter_preview(filter_id, self.filter_params.clone());
self.refresh_composite_if_needed();
return Task::perform(async {}, |_| Message::CompositeRefresh);
}
} else {
// Restore original pixels
self.documents[self.active_doc].engine.filter_preview_restore();
self.refresh_composite_if_needed();
return Task::perform(async {}, |_| Message::CompositeRefresh);
}
}
Message::FilterPreviewApply => {
if let Some(filter) = self.selected_filter {
let filter_id = filter_type_to_id(filter);
self.documents[self.active_doc].engine.apply_filter(filter_id, self.filter_params.clone());
self.refresh_composite_if_needed();
self.filter_preview_active = false;
self.selected_filter = None;
self.filter_params = serde_json::json!({});
return Task::perform(async {}, |_| Message::CompositeRefresh);
}
}
Message::FilterPreviewRestore => {
if self.filter_preview_active {
self.documents[self.active_doc].engine.filter_preview_restore();
self.refresh_composite_if_needed();
return Task::perform(async {}, |_| Message::CompositeRefresh);
}
}
// ── Dialogs ───────────────────────────────────
Message::DialogOpen(dialog) => {
self.active_dialog = dialog;
@@ -66,7 +66,7 @@ pub fn dock_view<'a>(
)
}
PaneType::Filters => {
crate::panels::filters::view(app.selected_filter, &app.filter_params, colors)
crate::panels::filters::view(app.selected_filter, &app.filter_params, app.filter_preview_active, colors)
}
PaneType::ColorPicker => {
crate::color_picker::view(&app.fg_color, &app.bg_color, &app.recent_colors, app.color_tab)
@@ -5,7 +5,7 @@ use crate::app::Message;
use crate::panels::styles;
use crate::theme::ThemeColors;
use hcie_engine_api::FilterType;
use iced::widget::{button, column, container, horizontal_rule, row, scrollable, text};
use iced::widget::{button, checkbox, column, container, horizontal_rule, row, scrollable, text};
use iced::{Element, Length};
/// Filter category with its filters.
@@ -88,11 +88,12 @@ const FILTER_CATEGORIES: &[FilterCategory] = &[
/// Build the filters panel.
///
/// Shows the filter category list on top, and when a filter is selected,
/// displays its parameter editing panel below the list. The Apply/Reset
/// buttons are always at the bottom.
/// displays its parameter editing panel below the list. The preview checkbox,
/// Apply, and Reset buttons are always at the bottom.
pub fn view(
selected_filter: Option<FilterType>,
filter_params: &serde_json::Value,
filter_preview_active: bool,
colors: ThemeColors,
) -> Element<'static, Message> {
let mut filter_list = column![].spacing(2);
@@ -145,7 +146,11 @@ pub fn view(
.on_press(Message::FilterReset)
.padding([6, 12]);
let buttons = row![apply_btn, reset_btn].spacing(8);
let preview_check = checkbox("Preview", filter_preview_active)
.on_toggle(Message::FilterPreviewToggle)
.size(11);
let buttons = row![preview_check, apply_btn, reset_btn].spacing(8);
// When a filter is selected, show its parameter panel below the list.
let param_section = match selected_filter {