Skip to content

Commit 768d671

Browse files
committed
[*] refactor
1 parent ba31c89 commit 768d671

File tree

10 files changed

+146
-35
lines changed

10 files changed

+146
-35
lines changed

todo.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
## 问题
2-
- moving filter参数面板暂停时会恢复默认值
32
- subtitle需要重新设计
3+
4+
- font 列表toggle实现逻辑过于复杂
5+
- font 搜索功能实现有问题,列表条目丢失
6+
- 刷新后导入条目丢失
7+
- fly in滤镜应该重构成和transform一样的模式
8+
- chorme-key 路径参数面板无法显示
9+
10+
- moving filter参数面板暂停时会恢复默认值
411
- color picker弹出时需要设置现有的颜色
512

613
## 待验证

wayshot/src/logic/video_editor/font.rs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
use crate::{
22
db::{FONT_TABLE as DB_TABLE, FontEntry},
3-
db_add, db_remove_all, db_select_all, db_update,
3+
db_select_all, db_update,
44
logic::{toast, tr::tr, video_editor::playlist::picker_files},
55
logic_cb,
66
slint_generatedAppWindow::{AppWindow, FontEntry as UIFontEntry},
77
};
8-
use slint::{ComponentHandle, Model, VecModel, Weak};
8+
use once_cell::sync::Lazy;
9+
use slint::{ComponentHandle, Model, SharedString, VecModel, Weak};
910
use std::{collections::HashSet, path::PathBuf};
10-
use video_editor::font::get_font_family_from_file;
11+
use tokio::sync::RwLock;
12+
use video_editor::font::{get_font_family_from_file, get_fonts_info};
1113

12-
db_add!(DB_TABLE, FontEntry);
13-
db_remove_all!(DB_TABLE);
1414
db_update!(DB_TABLE, FontEntry);
1515

16+
static FONT_CACHE: Lazy<RwLock<Vec<FontEntry>>> = Lazy::new(|| RwLock::new(Vec::new()));
17+
1618
#[macro_export]
1719
macro_rules! store_font_entries {
1820
($ui:expr) => {
@@ -30,6 +32,7 @@ pub fn init(ui: &AppWindow) {
3032
logic_cb!(init_font_dialog, ui);
3133
logic_cb!(refresh_font_entries, ui);
3234
logic_cb!(import_font_files, ui);
35+
logic_cb!(search_font_entries, ui, text);
3336
logic_cb!(toggle_font_marked, ui, index);
3437
}
3538

@@ -40,7 +43,7 @@ fn init_font_dialog(ui: &AppWindow) {
4043
if db_fonts.is_empty() {
4144
refresh_font_entries_impl(ui_weak.clone()).await;
4245
} else {
43-
sync_fonts_to_ui(ui_weak, db_fonts);
46+
sync_fonts_to_ui(ui_weak, db_fonts).await;
4447
}
4548
});
4649
}
@@ -66,7 +69,7 @@ async fn refresh_font_entries_impl(ui_weak: Weak<AppWindow>) {
6669
log::warn!("Failed to clear font table: {}", e);
6770
}
6871

69-
let system_fonts = match video_editor::font::get_fonts_info() {
72+
let system_fonts = match get_fonts_info() {
7073
Ok(fonts) => fonts,
7174
Err(e) => {
7275
toast::async_toast_warn(ui_weak.clone(), format!("Failed to get fonts: {}", e));
@@ -94,10 +97,13 @@ async fn refresh_font_entries_impl(ui_weak: Weak<AppWindow>) {
9497
font_entries.push(entry);
9598
}
9699

97-
sync_fonts_to_ui(ui_weak, font_entries);
100+
sync_fonts_to_ui(ui_weak, font_entries).await;
98101
}
99102

100-
fn sync_fonts_to_ui(ui_weak: Weak<AppWindow>, mut fonts: Vec<FontEntry>) {
103+
async fn sync_fonts_to_ui(ui_weak: Weak<AppWindow>, mut fonts: Vec<FontEntry>) {
104+
let fonts_for_cache = fonts.clone();
105+
*FONT_CACHE.write().await = fonts_for_cache;
106+
101107
fonts.sort_by(|a, b| b.marked.cmp(&a.marked));
102108
let ui_fonts: Vec<UIFontEntry> = fonts.into_iter().map(|f| f.into()).collect();
103109

@@ -119,23 +125,37 @@ fn import_font_files(ui: &AppWindow) {
119125
None => return,
120126
};
121127

128+
let mut imported_fonts: Vec<UIFontEntry> = Vec::new();
122129
for file_path in file_paths {
123-
import_font_to_db(ui_weak.clone(), file_path).await;
130+
if let Some(font_entry) = import_font_to_db(ui_weak.clone(), file_path).await {
131+
imported_fonts.push(font_entry.into());
132+
}
124133
}
125134

126-
refresh_font_entries_impl(ui_weak).await;
135+
if !imported_fonts.is_empty() {
136+
let mut cache = FONT_CACHE.write().await;
137+
for font in &imported_fonts {
138+
cache.push(font.clone().into());
139+
}
140+
141+
_ = ui_weak.upgrade_in_event_loop(move |ui| {
142+
let mut fonts: Vec<UIFontEntry> = store_font_entries!(ui).iter().collect();
143+
fonts.splice(0..0, imported_fonts);
144+
store_font_entries!(ui).set_vec(fonts);
145+
});
146+
}
127147
});
128148
}
129149

130-
async fn import_font_to_db(ui_weak: Weak<AppWindow>, file_path: PathBuf) {
150+
async fn import_font_to_db(ui_weak: Weak<AppWindow>, file_path: PathBuf) -> Option<FontEntry> {
131151
let family = match get_font_family_from_file(&file_path) {
132152
Ok(f) => f,
133153
Err(e) => {
134154
toast::async_toast_warn(
135155
ui_weak.clone(),
136156
format!("Failed to read font file {}: {}", file_path.display(), e),
137157
);
138-
return;
158+
return None;
139159
}
140160
};
141161

@@ -154,10 +174,11 @@ async fn import_font_to_db(ui_weak: Weak<AppWindow>, file_path: PathBuf) {
154174
ui_weak.clone(),
155175
format!("Failed to import font {}: {}", entry.family, e),
156176
);
157-
return;
177+
return None;
158178
}
159179

160180
toast::async_toast_success(ui_weak.clone(), format!("Imported font: {}", entry.family));
181+
Some(entry)
161182
}
162183

163184
fn toggle_font_marked(ui: &AppWindow, index: i32) {
@@ -175,3 +196,24 @@ fn toggle_font_marked(ui: &AppWindow, index: i32) {
175196
store_font_entries!(ui).set_vec(fonts);
176197
}
177198
}
199+
200+
fn search_font_entries(ui: &AppWindow, text: SharedString) {
201+
let ui_weak = ui.as_weak();
202+
let text = text.to_string();
203+
204+
tokio::spawn(async move {
205+
let cache = FONT_CACHE.read().await.clone();
206+
207+
let filtered = if text.is_empty() {
208+
cache
209+
} else {
210+
let keyword = text.to_lowercase();
211+
cache
212+
.into_iter()
213+
.filter(|f| f.family.to_lowercase().contains(&keyword))
214+
.collect()
215+
};
216+
217+
sync_fonts_to_ui(ui_weak, filtered).await;
218+
});
219+
}

wayshot/ui/logic.slint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export global Logic {
144144
callback init-font-dialog();
145145
callback refresh-font-entries();
146146
callback import-font-files();
147+
callback search-font-entries(text: string);
147148
callback toggle-font-marked(index: int);
148149

149150
callback init-sources-dialog();

wayshot/ui/panel/desktop/font-dialog.slint

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ import {
1212
IconBtn,
1313
MovingDialog,
1414
NoDataImg,
15+
CenterLayout,
16+
LineInput,
1517
} from "../../base/widgets.slint";
16-
import { CenterLayout } from "../../base/center-layout.slint";
1718

1819
component HeadBar inherits HorizontalLayout {
1920
alignment: end;
2021

22+
private property <bool> show-search-bar;
23+
2124
Rectangle {
2225
width: hbox.preferred-width;
2326
border-radius: self.height / 2;
@@ -31,9 +34,46 @@ component HeadBar inherits HorizontalLayout {
3134
padding-left: Theme.padding * 4;
3235
padding-right: Theme.padding * 4;
3336

37+
if show-search-bar: LineInput {
38+
width: Theme.default-font-size * 16;
39+
vpadding: Theme.padding / 2;
40+
41+
edited => {
42+
Logic.search-font-entries(self.text);
43+
}
44+
45+
key-pressed(event) => {
46+
if (event.text == Key.Escape) {
47+
Logic.search-font-entries("");
48+
show-search-bar = false;
49+
}
50+
}
51+
52+
Timer {
53+
interval: 200ms;
54+
running: true;
55+
56+
triggered() => {
57+
parent.focus();
58+
self.running = false;
59+
}
60+
}
61+
}
62+
3463
HorizontalLayout {
3564
spacing: Theme.spacing * 4;
3665

66+
IconBtn {
67+
is-show-tip: true;
68+
tip: Logic.tr("search");
69+
icon: Icons.search-light;
70+
hover-color: Store.setting-preference.is-dark ? Theme.secondary-background.darker(50%) : Theme.secondary-background.darker(5%);
71+
72+
clicked => {
73+
show-search-bar = !show-search-bar;
74+
}
75+
}
76+
3777
IconBtn {
3878
is-show-tip: true;
3979
tip: Logic.tr("refresh");
@@ -63,16 +103,18 @@ component HeadBar inherits HorizontalLayout {
63103

64104
component FontItem inherits Rectangle {
65105
in property <int> index;
66-
in property <FontEntry> font-info;
106+
in property <FontEntry> entry;
107+
in-out property <length> family-width;
108+
out property <length> family-preferred-width <=> family-lb.preferred-width;
67109

68110
background: ta.has-hover ? Theme.checked-background : (Math.mod(index, 2) == 0 ? Theme.table-item-first : Theme.table-item-second);
69111

70112
ta := TouchArea {
71113
mouse-cursor: MouseCursor.pointer;
72114

73115
clicked => {
74-
Store.selected-font-entry = font-info;
75-
VEFilter.selected-font-path = font-info.path;
116+
Store.selected-font-entry = entry;
117+
VEFilter.selected-font-path = entry.path;
76118
Store.is-show-font-dialog = false;
77119
}
78120
}
@@ -82,38 +124,41 @@ component FontItem inherits Rectangle {
82124
padding: Theme.padding * 2;
83125
spacing: Theme.spacing * 4;
84126

127+
Label {
128+
text: index + 1;
129+
color: Theme.secondary-text-color;
130+
}
131+
85132
IconBtn {
86133
icon: Icons.star-round-fill;
87134
icon-size: Theme.icon-size;
88-
colorize: font-info.marked ? Theme.warning-color : Theme.icon-color;
135+
colorize: entry.marked ? Theme.warning-color : Theme.icon-color;
89136
hover-color: mod(index, 2) == 0 ? Theme.table-item-second : Theme.table-item-first;
90137

91138
clicked => {
92139
Logic.toggle-font-marked(index);
93140
}
94141
}
95142

96-
Label {
97-
text: font-info.family;
143+
family-lb := Label {
144+
text: entry.family;
98145
font-weight: Theme.bold-font-weight;
99-
horizontal-alignment: left;
100-
overflow: elide;
146+
width: root.family-width;
101147
}
102148

103149
Label {
104-
text: font-info.path;
150+
text: entry.path;
105151
font-size: Theme.default-font-size * 0.8;
106152
color: Theme.secondary-text-color;
107153
horizontal-alignment: left;
108-
overflow: elide;
109154
}
110155
}
111156
}
112157

113158
export component FontDialog inherits MovingDialog {
114159
title: Logic.tr("Font");
115160
icon: Icons.font-light;
116-
header-width: Theme.default-font-size * 48;
161+
header-width: Theme.default-font-size * 56;
117162

118163
init => {
119164
Logic.init-font-dialog();
@@ -146,14 +191,23 @@ export component FontDialog inherits MovingDialog {
146191
x: parent.border-width;
147192
y: parent.border-width;
148193
width: parent.width - parent.border-width * 2;
194+
viewport-width: vbox.preferred-width;
195+
viewport-height: vbox.preferred-height;
149196

150-
if Store.font-entries.length > 0: VerticalLayout {
197+
vbox := VerticalLayout {
151198
alignment: start;
152199

153-
for font-info[index] in Store.font-entries: FontItem {
200+
private property <length> font-item-max-family-width;
201+
202+
for entry[index] in Store.font-entries: FontItem {
154203
index: index;
155-
font-info: font-info;
204+
entry: entry;
156205
height: font-item-height;
206+
family-width: parent.font-item-max-family-width;
207+
208+
init => {
209+
parent.font-item-max-family-width = max(parent.font-item-max-family-width, self.family-preferred-width);
210+
}
157211
}
158212
}
159213
}

wayshot/ui/panel/desktop/video-editor/preview/preview-locate-layer.slint

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ export component PreviewLocateLayer inherits Rectangle {
3434
}
3535

3636
init => {
37+
debug("xxxxxxxxxxxxxxxxxxxxxx", VEFilter.selected-filter.detail);
38+
3739
if (VEFilter.selected-filter.name == "fly in") {
40+
debug("yyyyyyyyyyyyyyyyyyyyyyy", VEFilter.selected-filter.detail);
41+
3842
fly-in-config = VEFilter.from-fly-in-json(VEFilter.selected-filter.detail);
3943
root.move-to-x = fly-in-config.move-to-x;
4044
root.move-to-y = fly-in-config.move-to-y;
@@ -102,4 +106,5 @@ export component PreviewLocateLayer inherits Rectangle {
102106
root.move-to-y = (end-handle.y + self.height / 2) / root.height;
103107
}
104108
}
105-
}
109+
}
110+

wayshot/ui/panel/desktop/video-editor/right-panel/filter/image.slint

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export component FilterImageDetail inherits Rectangle {
3636
}
3737
}
3838

39-
if selected-filter.name.to-lowercase() == "chroma-key": ChromaKey {
39+
if selected-filter.name.to-lowercase() == "chroma key": ChromaKey {
4040
index: index;
4141
width: parent.width;
4242
selected-filter: selected-filter;

wayshot/ui/panel/desktop/video-editor/right-panel/filter/video.slint

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export component FilterVideoDetail inherits Rectangle {
3636
}
3737
}
3838

39-
if selected-filter.name.to-lowercase() == "chroma-key": ChromaKey {
39+
if selected-filter.name.to-lowercase() == "chroma key": ChromaKey {
4040
index: index;
4141
width: parent.width;
4242
selected-filter: selected-filter;

wayshot/ui/panel/desktop/video-editor/right-panel/filter/video/chroma-key.slint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ export component ChromaKey inherits Rectangle {
132132
border-width: 1px;
133133

134134
clicked => {
135+
Store.video-editor-color-picker-color = Util.color-picker-hex-color(self.text);
135136
Store.video-editor-color-picker-toggle-flag = !Store.video-editor-color-picker-toggle-flag;
136137
}
137138
}

wayshot/ui/panel/desktop/video-editor/video-editor.slint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ export component VideoEditor inherits Rectangle {
334334
color-picker := ColorPickerPopup {
335335
x: (root.width - self.width) / 2;
336336
y: (root.height - self.height) / 4;
337+
selected-color <=> Store.video-editor-color-picker-color;
337338

338339
confirmed(color) => {
339340
Store.video-editor-color-picker-color = Util.color-picker-hex-color(color);

0 commit comments

Comments
 (0)