Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab0f49199b | ||
|
|
38b860bc32 | ||
|
|
055e39c24e | ||
|
|
1b22ffa526 | ||
|
|
0d9e9aa2ea | ||
|
|
298932cb32 | ||
|
|
127bc8d730 |
No files matched your search
Generated
+1
-1
@@ -1540,7 +1540,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ink-notes"
|
name = "ink-notes"
|
||||||
version = "0.42.0"
|
version = "0.43.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ab_glyph",
|
"ab_glyph",
|
||||||
"android_logger",
|
"android_logger",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ink-notes"
|
name = "ink-notes"
|
||||||
version = "0.42.0"
|
version = "0.43.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Notizbuch-App für Stift, Touch und Maus unter Linux"
|
description = "Notizbuch-App für Stift, Touch und Maus unter Linux"
|
||||||
repository = "https://gitea.pansi.eu/harald/ink-notes"
|
repository = "https://gitea.pansi.eu/harald/ink-notes"
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ Die Oberfläche gibt es auf Deutsch und Englisch; ink-notes folgt der Systemspra
|
|||||||
- **Glättung in zwei Stufen:** Während des Schreibens glättet ein 1€-Filter das Zittern, die Linie erscheint sofort. Beim Absetzen wird der Strich nachbearbeitet: Ecken (Knicke über 65°) bleiben erhalten und werden rund verbunden, der Druckverlauf wird geglättet, überflüssige Punkte entfallen, die Enden werden rund.
|
- **Glättung in zwei Stufen:** Während des Schreibens glättet ein 1€-Filter das Zittern, die Linie erscheint sofort. Beim Absetzen wird der Strich nachbearbeitet: Ecken (Knicke über 65°) bleiben erhalten und werden rund verbunden, der Druckverlauf wird geglättet, überflüssige Punkte entfallen, die Enden werden rund.
|
||||||
- **Druckkurve** im ☰-Menü an den eigenen Stift anpassen (weicher/härter, Schwelle gegen Grundrauschen).
|
- **Druckkurve** im ☰-Menü an den eigenen Stift anpassen (weicher/härter, Schwelle gegen Grundrauschen).
|
||||||
- **Tasten am Stift** im ☰-Menü belegen: Radieren (Standard), Auswählen, Textmarker, Stift oder nichts – gilt, solange die Taste gedrückt ist. Jede Taste erscheint dort nach dem ersten Drücken.
|
- **Tasten am Stift** im ☰-Menü belegen: Radieren (Standard), Auswählen, Textmarker, Stift oder nichts – gilt, solange die Taste gedrückt ist. Jede Taste erscheint dort nach dem ersten Drücken.
|
||||||
- **Radierer** in drei Modi: ganze Striche, nur den überstrichenen Teil (Teilstrich) oder nur Textmarker; die Größe stellt man in einem Menü wie bei den Stiften ein (wird gemerkt). Die Stiftrückseite radiert ebenfalls.
|
- **Radierer** in drei Modi: ganze Striche, nur den überstrichenen Teil (Teilstrich) oder nur Textmarker; berührte Textfelder verschwinden ganz, Bilder bleiben; die Größe stellt man in einem Menü wie bei den Stiften ein (wird gemerkt). Die Stiftrückseite radiert ebenfalls.
|
||||||
- **Virtuelles Lineal** (`L`): verschieben, am Griff drehen (rastet bei 15° ein); Striche entlang einer Kante werden gerade.
|
- **Virtuelles Lineal** (`L`): verschieben, am Griff drehen (rastet bei 15° ein); Striche entlang einer Kante werden gerade.
|
||||||
- **Nur ansehen** (👁 in der Werkzeugleiste): Stift, Finger und Maus scrollen und zoomen nur; die Werkzeuge verschwinden, nichts lässt sich versehentlich ändern. Erneut 👁 tippen, um zu schreiben.
|
- **Nur ansehen** (👁 in der Werkzeugleiste): Stift, Finger und Maus scrollen und zoomen nur; die Werkzeuge verschwinden, nichts lässt sich versehentlich ändern. Erneut 👁 tippen, um zu schreiben.
|
||||||
- **Platz schaffen** (↕ in der Werkzeugleiste): aufs Blatt tippen und nach unten ziehen – alles darunter rutscht mit, auch auf den folgenden Seiten. Was über ein Seitenende rutschen würde, beginnt auf der nächsten Seite; fehlende Seiten werden angehängt. Nach oben ziehen schließt leeren Platz. Ein Schritt für Rückgängig.
|
- **Platz schaffen** (↕ in der Werkzeugleiste): aufs Blatt tippen und nach unten ziehen – alles darunter rutscht mit, auch auf den folgenden Seiten. Was über ein Seitenende rutschen würde, beginnt auf der nächsten Seite; fehlende Seiten werden angehängt. Nach oben ziehen schließt leeren Platz. Ein Schritt für Rückgängig.
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ The interface is available in English and German; ink-notes follows the system l
|
|||||||
- **Two-stage smoothing:** While you write, a 1€ filter removes jitter and the line appears immediately. When you lift the pen, the stroke is refined: corners (bends over 65°) are kept and drawn round, the pressure curve is smoothed, redundant points are dropped and the ends become round.
|
- **Two-stage smoothing:** While you write, a 1€ filter removes jitter and the line appears immediately. When you lift the pen, the stroke is refined: corners (bends over 65°) are kept and drawn round, the pressure curve is smoothed, redundant points are dropped and the ends become round.
|
||||||
- **Pressure curve** adjustable to your pen in the ☰ menu (softer/harder, threshold against base noise).
|
- **Pressure curve** adjustable to your pen in the ☰ menu (softer/harder, threshold against base noise).
|
||||||
- **Pen buttons** can be assigned in the ☰ menu: erase (default), select, highlighter, pen or nothing – active while the button is held. Each button appears there after it is pressed for the first time.
|
- **Pen buttons** can be assigned in the ☰ menu: erase (default), select, highlighter, pen or nothing – active while the button is held. Each button appears there after it is pressed for the first time.
|
||||||
- **Eraser** with three modes: whole strokes, only the part you wipe over (partial stroke), or highlighter only; its size is set in a menu like the pens (remembered). The back end of the pen erases too.
|
- **Eraser** with three modes: whole strokes, only the part you wipe over (partial stroke), or highlighter only; text boxes it touches go as a whole, images stay; its size is set in a menu like the pens (remembered). The back end of the pen erases too.
|
||||||
- **Virtual ruler** (`L`): move it, rotate it by its handle (snaps to 15°); strokes along an edge become straight.
|
- **Virtual ruler** (`L`): move it, rotate it by its handle (snaps to 15°); strokes along an edge become straight.
|
||||||
- **View only** (👁 in the toolbar): pen, finger and mouse only scroll and zoom; the tools disappear and nothing can be changed by accident. Tap 👁 again to write.
|
- **View only** (👁 in the toolbar): pen, finger and mouse only scroll and zoom; the tools disappear and nothing can be changed by accident. Tap 👁 again to write.
|
||||||
- **Make space** (↕ in the toolbar): tap the page and drag down – everything below moves along, also on the following pages. Whatever would slide past the end of a page continues on the next one; missing pages are appended. Dragging up closes empty space. Undo reverts it in one step.
|
- **Make space** (↕ in the toolbar): tap the page and drag down – everything below moves along, also on the following pages. Whatever would slide past the end of a page continues on the next one; missing pages are appended. Dragging up closes empty space. Undo reverts it in one step.
|
||||||
|
|||||||
@@ -84,6 +84,21 @@
|
|||||||
</branding>
|
</branding>
|
||||||
<content_rating type="oars-1.1" />
|
<content_rating type="oars-1.1" />
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="0.43.0" date="2026-11-09">
|
||||||
|
<description>
|
||||||
|
<p>The pen draws without delay again on Wayland, and the eraser removes text boxes such as an inserted math result.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="0.42.2" date="2026-11-05">
|
||||||
|
<description>
|
||||||
|
<p>"Draw with finger" is remembered now and on by default on Android, so phones without a pen can write again after a restart or an update.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="0.42.1" date="2026-11-02">
|
||||||
|
<description>
|
||||||
|
<p>Swiping with a finger glides on again on Wayland: lifting the finger no longer arrives late and stops the page right away.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="0.42.0" date="2026-10-28">
|
<release version="0.42.0" date="2026-10-28">
|
||||||
<description>
|
<description>
|
||||||
<p>Built-in Nextcloud sync: sign in through the browser and the notebooks are synced with your Nextcloud, also private servers and without a sync client.</p>
|
<p>Built-in Nextcloud sync: sign in through the browser and the notebooks are synced with your Nextcloud, also private servers and without a sync client.</p>
|
||||||
|
|||||||
@@ -84,6 +84,21 @@
|
|||||||
</branding>
|
</branding>
|
||||||
<content_rating type="oars-1.1" />
|
<content_rating type="oars-1.1" />
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="0.43.0" date="2026-11-09">
|
||||||
|
<description>
|
||||||
|
<p>The pen draws without delay again on Wayland, and the eraser removes text boxes such as an inserted math result.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="0.42.2" date="2026-11-05">
|
||||||
|
<description>
|
||||||
|
<p>"Draw with finger" is remembered now and on by default on Android, so phones without a pen can write again after a restart or an update.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release version="0.42.1" date="2026-11-02">
|
||||||
|
<description>
|
||||||
|
<p>Swiping with a finger glides on again on Wayland: lifting the finger no longer arrives late and stops the page right away.</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="0.42.0" date="2026-10-28">
|
<release version="0.42.0" date="2026-10-28">
|
||||||
<description>
|
<description>
|
||||||
<p>Built-in Nextcloud sync: sign in through the browser and the notebooks are synced with your Nextcloud, also private servers and without a sync client.</p>
|
<p>Built-in Nextcloud sync: sign in through the browser and the notebooks are synced with your Nextcloud, also private servers and without a sync client.</p>
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
Notebook app for pen, touch and mouse on Linux (tested on Zorin OS 18 / Ubuntu 24.04).
|
Notebook app for pen, touch and mouse on Linux (tested on Zorin OS 18 / Ubuntu 24.04).
|
||||||
|
|
||||||
### Highlights:
|
### Highlights:
|
||||||
|
- **Pen without lag on Wayland**: Pen events reached the app only when something else woke it, so strokes trailed behind the pen or appeared only later. Every event from the compositor now wakes the app; it still uses no CPU while idle (Issue #53)
|
||||||
|
- **Eraser removes text**: The whole-stroke and partial erasers now remove a text box – typed text or an inserted math result – as soon as they touch it. The highlighter eraser leaves text alone, images are never erased (Issue #54)
|
||||||
|
- **Writing with the finger on Android**: "Draw with finger" (☰ → Input) is now remembered and starts switched on on Android, where phones usually have no pen. Before, it was off after every start, so after an update one finger only moved the page (Issue #50)
|
||||||
|
- **Momentum scrolling with the finger fixed**: On Wayland, lifting the finger after a swipe could reach the app only together with the next touch, so the page stopped dead instead of gliding on. The app now keeps listening while a finger is on the screen, so the page glides after a quick swipe and slows down gradually (Issue #28)
|
||||||
- **Nextcloud built in**: ☰ → Storage location → Nextcloud syncs the notebooks directly with your Nextcloud – also on Android and without a sync client. Enter the server address (private servers in a subfolder, with their own port or a self-signed certificate work too), sign in in the browser; the app gets an app password of its own that "Disconnect" revokes again. Syncing runs every 30 seconds and shortly after saving and keeps working offline; a page changed on two devices is kept twice, deleted notebooks and pages go into the trash on both sides, changes arriving for the open notebook wait until it is saved (Issue #49)
|
- **Nextcloud built in**: ☰ → Storage location → Nextcloud syncs the notebooks directly with your Nextcloud – also on Android and without a sync client. Enter the server address (private servers in a subfolder, with their own port or a self-signed certificate work too), sign in in the browser; the app gets an app password of its own that "Disconnect" revokes again. Syncing runs every 30 seconds and shortly after saving and keeps working offline; a page changed on two devices is kept twice, deleted notebooks and pages go into the trash on both sides, changes arriving for the open notebook wait until it is saved (Issue #49)
|
||||||
- **Security update**: rustls 0.23.46 (TLS library for update checks and the Nextcloud sync) fixes a way for key material to end up in logs (Issue #51); ink-notes itself was not affected, as it doesn't keep TLS sessions
|
- **Security update**: rustls 0.23.46 (TLS library for update checks and the Nextcloud sync) fixes a way for key material to end up in logs (Issue #51); ink-notes itself was not affected, as it doesn't keep TLS sessions
|
||||||
- **Android toolbar fix**: The toolbar and menus stay clear of the status bar, the navigation bar and the camera cutout, so the topmost button (📚 notebooks) can be tapped again; in landscape the page is centered between the side bars. Nothing changes on Linux and Windows (Issue #50)
|
- **Android toolbar fix**: The toolbar and menus stay clear of the status bar, the navigation bar and the camera cutout, so the topmost button (📚 notebooks) can be tapped again; in landscape the page is centered between the side bars. Nothing changes on Linux and Windows (Issue #50)
|
||||||
|
|||||||
+17
@@ -1471,6 +1471,7 @@ pub fn run_with(
|
|||||||
ui_state.stylus_buttons = ui_settings.stylus_buttons.clone();
|
ui_state.stylus_buttons = ui_settings.stylus_buttons.clone();
|
||||||
ui_state.set_eraser_radius_mm(ui_settings.eraser_radius_mm);
|
ui_state.set_eraser_radius_mm(ui_settings.eraser_radius_mm);
|
||||||
ui_state.math.set_enabled(ui_settings.math_assist);
|
ui_state.math.set_enabled(ui_settings.math_assist);
|
||||||
|
ui_state.touch_draw_enabled = ui_settings.touch_draw;
|
||||||
ui_state.select_pen(ui_settings.active_pen);
|
ui_state.select_pen(ui_settings.active_pen);
|
||||||
ui_state.highlighter_colors = ui_settings.highlighter_colors;
|
ui_state.highlighter_colors = ui_settings.highlighter_colors;
|
||||||
ui_state.select_highlighter_color(ui_settings.active_highlighter);
|
ui_state.select_highlighter_color(ui_settings.active_highlighter);
|
||||||
@@ -2471,6 +2472,11 @@ pub fn run_with(
|
|||||||
|| is_stylus_drawing
|
|| is_stylus_drawing
|
||||||
|| is_stylus_in_proximity
|
|| is_stylus_in_proximity
|
||||||
|| fling.is_active()
|
|| fling.is_active()
|
||||||
|
// While a finger is down: on Wayland, the lift can already sit in winit's
|
||||||
|
// queue (read from the socket by the graphics driver) without waking the
|
||||||
|
// loop, and then only arrives with the next touch, which stops the glide
|
||||||
|
// right away (Issue #28)
|
||||||
|
|| !active_touches.is_empty()
|
||||||
{
|
{
|
||||||
target.set_control_flow(ControlFlow::wait_duration(Duration::from_millis(8)));
|
target.set_control_flow(ControlFlow::wait_duration(Duration::from_millis(8)));
|
||||||
} else if let Some(at) = [
|
} else if let Some(at) = [
|
||||||
@@ -3710,6 +3716,9 @@ pub fn run_with(
|
|||||||
match touch.phase {
|
match touch.phase {
|
||||||
TouchPhase::Started => {
|
TouchPhase::Started => {
|
||||||
// Jede neue Berührung hält ein gleitendes Blatt an
|
// Jede neue Berührung hält ein gleitendes Blatt an
|
||||||
|
if debug_fling && fling.is_active() {
|
||||||
|
eprintln!("[Nachgleiten] Neuer Finger hält das Gleiten an");
|
||||||
|
}
|
||||||
fling.stop();
|
fling.stop();
|
||||||
// Event-Isolation für Touch-Eingaben
|
// Event-Isolation für Touch-Eingaben
|
||||||
let is_touch_in_ui = ui::is_screen_point_in_ui(
|
let is_touch_in_ui = ui::is_screen_point_in_ui(
|
||||||
@@ -5348,6 +5357,14 @@ pub fn run_with(
|
|||||||
&mut ui_state,
|
&mut ui_state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
UiAction::SetTouchDraw(on) => {
|
||||||
|
ui_settings.touch_draw = on;
|
||||||
|
save_ui_settings(
|
||||||
|
&ui_settings,
|
||||||
|
ui_settings_path.as_deref(),
|
||||||
|
&mut ui_state,
|
||||||
|
);
|
||||||
|
}
|
||||||
UiAction::SetSidebarSide(side) => {
|
UiAction::SetSidebarSide(side) => {
|
||||||
ui_settings.sidebar_side = side;
|
ui_settings.sidebar_side = side;
|
||||||
save_ui_settings(
|
save_ui_settings(
|
||||||
|
|||||||
+76
-6
@@ -275,7 +275,7 @@ pub enum EraserMode {
|
|||||||
/// Nur Textmarker – die Handschrift darunter bleibt erhalten
|
/// Nur Textmarker – die Handschrift darunter bleibt erhalten
|
||||||
HighlighterOnly,
|
HighlighterOnly,
|
||||||
/// Nur den überstrichenen Teil eines Strichs entfernen; der Rest bleibt in Stücken
|
/// Nur den überstrichenen Teil eines Strichs entfernen; der Rest bleibt in Stücken
|
||||||
/// erhalten. Formen werden als Ganzes radiert.
|
/// erhalten. Formen und Textfelder werden als Ganzes radiert.
|
||||||
Partial,
|
Partial,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,6 +578,12 @@ impl Stroke {
|
|||||||
min_dist
|
min_dist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A text box goes as a whole once the eraser touches it, like a typed or inserted math
|
||||||
|
/// result (Issue #54). Images are never erased.
|
||||||
|
fn erased_as_text(&self, eraser_pos: glam::Vec2, eraser_radius: f32) -> bool {
|
||||||
|
self.is_text() && self.distance_to_point(eraser_pos) <= eraser_radius
|
||||||
|
}
|
||||||
|
|
||||||
/// Prüft, ob dieser Strich von einem Radierer an Position `eraser_pos` mit Radius `eraser_radius` getroffen wird.
|
/// Prüft, ob dieser Strich von einem Radierer an Position `eraser_pos` mit Radius `eraser_radius` getroffen wird.
|
||||||
pub fn intersects_eraser(
|
pub fn intersects_eraser(
|
||||||
&self,
|
&self,
|
||||||
@@ -942,10 +948,15 @@ impl Page {
|
|||||||
let mut hit_indices = Vec::new();
|
let mut hit_indices = Vec::new();
|
||||||
|
|
||||||
for (i, stroke) in self.strokes.iter().enumerate() {
|
for (i, stroke) in self.strokes.iter().enumerate() {
|
||||||
if !stroke.is_object()
|
let hit = if stroke.is_text() {
|
||||||
&& mode.erases(stroke.tool)
|
mode != EraserMode::HighlighterOnly
|
||||||
&& stroke.intersects_eraser(eraser_pos, eraser_radius, max_stroke_radius)
|
&& stroke.erased_as_text(eraser_pos, eraser_radius)
|
||||||
{
|
} else {
|
||||||
|
!stroke.is_object()
|
||||||
|
&& mode.erases(stroke.tool)
|
||||||
|
&& stroke.intersects_eraser(eraser_pos, eraser_radius, max_stroke_radius)
|
||||||
|
};
|
||||||
|
if hit {
|
||||||
hit_indices.push(i);
|
hit_indices.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -970,7 +981,7 @@ impl Page {
|
|||||||
|
|
||||||
/// Teilradierer: entfernt den Teil aller Striche im Kreis um `eraser_pos`. Getroffene
|
/// Teilradierer: entfernt den Teil aller Striche im Kreis um `eraser_pos`. Getroffene
|
||||||
/// Striche werden durch ihre übrig gebliebenen Stücke ersetzt (neue IDs aus `next_id`),
|
/// Striche werden durch ihre übrig gebliebenen Stücke ersetzt (neue IDs aus `next_id`),
|
||||||
/// Formen als Ganzes entfernt, Bilder und Textfelder nie. Aufeinanderfolgende Schnitte
|
/// Formen und Textfelder als Ganzes entfernt, Bilder nie. Aufeinanderfolgende Schnitte
|
||||||
/// eines Radierzugs bilden einen gemeinsamen Undo-Schritt. Gibt `true` zurück, wenn sich etwas geändert hat.
|
/// eines Radierzugs bilden einen gemeinsamen Undo-Schritt. Gibt `true` zurück, wenn sich etwas geändert hat.
|
||||||
pub fn erase_partial_at(
|
pub fn erase_partial_at(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -982,6 +993,14 @@ impl Page {
|
|||||||
let mut added = Vec::new();
|
let mut added = Vec::new();
|
||||||
let mut result = Vec::with_capacity(self.strokes.len());
|
let mut result = Vec::with_capacity(self.strokes.len());
|
||||||
for stroke in std::mem::take(&mut self.strokes) {
|
for stroke in std::mem::take(&mut self.strokes) {
|
||||||
|
if stroke.is_text() {
|
||||||
|
if stroke.erased_as_text(eraser_pos, eraser_radius) {
|
||||||
|
removed.push(stroke);
|
||||||
|
} else {
|
||||||
|
result.push(stroke);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let reach = eraser_radius + stroke.width / 2.0;
|
let reach = eraser_radius + stroke.width / 2.0;
|
||||||
if stroke.is_object() || !stroke.aabb.expanded(reach).contains_point(eraser_pos) {
|
if stroke.is_object() || !stroke.aabb.expanded(reach).contains_point(eraser_pos) {
|
||||||
result.push(stroke);
|
result.push(stroke);
|
||||||
@@ -2177,6 +2196,57 @@ mod tests {
|
|||||||
assert!(page.strokes.is_empty());
|
assert!(page.strokes.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eraser_removes_text_boxes_but_not_images() {
|
||||||
|
let corners = |x: f32| {
|
||||||
|
[
|
||||||
|
glam::Vec2::new(x, 100.0),
|
||||||
|
glam::Vec2::new(x + 100.0, 100.0),
|
||||||
|
glam::Vec2::new(x + 100.0, 150.0),
|
||||||
|
glam::Vec2::new(x, 150.0),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
let text = || {
|
||||||
|
Stroke::new_text(
|
||||||
|
1,
|
||||||
|
crate::text::TextBox::new("10".into(), 40.0, crate::text::TextFont::Sans, 100.0),
|
||||||
|
corners(100.0),
|
||||||
|
[0.0, 0.0, 0.0, 1.0],
|
||||||
|
)
|
||||||
|
};
|
||||||
|
for mode in [EraserMode::All, EraserMode::Partial] {
|
||||||
|
let mut page = Page::new(1, PageBackground::Grid5mm);
|
||||||
|
page.add_stroke(text());
|
||||||
|
page.add_stroke(Stroke::new_image(2, "a".into(), corners(300.0)));
|
||||||
|
let mut next_id = 10;
|
||||||
|
let mut erase = |page: &mut Page, at: glam::Vec2| match mode {
|
||||||
|
EraserMode::Partial => page.erase_partial_at(at, 10.0, &mut next_id),
|
||||||
|
_ => !page.erase_at(at, 10.0, 2.0, mode).is_empty(),
|
||||||
|
};
|
||||||
|
// Next to the box: nothing; touching its edge or inside: the whole box goes
|
||||||
|
assert!(!erase(&mut page, glam::Vec2::new(85.0, 120.0)));
|
||||||
|
assert!(!erase(&mut page, glam::Vec2::new(350.0, 120.0)));
|
||||||
|
assert!(erase(&mut page, glam::Vec2::new(95.0, 120.0)));
|
||||||
|
assert_eq!(
|
||||||
|
page.strokes.iter().map(|s| s.id).collect::<Vec<_>>(),
|
||||||
|
vec![2]
|
||||||
|
);
|
||||||
|
assert!(page.undo());
|
||||||
|
assert_eq!(page.strokes.len(), 2);
|
||||||
|
}
|
||||||
|
// The highlighter eraser leaves text alone
|
||||||
|
let mut page = Page::new(1, PageBackground::Grid5mm);
|
||||||
|
page.add_stroke(text());
|
||||||
|
assert!(page
|
||||||
|
.erase_at(
|
||||||
|
glam::Vec2::new(150.0, 120.0),
|
||||||
|
10.0,
|
||||||
|
2.0,
|
||||||
|
EraserMode::HighlighterOnly
|
||||||
|
)
|
||||||
|
.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pdf_page_size_follows_orientation() {
|
fn test_pdf_page_size_follows_orientation() {
|
||||||
// Hochformat (A4, Letter) bleibt A4 hoch
|
// Hochformat (A4, Letter) bleibt A4 hoch
|
||||||
|
|||||||
@@ -234,6 +234,9 @@ pub struct UiSettings {
|
|||||||
pub storage_dir: Option<PathBuf>,
|
pub storage_dir: Option<PathBuf>,
|
||||||
/// Compute handwritten math after `=` (Issue #46)
|
/// Compute handwritten math after `=` (Issue #46)
|
||||||
pub math_assist: bool,
|
pub math_assist: bool,
|
||||||
|
/// One finger draws instead of moving the page. On by default on Android, where phones
|
||||||
|
/// usually have no pen (Issue #50)
|
||||||
|
pub touch_draw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UiSettings {
|
impl Default for UiSettings {
|
||||||
@@ -256,6 +259,7 @@ impl Default for UiSettings {
|
|||||||
eraser_radius_mm: 3.0,
|
eraser_radius_mm: 3.0,
|
||||||
storage_dir: None,
|
storage_dir: None,
|
||||||
math_assist: false,
|
math_assist: false,
|
||||||
|
touch_draw: cfg!(target_os = "android"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,6 +358,7 @@ mod tests {
|
|||||||
eraser_radius_mm: 6.0,
|
eraser_radius_mm: 6.0,
|
||||||
storage_dir: Some(PathBuf::from("/home/pia/Nextcloud/ink-notes")),
|
storage_dir: Some(PathBuf::from("/home/pia/Nextcloud/ink-notes")),
|
||||||
math_assist: true,
|
math_assist: true,
|
||||||
|
touch_draw: true,
|
||||||
};
|
};
|
||||||
settings.save_to(&path).unwrap();
|
settings.save_to(&path).unwrap();
|
||||||
assert_eq!(UiSettings::load_from(&path), settings);
|
assert_eq!(UiSettings::load_from(&path), settings);
|
||||||
|
|||||||
@@ -319,6 +319,8 @@ pub enum UiAction {
|
|||||||
SetSidebarSide(SidebarSide),
|
SetSidebarSide(SidebarSide),
|
||||||
/// Compute handwritten math after `=` on or off (Issue #46)
|
/// Compute handwritten math after `=` on or off (Issue #46)
|
||||||
SetMathAssist(bool),
|
SetMathAssist(bool),
|
||||||
|
/// One finger draws or moves the page (saved, Issue #50)
|
||||||
|
SetTouchDraw(bool),
|
||||||
/// Sprache der Oberfläche; `None` = Sprache des Systems
|
/// Sprache der Oberfläche; `None` = Sprache des Systems
|
||||||
SetLanguage(Option<crate::i18n::Language>),
|
SetLanguage(Option<crate::i18n::Language>),
|
||||||
/// Papierfarbe der Anzeige und Aufhellen dunkler Tinte (wird gespeichert)
|
/// Papierfarbe der Anzeige und Aufhellen dunkler Tinte (wird gespeichert)
|
||||||
@@ -4613,13 +4615,18 @@ pub fn render_ui(
|
|||||||
});
|
});
|
||||||
|
|
||||||
section(ui, t!("EINGABE"));
|
section(ui, t!("EINGABE"));
|
||||||
ui.checkbox(
|
if ui
|
||||||
&mut state.touch_draw_enabled,
|
.checkbox(
|
||||||
t!("Mit dem Finger zeichnen"),
|
&mut state.touch_draw_enabled,
|
||||||
)
|
t!("Mit dem Finger zeichnen"),
|
||||||
.on_hover_text(
|
)
|
||||||
t!("Aus: ein Finger verschiebt, zwei Finger zoomen (empfohlen mit Stift).\nAn: ein Finger zeichnet."),
|
.on_hover_text(
|
||||||
);
|
t!("Aus: ein Finger verschiebt, zwei Finger zoomen (empfohlen mit Stift).\nAn: ein Finger zeichnet."),
|
||||||
|
)
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
actions.push(UiAction::SetTouchDraw(state.touch_draw_enabled));
|
||||||
|
}
|
||||||
let mut math = state.math.enabled;
|
let mut math = state.math.enabled;
|
||||||
if ui
|
if ui
|
||||||
.checkbox(&mut math, t!("Formeln nach „=“ ausrechnen"))
|
.checkbox(&mut math, t!("Formeln nach „=“ ausrechnen"))
|
||||||
|
|||||||
Vendored
+4
@@ -18,6 +18,10 @@ docs of the original crate were removed.
|
|||||||
timestamp of each touch event (Started, Moved, Ended), so ink-notes measures the swipe speed
|
timestamp of each touch event (Started, Moved, Ended), so ink-notes measures the swipe speed
|
||||||
for gliding with the real event times and not with the time it got around to handling them
|
for gliding with the real event times and not with the time it got around to handling them
|
||||||
(Issue #28).
|
(Issue #28).
|
||||||
|
- `src/platform_impl/linux/wayland/event_loop/mod.rs`: every read from the Wayland socket wakes
|
||||||
|
the app (`AboutToWait`), also when the events belong to another queue on the same connection.
|
||||||
|
octotablet's pen events live on such a queue and only `dispatch_pending` it, so before, pen
|
||||||
|
strokes waited until something else woke the loop (Issue #53).
|
||||||
- `Cargo.toml`: `[lints.rust] warnings = "allow"`, because a path dependency is not built with
|
- `Cargo.toml`: `[lints.rust] warnings = "allow"`, because a path dependency is not built with
|
||||||
capped lints like a crates.io dependency.
|
capped lints like a crates.io dependency.
|
||||||
|
|
||||||
|
|||||||
@@ -105,10 +105,11 @@ impl<T: 'static> EventLoop<T> {
|
|||||||
let wayland_dispatcher =
|
let wayland_dispatcher =
|
||||||
calloop::Dispatcher::new(wayland_source, |_, queue, winit_state: &mut WinitState| {
|
calloop::Dispatcher::new(wayland_source, |_, queue, winit_state: &mut WinitState| {
|
||||||
let result = queue.dispatch_pending(winit_state);
|
let result = queue.dispatch_pending(winit_state);
|
||||||
if result.is_ok()
|
// ink-notes patch: wake the app for every read from the socket, not only for
|
||||||
&& (!winit_state.events_sink.is_empty()
|
// winit's own events. Events for other queues on the same connection (pen
|
||||||
|| !winit_state.window_compositor_updates.is_empty())
|
// input from octotablet's queue) would otherwise wait until something else
|
||||||
{
|
// wakes the loop, so pen strokes appeared late or not at all (Issue #53).
|
||||||
|
if result.is_ok() {
|
||||||
winit_state.dispatched_events = true;
|
winit_state.dispatched_events = true;
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
|||||||
Reference in new issue
Block a user