Skip to content

Commit 718547e

Browse files
committed
[*] refactor: video-editor
1 parent 3f50c98 commit 718547e

File tree

3 files changed

+135
-97
lines changed

3 files changed

+135
-97
lines changed

wayshot/src/logic/video_editor/segment.rs

Lines changed: 135 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use super::command::{sync_manager_to_ui, with_history_manager};
22
use crate::{
3-
logic::toast, logic_cb,
3+
global_store,
4+
logic::toast,
5+
logic_cb,
46
slint_generatedAppWindow::{
57
AppWindow, SelectedSegmentIndex as UISelectedSegmentIndex,
68
VideoEditorTrackSegment as UIVideoEditorTrackSegment,
@@ -10,28 +12,65 @@ use crate::{
1012
use slint::{ComponentHandle, Model, VecModel};
1113
use std::time::Duration;
1214
use video_editor::{
15+
Error,
1316
commands::{
1417
batch::BatchCommand,
1518
segment::{
1619
MoveSegmentToTimeCommand, RemoveSegmentCommand, ShrinkSegmentLeftCommand,
17-
ShrinkSegmentRightCommand, StretchSegmentLeftCommand, StretchSegmentRightCommand,
20+
ShrinkSegmentRightCommand, SplitSegmentCommand, StretchSegmentLeftCommand,
21+
StretchSegmentRightCommand,
1822
},
1923
},
2024
tracks::track::Track,
21-
Error,
2225
};
2326

2427
pub fn init(ui: &AppWindow) {
2528
logic_cb!(video_editor_add_selected_segment, ui, index);
26-
logic_cb!(video_editor_stretch_segment_left, ui, index, diff_duration_ms);
27-
logic_cb!(video_editor_shrink_segment_left, ui, index, diff_duration_ms);
28-
logic_cb!(video_editor_stretch_segment_right, ui, index, diff_duration_ms);
29-
logic_cb!(video_editor_shrink_segment_right, ui, index, diff_duration_ms);
30-
logic_cb!(video_editor_move_segment_to_left_timeoffet, ui, index, diff_duration_ms);
31-
logic_cb!(video_editor_move_segment_to_right_timeoffset, ui, index, diff_duration_ms);
32-
logic_cb!(video_editor_is_selected_segment, ui, selected_segment, index);
29+
logic_cb!(
30+
video_editor_stretch_segment_left,
31+
ui,
32+
index,
33+
diff_duration_ms
34+
);
35+
logic_cb!(
36+
video_editor_shrink_segment_left,
37+
ui,
38+
index,
39+
diff_duration_ms
40+
);
41+
logic_cb!(
42+
video_editor_stretch_segment_right,
43+
ui,
44+
index,
45+
diff_duration_ms
46+
);
47+
logic_cb!(
48+
video_editor_shrink_segment_right,
49+
ui,
50+
index,
51+
diff_duration_ms
52+
);
53+
logic_cb!(
54+
video_editor_move_segment_to_left_timeoffet,
55+
ui,
56+
index,
57+
diff_duration_ms
58+
);
59+
logic_cb!(
60+
video_editor_move_segment_to_right_timeoffset,
61+
ui,
62+
index,
63+
diff_duration_ms
64+
);
65+
logic_cb!(
66+
video_editor_is_selected_segment,
67+
ui,
68+
selected_segment,
69+
index
70+
);
3371
logic_cb!(video_editor_selected_segment, ui);
3472
logic_cb!(video_editor_remove_segments, ui);
73+
logic_cb!(video_editor_split_segment, ui);
3574
}
3675

3776
fn video_editor_add_selected_segment(ui: &AppWindow, index: UISelectedSegmentIndex) {
@@ -46,7 +85,8 @@ fn video_editor_add_selected_segment(ui: &AppWindow, index: UISelectedSegmentInd
4685

4786
if index.modifiers.control {
4887
if is_selected {
49-
selected_indices.retain(|s| !(s.track_index == index.track_index && s.index == index.index));
88+
selected_indices
89+
.retain(|s| !(s.track_index == index.track_index && s.index == index.index));
5090
} else {
5191
selected_indices.push(index.clone());
5292
}
@@ -58,7 +98,10 @@ fn video_editor_add_selected_segment(ui: &AppWindow, index: UISelectedSegmentInd
5898
let start = last.index.min(index.index);
5999
let end = last.index.max(index.index);
60100
for i in start..=end {
61-
if !selected_indices.iter().any(|s| s.track_index == index.track_index && s.index == i) {
101+
if !selected_indices
102+
.iter()
103+
.any(|s| s.track_index == index.track_index && s.index == i)
104+
{
62105
selected_indices.push(UISelectedSegmentIndex {
63106
track_index: index.track_index,
64107
index: i,
@@ -149,14 +192,15 @@ fn video_editor_selected_segment(ui: &AppWindow) -> UIVideoEditorTrackSegment {
149192

150193
if let Some((track_idx, seg_idx)) = selected_indices.first() {
151194
if let Some(segment_arc) = with_history_manager(|state| {
152-
state.tracks_manager.get(*track_idx).and_then(|track| {
153-
match track {
195+
state
196+
.tracks_manager
197+
.get(*track_idx)
198+
.and_then(|track| match track {
154199
Track::Video(inner) => inner.track.segments.get(*seg_idx).cloned(),
155200
Track::Audio(inner) => inner.track.segments.get(*seg_idx).cloned(),
156201
Track::Subtitle(inner) => inner.track.segments.get(*seg_idx).cloned(),
157202
Track::Overlay(inner) => inner.track.segments.get(*seg_idx).cloned(),
158-
}
159-
})
203+
})
160204
}) {
161205
let ui_segment: UIVideoEditorTrackSegment = segment_arc.into();
162206
return ui_segment;
@@ -196,9 +240,7 @@ fn video_editor_remove_segments(ui: &AppWindow) {
196240
for (track_idx, mut seg_indices) in segments_per_track {
197241
seg_indices.sort_by(|a, b| b.cmp(a)); // Sort descending
198242
for seg_idx in seg_indices {
199-
batch_command.add_command(Box::new(RemoveSegmentCommand::new(
200-
track_idx, seg_idx,
201-
)));
243+
batch_command.add_command(Box::new(RemoveSegmentCommand::new(track_idx, seg_idx)));
202244
}
203245
}
204246

@@ -221,11 +263,68 @@ fn video_editor_remove_segments(ui: &AppWindow) {
221263
});
222264
}
223265
Err(e) => {
224-
toast::async_toast_warn(
225-
ui_weak,
226-
format!("Failed to remove segments: {}", e),
227-
);
266+
toast::async_toast_warn(ui_weak, format!("Failed to remove segments: {}", e));
267+
}
268+
}
269+
});
270+
}
271+
272+
fn video_editor_split_segment(ui: &AppWindow) {
273+
let ui_weak = ui.as_weak();
274+
let timeline_offset_ms = global_store!(ui).get_video_editor_timeline_offset();
275+
let selected_segments = get_selected_segment_indices(&ui);
276+
277+
if selected_segments.len() != 1 {
278+
crate::toast_warn!(ui, "Please select exactly one segment to split".to_string());
279+
return;
280+
}
281+
282+
tokio::spawn(async move {
283+
let (track_index, segment_index) = selected_segments[0];
284+
285+
let result: Result<(), String> = with_history_manager(|state| {
286+
if track_index >= state.tracks_manager.len() {
287+
return Err(format!("Invalid track index: {}", track_index));
288+
}
289+
290+
if let Some(track) = state.tracks_manager.get(track_index) {
291+
let segments = match track {
292+
Track::Video(inner) => &inner.track.segments,
293+
Track::Audio(inner) => &inner.track.segments,
294+
Track::Subtitle(inner) => &inner.track.segments,
295+
Track::Overlay(inner) => &inner.track.segments,
296+
};
297+
298+
if segment_index >= segments.len() {
299+
return Err(format!("Invalid segment index: {}", segment_index));
300+
}
301+
302+
let seg = &segments[segment_index];
303+
304+
let segment_start = seg.timeline_offset.as_millis() as i32;
305+
let split_position = timeline_offset_ms - segment_start;
306+
307+
if split_position <= 0 || split_position >= seg.duration.as_millis() as i32 {
308+
return Err("Timeline cursor must be within the segment".to_string());
309+
}
310+
311+
let split_duration = Duration::from_millis(split_position as u64);
312+
let command = SplitSegmentCommand::new(track_index, segment_index, split_duration);
313+
state
314+
.history_manager
315+
.execute(&mut state.tracks_manager, Box::new(command))
316+
.map_err(|e| e.to_string())
317+
} else {
318+
Err("Track not found".to_string())
319+
}
320+
});
321+
322+
match result {
323+
Ok(_) => {
324+
sync_manager_to_ui(ui_weak.clone());
325+
toast::async_toast_success(ui_weak, "Segment split successfully".to_string());
228326
}
327+
Err(e) => toast::async_toast_warn(ui_weak, e.to_string()),
229328
}
230329
});
231330
}
@@ -246,7 +345,10 @@ fn modify_segment_duration(
246345

247346
let result = with_history_manager(|state| {
248347
if track_idx >= state.tracks_manager.len() {
249-
return Err(Error::IndexOutOfBounds(track_idx, state.tracks_manager.len()));
348+
return Err(Error::IndexOutOfBounds(
349+
track_idx,
350+
state.tracks_manager.len(),
351+
));
250352
}
251353

252354
let track = state
@@ -274,12 +376,8 @@ fn modify_segment_duration(
274376
.history_manager
275377
.execute(&mut state.tracks_manager, Box::new(command))
276378
} else {
277-
let command = ShrinkSegmentLeftCommand::new(
278-
track_idx,
279-
seg_idx,
280-
duration,
281-
shift_timeline,
282-
);
379+
let command =
380+
ShrinkSegmentLeftCommand::new(track_idx, seg_idx, duration, shift_timeline);
283381
state
284382
.history_manager
285383
.execute(&mut state.tracks_manager, Box::new(command))
@@ -335,7 +433,10 @@ fn move_segment(ui: &AppWindow, index: UISelectedSegmentIndex, diff_ms: i32) {
335433

336434
let result = with_history_manager(|state| {
337435
if track_idx >= state.tracks_manager.len() {
338-
return Err(Error::IndexOutOfBounds(track_idx, state.tracks_manager.len()));
436+
return Err(Error::IndexOutOfBounds(
437+
track_idx,
438+
state.tracks_manager.len(),
439+
));
339440
}
340441

341442
let track = state
@@ -358,8 +459,7 @@ fn move_segment(ui: &AppWindow, index: UISelectedSegmentIndex, diff_ms: i32) {
358459
current_offset + duration
359460
};
360461

361-
let command =
362-
MoveSegmentToTimeCommand::new(track_idx, seg_idx, new_offset, false);
462+
let command = MoveSegmentToTimeCommand::new(track_idx, seg_idx, new_offset, false);
363463

364464
state
365465
.history_manager
@@ -389,4 +489,5 @@ fn get_selected_segment_indices(ui: &AppWindow) -> Vec<(usize, usize)> {
389489
}
390490
})
391491
.collect()
392-
}
492+
}
493+

wayshot/src/logic/video_editor/track.rs

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use video_editor::{
1313
Error,
1414
commands::{
1515
BatchCommand,
16-
segment::SplitSegmentCommand,
1716
track::{
1817
AddTrackCommand, DetachAudioTracksCommand, DetachSubtitleTracksCommand,
1918
InsertTrackCommand, MoveTrackCommand, RemoveTrackCommand, ToggleTrackMutedCommand,
@@ -41,7 +40,6 @@ macro_rules! store_video_editor_selected_tracks_index {
4140
pub fn init(ui: &AppWindow) {
4241
logic_cb!(video_editor_add_track, ui, ty);
4342
logic_cb!(video_editor_remove_tracks, ui);
44-
logic_cb!(video_editor_split_segment, ui);
4543
logic_cb!(video_editor_track_move_up, ui, index);
4644
logic_cb!(video_editor_track_move_down, ui, index);
4745
logic_cb!(video_editor_insert_video_track, ui, index);
@@ -136,66 +134,6 @@ fn video_editor_remove_tracks(ui: &AppWindow) {
136134
});
137135
}
138136

139-
fn video_editor_split_segment(ui: &AppWindow) {
140-
let ui_weak = ui.as_weak();
141-
let timeline_offset_ms = global_store!(ui).get_video_editor_timeline_offset();
142-
let selected_segments = get_selected_segment_indices(&ui);
143-
144-
if selected_segments.len() != 1 {
145-
crate::toast_warn!(ui, "Please select exactly one segment to split".to_string());
146-
return;
147-
}
148-
149-
tokio::spawn(async move {
150-
let (track_index, segment_index) = selected_segments[0];
151-
152-
let result: Result<(), String> = with_history_manager(|state| {
153-
if track_index >= state.tracks_manager.len() {
154-
return Err(format!("Invalid track index: {}", track_index));
155-
}
156-
157-
if let Some(track) = state.tracks_manager.get(track_index) {
158-
let segments = match track {
159-
Track::Video(inner) => &inner.track.segments,
160-
Track::Audio(inner) => &inner.track.segments,
161-
Track::Subtitle(inner) => &inner.track.segments,
162-
Track::Overlay(inner) => &inner.track.segments,
163-
};
164-
165-
if segment_index >= segments.len() {
166-
return Err(format!("Invalid segment index: {}", segment_index));
167-
}
168-
169-
let seg = &segments[segment_index];
170-
171-
let segment_start = seg.timeline_offset.as_millis() as i32;
172-
let split_position = timeline_offset_ms - segment_start;
173-
174-
if split_position <= 0 || split_position >= seg.duration.as_millis() as i32 {
175-
return Err("Timeline cursor must be within the segment".to_string());
176-
}
177-
178-
let split_duration = Duration::from_millis(split_position as u64);
179-
let command = SplitSegmentCommand::new(track_index, segment_index, split_duration);
180-
state
181-
.history_manager
182-
.execute(&mut state.tracks_manager, Box::new(command))
183-
.map_err(|e| e.to_string())
184-
} else {
185-
Err("Track not found".to_string())
186-
}
187-
});
188-
189-
match result {
190-
Ok(_) => {
191-
sync_manager_to_ui(ui_weak.clone());
192-
toast::async_toast_success(ui_weak, "Segment split successfully".to_string());
193-
}
194-
Err(e) => toast::async_toast_warn(ui_weak, e.to_string()),
195-
}
196-
});
197-
}
198-
199137
fn video_editor_track_move_up(ui: &AppWindow, index: i32) {
200138
if index <= 0 {
201139
return;

wayshot/ui/logic.slint

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,6 @@ export global Logic {
304304

305305
callback video-editor-remove-segments();
306306
callback video-editor-split-segment();
307-
308307
callback video-editor-add-selected-segment(index: SelectedSegmentIndex);
309308
callback video-editor-update-segment-duration(index: SelectedSegmentIndex);
310309
callback video-editor-stretch-segment-left(index: SelectedSegmentIndex, diff-duration-ms: int);

0 commit comments

Comments
 (0)