Files
Marcos Paulo c40225838c
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
fix(ui,math): mouse wheel scrolls cards again, assistant change preview as full-window side-by-side diff, more LaTeX commands
- card areas now cover their card, so egui sees the pointer over them (wheel scroll in note, diff, sidebar, assistant)
- Preview button on pending changes opens a full-window review; Side by side / Unified toggle
- math: log/ln/det/trig operators, \operatorname, \bmod, \pmod, \iint, \xrightarrow, negated relations

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 23:27:08 -03:00

61 lines
2.9 KiB
Rust

//! The wheel scrolls a long note, including over wide display formulas.
use egui::{Context, RawInput};
use notescraft_engine::Session;
use notescraft_ui_egui::app::NotesApp;
use std::sync::atomic::{AtomicU64, Ordering};
static NEXT: AtomicU64 = AtomicU64::new(0);
const WIDE: &str = r"$$\sum_{k=0}^{n}ar^{k}=a\cdot\frac{1-r^{n+1}}{1-r},\qquad \sum_{k=0}^{\infty}ar^{k}=\frac{a}{1-r},\qquad \sum_{k=1}^{n}k^3=\left(\frac{n(n+1)}{2}\right)^2,\qquad \sum_{k=1}^{n}k^2=\frac{n(n+1)(2n+1)}{6}$$";
fn first_heading_y(app: &mut NotesApp, ctx: &Context, wheel: Option<egui::Pos2>) -> Option<f32> {
let mut found = None;
for frame in 0..4_u32 {
let mut events = vec![egui::Event::PointerMoved(wheel.unwrap_or(egui::pos2(700.0, 450.0)))];
if frame == 2 && wheel.is_some() {
events.push(egui::Event::MouseWheel {
unit: egui::MouseWheelUnit::Point,
delta: egui::vec2(0.0, -200.0),
phase: egui::TouchPhase::Move,
modifiers: egui::Modifiers::NONE,
});
}
let mut out = ctx.run_ui(
RawInput {
screen_rect: Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1440.0, 900.0))),
time: Some(f64::from(u32::try_from(NEXT.fetch_add(1, Ordering::Relaxed)).unwrap_or(0))),
events,
..Default::default()
},
|ui| app.ui(ui.ctx()),
);
out.textures_delta.clear();
found = out.shapes.iter().find_map(|shape| match &shape.shape {
egui::Shape::Text(text) if text.galley.text() == "Top heading" => Some(text.pos.y),
_ => None,
});
}
found
}
#[test]
fn wheel_scrolls_a_note_over_text_and_over_wide_formulas() {
for (name, body) in [("text", "plain paragraph\n\n".repeat(60)), ("math", format!("{WIDE}\n\n").repeat(30))] {
let root = std::env::temp_dir().join(format!("notescraft-scroll-{}-{name}", std::process::id()));
std::fs::create_dir_all(&root).expect("root");
std::fs::write(root.join("long.md"), format!("# Top heading\n\n{body}")).expect("note");
let mut session = Session::open(&root).expect("session");
session.use_settings_dir(root.join("config"));
let mut app = NotesApp::new(session, notescraft_themes::builtin("catppuccin-mocha").expect("theme"));
app.open_note("long.md");
let ctx = Context::default();
let before = first_heading_y(&mut app, &ctx, None);
let mut moved = false;
for (x, y) in [(400.0, 300.0), (600.0, 400.0), (700.0, 520.0), (800.0, 640.0), (900.0, 300.0)] {
let after = first_heading_y(&mut app, &ctx, Some(egui::pos2(x, y)));
moved |= before.zip(after).is_none_or(|(b, a)| (b - a).abs() > 20.0);
}
assert!(before.is_some() && moved, "{name}: wheel did not move the note ({before:?})");
}
}