Symbols: thumbnails work out the document's resource key once per panel frame, not per tile

Review follow-up (CodeRabbit): each thumbnail hashed every symbol's and pattern's art before its
texture cache lookup, so a panel frame cost visible tiles × (symbols + patterns) even when every
thumbnail was cached. The Symbols panel works the key out once per frame, a symbol library panel
once per library it shows, and the dragged chip once; thumbnails take it as given.
This commit is contained in:
Taha-Mahmoodi
2026-10-24 03:09:11 +07:00
committed by bflatastic
parent f6715487c0
commit 5c8e440ab5
2 changed files with 19 additions and 14 deletions
+2 -2
View File
@@ -609,11 +609,11 @@ pub(crate) fn drag_preview(app: &VectorcraftApp, ctx: &egui::Context) {
},
PanelDrag::GraphicStyle(name) => return pointer_chip(ctx, |ui, r| super::graphic_styles::paint_style(app, ui, r, name)),
PanelDrag::Symbol(name) => match app.session.active() {
Some(st) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &st.doc, r, name)),
Some(st) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &st.doc, super::symbols::resources_key(&st.doc), r, name)),
None => return,
},
PanelDrag::LibrarySymbol { library, name } => match vectorcraft_engine::cmd::symbollib::library(&app.session, library) {
Some((_, lib)) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &lib.doc, r, name)),
Some((_, lib)) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &lib.doc, super::symbols::resources_key(&lib.doc), r, name)),
None => return,
},
PanelDrag::Brush { def, .. } => return pointer_chip(ctx, |ui, r| super::brushes::chip(ui, r, def)),
+17 -12
View File
@@ -20,15 +20,15 @@ use crate::theme::Tokens;
use crate::widgets::{self, PanelDrag, menu_item};
/// A thumbnail of symbol `name` (an instance at its natural size), cached by the identity of the
/// art it shows: its own and that of the symbols and patterns it may use.
fn thumb(ui: &Ui, doc: &Document, name: &str, size: f32) -> Option<egui::TextureHandle> {
/// art it shows: its own and `resources`, [`resources_key`] of `doc`.
fn thumb(ui: &Ui, doc: &Document, resources: u64, name: &str, size: f32) -> Option<egui::TextureHandle> {
thread_local! {
static RENDERER: RefCell<vectorcraft_render::Renderer> = RefCell::new(vectorcraft_render::Renderer::new());
static CACHE: crate::graphics::TexCache<HashMap<(usize, u64, String, u32), egui::TextureHandle>> = crate::graphics::TexCache::default();
}
let sym = doc.symbols.iter().find(|s| s.name == name)?;
let px = (size * ui.ctx().pixels_per_point()).round().max(8.0) as u32;
let key = (Arc::as_ptr(&sym.art) as usize, resources_key(doc), name.to_string(), px);
let key = (Arc::as_ptr(&sym.art) as usize, resources, name.to_string(), px);
if let Some(t) = CACHE.with(|c| c.borrow().get(&key).cloned()) {
return Some(t);
}
@@ -45,8 +45,9 @@ fn thumb(ui: &Ui, doc: &Document, name: &str, size: f32) -> Option<egui::Texture
Some(tex)
}
/// The identity of `doc`'s symbol and pattern art, which a symbol's thumbnail may show.
fn resources_key(doc: &Document) -> u64 {
/// The identity of `doc`'s symbol and pattern art, which a symbol's thumbnail may show. It takes a
/// pass over them: work it out once per panel frame, not per thumbnail.
pub(crate) fn resources_key(doc: &Document) -> u64 {
use std::hash::{Hash, Hasher};
let mut h = std::collections::hash_map::DefaultHasher::new();
for s in &doc.symbols {
@@ -73,10 +74,10 @@ fn render_thumb(r: &mut vectorcraft_render::Renderer, doc: &Document, name: &str
}
/// Symbol `name`'s thumbnail on white in `r` (the panel's tiles and the chip a dragged symbol
/// shows at the pointer).
pub(crate) fn chip(ui: &Ui, doc: &Document, r: egui::Rect, name: &str) {
/// shows at the pointer); `resources` is [`resources_key`] of `doc`.
pub(crate) fn chip(ui: &Ui, doc: &Document, resources: u64, r: egui::Rect, name: &str) {
ui.painter().rect_filled(r, 0.0, egui::Color32::WHITE);
if let Some(tex) = thumb(ui, doc, name, r.width()) {
if let Some(tex) = thumb(ui, doc, resources, name, r.width()) {
ui.painter().image(tex.id(), r, egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)), egui::Color32::WHITE);
}
}
@@ -101,6 +102,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
let t = Tokens::get(ui.ctx());
let Some(doc) = app.session.active().map(|d| d.doc.clone()) else { return };
let names: Vec<String> = doc.symbols.iter().map(|s| s.name.clone()).collect();
let resources = resources_key(&doc);
let list: bool = pstate(ui.ctx(), "sym-list");
let sel = current(app);
let mut clicked: Option<(String, bool)> = None;
@@ -121,7 +123,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
} else if resp.hovered() {
ui.painter().rect_filled(r, 0.0, t.hover);
}
chip(ui, &doc, egui::Rect::from_center_size(r.left_center() + vec2(14.0, 0.0), vec2(22.0, 22.0)), n);
chip(ui, &doc, resources, egui::Rect::from_center_size(r.left_center() + vec2(14.0, 0.0), vec2(22.0, 22.0)), n);
ui.painter().text(r.left_center() + vec2(32.0, 0.0), egui::Align2::LEFT_CENTER, n, egui::FontId::proportional(12.5), t.text);
if resp.double_clicked() {
clicked = Some((n.clone(), true));
@@ -134,7 +136,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
for n in &names {
let (r, resp) = ui.allocate_exact_size(vec2(44.0, 44.0), Sense::click_and_drag());
widgets::drag_source(ui, &resp, || PanelDrag::Symbol(n.clone()));
chip(ui, &doc, r.shrink(2.0), n);
chip(ui, &doc, resources, r.shrink(2.0), n);
let on = sel.as_deref() == Some(n.as_str());
ui.painter().rect_stroke(
r,
@@ -245,6 +247,8 @@ fn save_library(app: &mut VectorcraftApp, names: Vec<String>) {
pub(crate) struct LibSymbol {
lib: Arc<SymbolLibrary>,
index: usize,
/// [`resources_key`] of the library's document.
resources: u64,
}
impl LibSymbol {
@@ -274,7 +278,8 @@ impl LibraryKind for SymbolLibraries {
}
fn get(app: &VectorcraftApp, id: &str) -> Option<(String, Self::Lib)> {
let (info, lib) = symbollib::library(&app.session, id)?;
let shown = (0..lib.len()).map(|index| LibSymbol { lib: lib.clone(), index }).collect();
let resources = resources_key(&lib.doc);
let shown = (0..lib.len()).map(|index| LibSymbol { lib: lib.clone(), index, resources }).collect();
Some((info.name, Arc::new(shown)))
}
fn find(app: &VectorcraftApp, key: &str) -> library_panel::Found {
@@ -289,7 +294,7 @@ impl LibraryKind for SymbolLibraries {
}
/// The symbol's art on white, as the Symbols panel shows it.
fn draw(_: &VectorcraftApp, ui: &Ui, r: egui::Rect, s: &LibSymbol, selected: bool, hovered: bool) {
chip(ui, &s.lib.doc, r, s.name());
chip(ui, &s.lib.doc, s.resources, r, s.name());
super::graphic_styles::outline(ui, r, selected, hovered);
}
fn row_icons(_: &Ui, _: egui::Rect, _: &LibSymbol) {}