LRC-LIB-KEYWORDS: control requests wait for a frame's first pass; a hold lasts one pass

A pass drawn again after a discard still has the widgets of the pass
thrown away, so a control request answered there found a row where it no
longer is; it also added a 240 fps sample to perf.fps. Control requests
and the fps sample now run on a frame's first pass only. The Keyword
List's hold is kept for the pass right after it was asked for, so it
never moves a panel that was not drawn in between.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nathaniel Ledford
2026-10-14 12:41:48 -04:00
co-authored by Claude Opus 5.5
parent 648b1b5a93
commit 2b635bb167
2 changed files with 16 additions and 9 deletions
+10 -6
View File
@@ -1021,13 +1021,17 @@ impl LightcraftApp {
if ctx.input(|i| i.viewport().close_requested()) && !panels::notices::may_close(self) {
ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);
}
let now = ctx.input(|i| i.time);
let dt = now - self.last_time;
if dt > 0.0 {
self.perf.fps = self.perf.fps * 0.9 + (1.0 / dt).min(240.0) * 0.1;
// (once a frame: a pass drawn again after a discard has no input of its own, and still the
// widgets of the pass thrown away, where a request would find them out of place)
if ctx.current_pass_index() == 0 {
let now = ctx.input(|i| i.time);
let dt = now - self.last_time;
if dt > 0.0 {
self.perf.fps = self.perf.fps * 0.9 + (1.0 / dt).min(240.0) * 0.1;
}
self.last_time = now;
self.drain_control(ctx);
}
self.last_time = now;
self.drain_control(ctx);
self.apply_settings(ctx);
if !self.synthetic.is_empty() {
ctx.request_repaint();
+6 -3
View File
@@ -15,7 +15,7 @@ pub fn show(app: &mut LightcraftApp, ui: &mut egui::Ui) {
let t = Tokens::get(ui.ctx());
let frame = egui::Frame::NONE.fill(t.chrome).stroke(egui::Stroke::new(1.0, t.divider));
frame.show(ui, |ui| {
// (taken on every pass, so a hold the panel was not drawn for is forgotten)
// (taken on every pass the panel is drawn; one from earlier than the pass before is forgotten)
let held = held_offset(ui.ctx());
let Some(id) = app.session.active() else {
// the Keyword List is the library's, not a photo's: it is there without a selection
@@ -77,7 +77,10 @@ const HOLD: &str = "right-scroll-hold";
/// the Keywords box grew. Set on the scroll area as it starts, so the pass drawn again shows the list
/// in place (a scroll asked for during a pass only lands a frame later).
fn held_offset(ctx: &egui::Context) -> Option<f32> {
let grew = ctx.data_mut(|d| d.remove_temp::<f32>(egui::Id::new(HOLD)))?;
let (grew, asked) = ctx.data_mut(|d| d.remove_temp::<(f32, u64)>(egui::Id::new(HOLD)))?;
if asked.checked_add(1) != Some(ctx.cumulative_pass_nr()) {
return None;
}
let offset = ctx.data(|d| d.get_temp::<f32>(egui::Id::new(OFFSET)))?;
Some((offset + grew).max(0.0)).filter(|o| o.is_finite())
}
@@ -957,7 +960,7 @@ fn hold_list_in_place(ui: &mut egui::Ui, top: f32) {
if on_box || typing {
return;
}
ui.data_mut(|d| d.insert_temp(egui::Id::new(HOLD), grew));
ui.data_mut(|d| d.insert_temp(egui::Id::new(HOLD), (grew, pass)));
// (drawn again at once at the new offset, so the list never shows a frame out of place)
ui.ctx().request_discard("the Keyword List holds its place");
}