fix: larger toolbar buttons, text field grows with the text (Issues #35, #34, #28)

- Toolbar: 2 px gaps and 3 px dividers instead of 3 px and 7 px, and the
  size estimate now matches the measured layout exactly. On a 900 px
  screen the buttons are back to 30 px despite the new view-only button.
- Text tool: a new field starts three letters wide and grows with the
  longest line up to the wrap width at the page edge.
- INK_NOTES_DEBUG_FLING now confirms it is active and logs every finger
  lift, including touches ignored because the pen is near.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
haraldandClaude Opus 5.5 committed 2026-10-21 11:44:39 +02:00
1 parent c38bfdd9b1
commit 819bc7d223
3 files changed
+56 -8

No files matched your search

+17 -1
View File
@@ -1426,6 +1426,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut touch_pan_last_pos = (0.0_f32, 0.0_f32);
// Nachgleiten nach schnellem Wischen mit dem Finger (Issue #28)
let mut fling = ink_notes::viewport::Fling::default();
// Diagnosis for Issue #28: log every finger lift and the swipe speed
let debug_fling = std::env::var_os("INK_NOTES_DEBUG_FLING").is_some();
if debug_fling {
eprintln!("[Nachgleiten] Diagnose aktiv – bitte mit dem Finger wischen");
}
// Stylus / Digitizer Zustand (Octotablet / Wayland Tablet Protocol)
let mut is_stylus_drawing = false;
@@ -2843,6 +2848,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Hardware-Palm-Rejection: Wenn der Stylus in Proximity ist oder zeichnet, Touch ignorieren
if is_stylus_drawing || is_stylus_in_proximity {
if debug_fling && touch.phase != TouchPhase::Moved {
eprintln!("[Nachgleiten] Finger ignoriert ({:?}): Stift in der Nähe", touch.phase);
}
return;
}
@@ -3058,6 +3066,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
TouchPhase::Ended | TouchPhase::Cancelled => {
active_touches.remove(&touch.id);
long_press.cancel();
if debug_fling {
eprintln!(
"[Nachgleiten] Finger abgehoben ({:?}), verschiebt: {}, weitere Finger: {}",
touch.phase,
is_touch_panning,
active_touches.len()
);
}
if active_touches.is_empty() {
is_pinch_gesturing = false;
@@ -3069,7 +3085,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
canvas.pan(dx, dy);
fling.track(Vec2::new(dx, dy), Instant::now());
let velocity = fling.release(Instant::now());
if std::env::var_os("INK_NOTES_DEBUG_FLING").is_some() {
if debug_fling {
eprintln!(
"[Nachgleiten] {:.0} px/s beim Abheben, gleitet: {}",
velocity.length(),
+27
View File
@@ -151,6 +151,20 @@ impl TextBox {
glam::Vec2::new(self.wrap_width.max(self.size), self.layout().height())
}
/// Width of the field while it is being edited: as wide as the longest line plus room for
/// the next character, at most the wrap width, so a new field starts short (Issue #34).
pub fn edit_width(&self) -> f32 {
let widest = self
.layout()
.lines
.iter()
.map(|line| line.width)
.fold(0.0, f32::max);
(widest + self.size)
.max(3.0 * self.size)
.min(self.wrap_width.max(self.size))
}
/// Setzt den Text mit Zeilenumbruch an Leerzeichen; zu lange Wörter werden zeichenweise
/// umbrochen, Zeilenumbrüche im Text bleiben erhalten.
pub fn layout(&self) -> TextLayout {
@@ -409,6 +423,19 @@ mod tests {
TextBox::new(content.to_string(), 50.0, TextFont::Sans, wrap_width)
}
#[test]
fn test_edit_width_grows_with_the_text() {
let empty = sample("", 1500.0);
assert!((empty.edit_width() - 150.0).abs() < 1e-3);
let short = sample("Hallo", 1500.0);
let longer = sample("Hallo Welt, wie geht es", 1500.0);
assert!(short.edit_width() < longer.edit_width());
assert!(longer.edit_width() < 1500.0);
// Long text wraps at the page edge and fills the full width
let long = sample(&"Wort ".repeat(100), 1500.0);
assert!((long.edit_width() - 1500.0).abs() < 1e-3);
}
#[test]
fn test_fonts_load() {
for font in [TextFont::Sans, TextFont::Mono] {
+12 -7
View File
@@ -639,13 +639,16 @@ impl UiState {
/// Länge der längsten Farbpalette; so viel Platz hält die Leiste immer frei.
pub const MAX_PALETTE_LEN: usize = 5;
/// Vertical gap between toolbar buttons and the height of a divider line.
pub const SIDEBAR_SPACING: f32 = 2.0;
pub const SIDEBAR_DIVIDER: f32 = 3.0;
/// Durchmesser der Farbtupfer passend zur Knopfgröße.
pub fn sidebar_swatch_size(button_size: f32) -> f32 {
button_size - 10.0
}
/// Größte Knopfgröße (40 px, schrittweise bis 28 px), bei der die Leiste mit allen Elementen
/// Größte Knopfgröße (40 px, schrittweise bis 26 px), bei der die Leiste mit allen Elementen
/// des aktiven Werkzeugs in `max_height` passt. `continuous`: durchgehende Ansicht (ohne
/// Blätterpfeile).
pub fn sidebar_button_size(tool: ActiveTool, max_height: f32, continuous: bool) -> f32 {
@@ -655,11 +658,11 @@ impl UiState {
let page_buttons = if continuous { 2 } else { 4 };
let buttons = 12 + page_buttons + if select { 4 } else { 0 };
let dividers = 5 + usize::from(select);
let spacing = 3.0;
let spacing = Self::SIDEBAR_SPACING;
let needed = |b: f32| {
buttons as f32 * (b + spacing)
+ Self::MAX_PALETTE_LEN as f32 * (Self::sidebar_swatch_size(b) + spacing)
+ dividers as f32 * (7.0 + spacing)
+ dividers as f32 * (Self::SIDEBAR_DIVIDER + spacing)
// frame, margins and the spacing egui adds (measured with the selection tool)
+ 40.0
};
@@ -1092,8 +1095,10 @@ fn sidebar_button(
/// Waagerechte Trennlinie zwischen Gruppen der Werkzeugleiste.
fn sidebar_divider(ui: &mut egui::Ui, button_size: f32) {
let (rect, _) =
ui.allocate_exact_size(egui::vec2(button_size - 12.0, 7.0), egui::Sense::hover());
let (rect, _) = ui.allocate_exact_size(
egui::vec2(button_size - 12.0, UiState::SIDEBAR_DIVIDER),
egui::Sense::hover(),
);
ui.painter().hline(
rect.x_range(),
rect.center().y,
@@ -1502,7 +1507,7 @@ fn text_edit_overlay(ctx: &egui::Context, state: &mut UiState) {
// anpassen, damit die Zeilen an denselben Stellen umbrechen wie auf dem Blatt
let height_px = font_size * ctx.pixels_per_point() * edit.text.font.height_per_em();
let rounding = height_px.round().max(1.0) / height_px;
let width = (edit.text.wrap_width.max(edit.text.size) * sx * view.scale * rounding).max(8.0);
let width = (edit.text.edit_width() * sx * view.scale * rounding).max(8.0);
let color = color32_from(if adapt {
adapt_ink_color(edit.color)
} else {
@@ -3004,7 +3009,7 @@ pub fn render_ui(
// Zentriertes Layout nimmt sonst die volle Fensterbreite ein
ui.set_width(btn);
ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| {
ui.spacing_mut().item_spacing = egui::vec2(0.0, 3.0);
ui.spacing_mut().item_spacing = egui::vec2(0.0, UiState::SIDEBAR_SPACING);
// --- Notizbücher ---
let doc_tooltip = t!(