Merge pull request #1695

This commit is contained in:
Brandon Thomas
2026-10-18 09:35:34 -04:00
4 changed files with 60 additions and 11 deletions
+27
View File
@@ -428,6 +428,8 @@ pub struct Prefs {
pub recent_presets: Vec<String>,
/// Character panel: recently used font families, newest first.
pub recent_fonts: Vec<String>,
/// Effects & Presets: the starred effects' ids, in the order starred.
pub effects_favorites: Vec<String>,
/// Preview panel: every shortcut's options.
pub preview: crate::preview::PreviewSettings,
/// View ▸ Simulate Output ▸ My Custom RGB.
@@ -468,6 +470,7 @@ impl Default for Prefs {
recent_footage: vec![],
recent_presets: vec![],
recent_fonts: vec![],
effects_favorites: vec![],
preview: crate::preview::PreviewSettings::default(),
custom_rgb: crate::viewer::CustomRgb::default(),
comp_presets: vec![],
@@ -597,6 +600,9 @@ impl Prefs {
pub fn normalize(&mut self) {
self.version = PREFS_VERSION;
self.comp_presets.retain(CompPreset::is_valid);
let mut seen = std::collections::HashSet::new();
self.effects_favorites.retain(|id| !id.is_empty() && seen.insert(id.clone()));
self.effects_favorites.truncate(MAX_EFFECTS_FAVORITES);
if !is_choice(WINDOW_GRAPHICS, &self.startup.window_graphics) {
self.startup.window_graphics = Startup::default().window_graphics;
}
@@ -715,6 +721,7 @@ impl Prefs {
recent_footage: std::mem::take(&mut self.recent_footage),
recent_presets: std::mem::take(&mut self.recent_presets),
recent_fonts: std::mem::take(&mut self.recent_fonts),
effects_favorites: std::mem::take(&mut self.effects_favorites),
preview: std::mem::take(&mut self.preview),
comp_presets: std::mem::take(&mut self.comp_presets),
..d
@@ -916,6 +923,23 @@ impl Prefs {
push_mru(&mut self.recent_fonts, family, 30);
}
/// Is effect `id` starred in Effects & Presets?
pub fn is_effect_favorite(&self, id: &str) -> bool {
self.effects_favorites.iter().any(|f| f == id)
}
/// Star effect `id` in Effects & Presets, or un-star it; true when it is starred now.
pub fn toggle_effect_favorite(&mut self, id: &str) -> bool {
if self.is_effect_favorite(id) {
self.effects_favorites.retain(|f| f != id);
false
} else {
self.effects_favorites.push(id.to_string());
self.effects_favorites.truncate(MAX_EFFECTS_FAVORITES);
self.is_effect_favorite(id)
}
}
/// The recent fonts the Character panel shows (at most Number of Recent Fonts to Display).
pub fn recent_fonts_shown(&self) -> &[String] {
let n = (self.type_.recent_fonts as usize).min(self.recent_fonts.len());
@@ -933,6 +957,9 @@ impl Prefs {
}
}
/// Most effects Effects & Presets keeps starred (a hand-edited settings file can hold more).
const MAX_EFFECTS_FAVORITES: usize = 1000;
fn push_mru(list: &mut Vec<String>, v: &str, max: usize) {
list.retain(|x| x != v);
list.insert(0, v.to_string());
+28
View File
@@ -212,6 +212,34 @@ fn prefs_commands_get_set_reset_and_persist() {
);
}
/// Effects & Presets' starred effects live in the settings (#1692): they come back in the next
/// session, un-starring sticks too, Reset All keeps them, and a hand-edited list loses its
/// repeats and empty ids on load.
#[test]
fn effects_favorites_persist_across_sessions() {
let store = Arc::new(MemoryConfig::default());
let mut s = Session { config: Some(store.clone()), ..Default::default() };
assert!(s.prefs.toggle_effect_favorite("ADBE Gaussian Blur 2"));
assert!(s.prefs.toggle_effect_favorite("ADBE Glo2"));
s.save_prefs();
let reopen = |store: &Arc<MemoryConfig>| {
let mut s = Session { config: Some(store.clone()), ..Default::default() };
s.load_settings();
s
};
let mut s2 = reopen(&store);
assert_eq!(s2.prefs.effects_favorites, ["ADBE Gaussian Blur 2", "ADBE Glo2"]);
assert!(!s2.prefs.toggle_effect_favorite("ADBE Glo2"), "un-starred");
s2.save_prefs();
let mut s3 = reopen(&store);
assert_eq!(s3.prefs.effects_favorites, ["ADBE Gaussian Blur 2"]);
s3.execute("prefs.reset", json!({})).unwrap();
assert!(s3.prefs.is_effect_favorite("ADBE Gaussian Blur 2"), "Reset All keeps the stars");
let edited = store.read(PREFS_FILE).unwrap().replace("\"effectsFavorites\": [", "\"effectsFavorites\": [\"\", \"ADBE Glo2\", \"ADBE Glo2\", ");
store.write(PREFS_FILE, &edited).unwrap();
assert_eq!(reopen(&store).prefs.effects_favorites, ["ADBE Glo2", "ADBE Gaussian Blur 2"]);
}
/// Composition Settings presets the user saves live in the settings: they persist, a save with
/// an existing name replaces it, they survive Reset All, and invalid ones (from a hand-edited
/// settings file) are dropped on load.
+5 -7
View File
@@ -195,7 +195,7 @@ fn effect_row(
}
app.auto.add(&format!("{auto_prefix}.{}", e.id), r, e.name);
// Favourite star (always shown when starred, else on hover).
let fav = app.ui.effects_favorites.contains(e.id);
let fav = app.session.prefs.is_effect_favorite(e.id);
let sresp = ui.interact(star.intersect(list), egui::Id::new((auto_prefix, e.id, "star")), Sense::click());
if fav || resp.hovered() || sresp.hovered() {
let gold = Color32::from_rgb(0xe8, 0xc0, 0x40);
@@ -203,11 +203,9 @@ fn effect_row(
}
app.auto.add(&format!("{auto_prefix}.{}.star", e.id), star, if fav { "Remove from Favorites" } else { "Add to Favorites" });
if sresp.clicked() {
if fav {
app.ui.effects_favorites.remove(e.id);
} else {
app.ui.effects_favorites.insert(e.id.to_string());
}
// Kept in the settings, so the stars are there next time (#1692).
app.session.prefs.toggle_effect_favorite(e.id);
app.session.save_prefs();
return;
}
if resp.double_clicked() {
@@ -364,7 +362,7 @@ pub fn show(app: &mut EffectcraftApp, ui: &mut egui::Ui, rect: Rect) {
let lookup = |id: &str| reg.iter().find(|e| e.id == id);
// Favorites and Recently Used.
let favs: Vec<_> = app.ui.effects_favorites.iter().filter_map(|id| lookup(id)).filter(|e| keep(e)).collect();
let favs: Vec<_> = app.session.prefs.effects_favorites.iter().filter_map(|id| lookup(id)).filter(|e| keep(e)).collect();
if !favs.is_empty() && folder_row(app, ui, &lp, list, &mut y, "favorites", "Favorites", 0.0, searching, Some(Icon::Star)) {
let mut favs = favs;
favs.sort_by_key(|e| e.name);
-4
View File
@@ -643,9 +643,6 @@ pub struct UiState {
/// Levels (Individual Controls) editor: shown channel per effect uid.
#[serde(default)]
pub fx_levels_channel: BTreeMap<u64, usize>,
/// Effects & Presets: favourite effect ids (starred).
#[serde(default)]
pub effects_favorites: BTreeSet<String>,
/// Effects & Presets: recently applied effect ids, most recent first.
#[serde(default)]
pub effects_recent: Vec<String>,
@@ -734,7 +731,6 @@ impl Default for UiState {
fx_curve_channel: BTreeMap::new(),
fx_curve_pencil: BTreeSet::new(),
fx_levels_channel: BTreeMap::new(),
effects_favorites: BTreeSet::new(),
effects_recent: Vec::new(),
effects_view: EffectsView::default(),
snapping: true,