Skip to content

Commit 0f878cd

Browse files
committed
[*] refactor: video-editor
1 parent c9c02ed commit 0f878cd

File tree

3 files changed

+168
-38
lines changed

3 files changed

+168
-38
lines changed

wayshot/src/logic.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ macro_rules! global_util {
102102
};
103103
}
104104

105+
#[macro_export]
106+
macro_rules! global_ve_filter {
107+
($ui:expr) => {
108+
$ui.global::<crate::slint_generatedAppWindow::VEFilter>()
109+
};
110+
}
111+
105112
#[macro_export]
106113
macro_rules! logic_cb {
107114
($callback_name:ident, $ui:expr, $($arg:ident),*) => {

wayshot/src/logic/popup_action.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -277,19 +277,19 @@ pub fn init(ui: &AppWindow) {
277277
}
278278
"video-editor-up-filter" => {
279279
let index = user_data.parse::<i32>().unwrap();
280-
global_ve_filter!(ui).invoke_filter_up(&ui, index);
280+
global_ve_filter!(ui).invoke_up_filter(index);
281281
}
282282
"video-editor-down-filter" => {
283283
let index = user_data.parse::<i32>().unwrap();
284-
global_ve_filter!(ui).invoke_filter_down(&ui, index);
284+
global_ve_filter!(ui).invoke_down_filter(index);
285285
}
286286
"video-editor-remove-filter" => {
287287
let index = user_data.parse::<i32>().unwrap();
288-
global_ve_filter!(ui).invoke_filter_remove(&ui, index);
288+
global_ve_filter!(ui).invoke_remove_filter(index);
289289
}
290290
"video-editor-copy-filter" => {
291291
let index = user_data.parse::<i32>().unwrap();
292-
global_ve_filter!(ui).filter_copy(&ui, index);
292+
global_ve_filter!(ui).invoke_copy_filter(index);
293293
}
294294
_ => log::warn!("Unknown popup action: {action}"),
295295
}

wayshot/src/logic/video_editor/filter.rs

Lines changed: 157 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ use super::{
33
segment::refresh_affected_segments,
44
track::get_selected_segment_indices,
55
};
6-
use crate::{global_store, slint_generatedAppWindow::AppWindow};
7-
use slint::ComponentHandle;
6+
use crate::{global_store, global_ve_filter, slint_generatedAppWindow::{
7+
AppWindow, BrightnessDetail as UIBrightnessDetail, PresetFilter as UIPresetFilter,
8+
SegmentFilter as UISegmentFilter,
9+
}};
10+
use slint::{ComponentHandle, Model, SharedString, VecModel};
811
use video_editor::filters::{
912
audio::{
1013
CompressorFilter, FadeInFilter as AudioFadeInFilter, FadeOutFilter as AudioFadeOutFilter,
@@ -45,12 +48,6 @@ use video_editor::{
4548
tracks::track::Track,
4649
};
4750

48-
macro_rules! global_ve_filter {
49-
($ui:expr) => {
50-
$ui.global::<crate::slint_generatedAppWindow::VEFilter>()
51-
};
52-
}
53-
5451
#[macro_export]
5552
macro_rules! ve_filter_cb {
5653
($callback_name:ident, $ui:expr, $($arg:ident),*) => {
@@ -78,26 +75,18 @@ macro_rules! ve_filter_cb {
7875
}
7976

8077
pub fn init(ui: &AppWindow) {
81-
// ve_filter_cb!(up_filter, ui, index);
82-
// ve_filter_cb!(down_filter, ui, index);
83-
// ve_filter_cb!(remove_filter, ui, index);
84-
// ve_filter_cb!(toggle_filter, ui, index);
85-
// ve_filter_cb!(copy_filter, ui, index);
86-
// ve_filter_cb!(add_filter, ui, filter_name);
87-
88-
// Register add-filter callback
89-
let ui_weak = ui.as_weak();
90-
global_ve_filter!(ui).on_add_filter(move |filter_name| {
91-
let ui = ui_weak.unwrap();
92-
video_editor_filter_add(&ui, filter_name.to_string());
93-
});
94-
95-
// Register toggle-filter callback
96-
let ui_weak = ui.as_weak();
97-
global_ve_filter!(ui).on_toggle_filter(move |index| {
98-
let ui = ui_weak.unwrap();
99-
video_editor_filter_toggle(&ui, index);
100-
});
78+
ve_filter_cb!(up_filter, ui, index);
79+
ve_filter_cb!(down_filter, ui, index);
80+
ve_filter_cb!(remove_filter, ui, index);
81+
ve_filter_cb!(toggle_filter, ui, index);
82+
ve_filter_cb!(copy_filter, ui, index);
83+
ve_filter_cb!(add_filter, ui, filter_name);
84+
ve_filter_cb!(create_preset_filter, ui, name);
85+
ve_filter_cb!(add_preset_filter, ui, filter);
86+
ve_filter_cb!(add_cache_preset_filter, ui, filter);
87+
ve_filter_cb!(remove_cache_preset_filter, ui, filter);
88+
ve_filter_cb!(from_brightness_json, ui, json);
89+
ve_filter_cb!(modify_brightness_filter, ui, index, config);
10190
}
10291

10392
/// Get the current filter type based on the current track type
@@ -125,7 +114,7 @@ fn get_current_filter_type(ui: &AppWindow) -> FilterType {
125114
}
126115

127116
/// Move filter up in order
128-
pub fn filter_up(ui: &AppWindow, index: i32) {
117+
pub fn up_filter(ui: &AppWindow, index: i32) {
129118
let filter_index = index as usize;
130119
let filter_type = get_current_filter_type(ui);
131120

@@ -169,7 +158,7 @@ pub fn filter_up(ui: &AppWindow, index: i32) {
169158
}
170159

171160
/// Move filter down in order
172-
pub fn filter_down(ui: &AppWindow, index: i32) {
161+
pub fn down_filter(ui: &AppWindow, index: i32) {
173162
let filter_index = index as usize;
174163
let filter_type = get_current_filter_type(ui);
175164

@@ -209,7 +198,7 @@ pub fn filter_down(ui: &AppWindow, index: i32) {
209198
}
210199

211200
/// Remove a filter from selected segments
212-
pub fn filter_remove(ui: &AppWindow, index: i32) {
201+
pub fn remove_filter(ui: &AppWindow, index: i32) {
213202
let filter_index = index as usize;
214203
let filter_type = get_current_filter_type(ui);
215204

@@ -265,7 +254,7 @@ pub fn filter_remove(ui: &AppWindow, index: i32) {
265254
}
266255

267256
/// Toggle filter enabled state
268-
fn video_editor_filter_toggle(ui: &AppWindow, index: i32) {
257+
fn toggle_filter(ui: &AppWindow, index: i32) {
269258
let filter_index = index as usize;
270259
let filter_type = get_current_filter_type(ui);
271260

@@ -300,7 +289,7 @@ fn video_editor_filter_toggle(ui: &AppWindow, index: i32) {
300289
}
301290

302291
/// Copy filter to clipboard (for later pasting)
303-
pub fn filter_copy(ui: &AppWindow, index: i32) {
292+
pub fn copy_filter(ui: &AppWindow, index: i32) {
304293
let filter_index = index as usize;
305294
let filter_type = get_current_filter_type(ui);
306295

@@ -348,7 +337,8 @@ pub fn filter_copy(ui: &AppWindow, index: i32) {
348337
}
349338

350339
/// Add a filter to selected segments
351-
fn video_editor_filter_add(ui: &AppWindow, filter_name: String) {
340+
fn add_filter(ui: &AppWindow, filter_name: SharedString) {
341+
let filter_name = filter_name.to_string();
352342
let filter_type = get_current_filter_type(ui);
353343
let selected_segments = get_selected_segment_indices(ui);
354344

@@ -384,6 +374,139 @@ fn video_editor_filter_add(ui: &AppWindow, filter_name: String) {
384374
}
385375
}
386376

377+
/// Create a preset filter from cached filters
378+
fn create_preset_filter(ui: &AppWindow, name: slint::SharedString) {
379+
let cache_filters = global_ve_filter!(ui).get_cache_preset_filters();
380+
381+
if cache_filters.row_count() == 0 {
382+
crate::toast_warn!(ui, "No filters selected for preset");
383+
return;
384+
}
385+
386+
// Collect all SegmentFilters from the cached PresetFilters
387+
let mut all_filters: Vec<UISegmentFilter> = Vec::new();
388+
for preset in cache_filters.iter() {
389+
for seg_filter in preset.filters.iter() {
390+
all_filters.push(seg_filter);
391+
}
392+
}
393+
394+
let preset_filter = UIPresetFilter {
395+
name,
396+
filters: slint::ModelRc::from(std::rc::Rc::new(VecModel::from(all_filters))),
397+
};
398+
399+
// Add to video preset filters by default (can be extended for other types)
400+
let current_filters = global_ve_filter!(ui).get_video_preset_filters();
401+
let mut new_filters: Vec<UIPresetFilter> = current_filters.iter().collect();
402+
new_filters.push(preset_filter);
403+
404+
global_ve_filter!(ui).set_video_preset_filters(slint::ModelRc::from(std::rc::Rc::new(VecModel::from(new_filters))));
405+
406+
// Clear cache after creating preset
407+
global_ve_filter!(ui).set_cache_preset_filters(slint::ModelRc::default());
408+
409+
crate::toast_success!(ui, "Preset filter created");
410+
}
411+
412+
/// Add a preset filter to selected segments
413+
fn add_preset_filter(ui: &AppWindow, filter: UIPresetFilter) {
414+
let filter_type = get_current_filter_type(ui);
415+
let selected_segments = get_selected_segment_indices(ui);
416+
417+
if selected_segments.is_empty() {
418+
crate::toast_warn!(ui, "No segments selected");
419+
return;
420+
}
421+
422+
let mut batch_command = BatchCommand::new(format!("Add preset filter: {}", filter.name));
423+
424+
for segment_filter in filter.filters.iter() {
425+
let filter_name = segment_filter.name.to_string();
426+
427+
for (track_idx, seg_idx) in &selected_segments {
428+
let command =
429+
create_filter_command(*track_idx, *seg_idx, filter_type.clone(), &filter_name);
430+
if let Some(cmd) = command {
431+
batch_command.add_command(cmd);
432+
}
433+
}
434+
}
435+
436+
let result = with_history_manager(|state| {
437+
state
438+
.history_manager
439+
.execute(&mut state.tracks_manager, Box::new(batch_command))
440+
});
441+
442+
match result {
443+
Ok(execute_result) => {
444+
sync_manager_to_ui(ui);
445+
refresh_affected_segments(ui, execute_result.affected_segments);
446+
refresh_preview(ui);
447+
crate::toast_success!(ui, format!("Added preset filter: {}", filter.name));
448+
}
449+
Err(e) => crate::toast_warn!(ui, format!("Failed to add preset filter: {}", e)),
450+
}
451+
}
452+
453+
/// Add filter to cache for preset creation
454+
fn add_cache_preset_filter(ui: &AppWindow, filter: UISegmentFilter) {
455+
// Wrap the SegmentFilter in a PresetFilter for storage in cache-preset-filters
456+
let preset = UIPresetFilter {
457+
name: slint::SharedString::new(),
458+
filters: slint::ModelRc::from(std::rc::Rc::new(VecModel::from(vec![filter]))),
459+
};
460+
461+
let current_cache = global_ve_filter!(ui).get_cache_preset_filters();
462+
let mut new_cache: Vec<UIPresetFilter> = current_cache.iter().collect();
463+
new_cache.push(preset);
464+
global_ve_filter!(ui).set_cache_preset_filters(slint::ModelRc::from(std::rc::Rc::new(VecModel::from(new_cache))));
465+
}
466+
467+
/// Remove filter from cache for preset creation
468+
fn remove_cache_preset_filter(ui: &AppWindow, filter: UISegmentFilter) {
469+
let current_cache = global_ve_filter!(ui).get_cache_preset_filters();
470+
// Remove PresetFilters that contain a matching SegmentFilter
471+
let new_cache: Vec<UIPresetFilter> = current_cache
472+
.iter()
473+
.filter(|preset| {
474+
// Keep the preset if none of its filters match
475+
preset.filters.iter().all(|f| f.name != filter.name || f.detail != filter.detail)
476+
})
477+
.collect();
478+
global_ve_filter!(ui).set_cache_preset_filters(slint::ModelRc::from(std::rc::Rc::new(VecModel::from(new_cache))));
479+
}
480+
481+
/// Deserialize brightness config from JSON (pure callback)
482+
fn from_brightness_json(_ui: &AppWindow, json: slint::SharedString) -> UIBrightnessDetail {
483+
// Parse JSON and return BrightnessDetail
484+
match serde_json::from_str::<serde_json::Value>(json.as_str()) {
485+
Ok(value) => {
486+
let adjustment = value
487+
.get("adjustment")
488+
.and_then(|v| v.as_f64())
489+
.unwrap_or(0.0) as f32;
490+
UIBrightnessDetail { adjustment }
491+
}
492+
Err(_) => UIBrightnessDetail { adjustment: 0.0 },
493+
}
494+
}
495+
496+
/// Modify brightness filter configuration
497+
fn modify_brightness_filter(ui: &AppWindow, index: i32, config: UIBrightnessDetail) {
498+
// TODO: Implement proper filter modification through command pattern
499+
// This requires adding as_any_mut() to the VideoFilter trait or implementing
500+
// a ModifyFilterCommand in the video-editor library.
501+
log::warn!(
502+
"modify_brightness_filter called with index={}, adjustment={}",
503+
index,
504+
config.adjustment
505+
);
506+
// Refresh UI to reflect current state
507+
sync_manager_to_ui(ui);
508+
}
509+
387510
/// Get available video filter names
388511
#[allow(dead_code)]
389512
fn video_editor_filter_get_video_filters(_ui: &AppWindow, _flag: bool) -> Vec<String> {

0 commit comments

Comments
 (0)