mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-03 15:05:02 -06:00
M3: All tools expands to a full, searchable view
An expand button at the top-left of the All tools sidebar opens a view that fills the workspace, like Acrobat's tools page: every tool as a tile, filed under five categories (Create & Edit, Review & Compare, Forms & Signatures, Protect & Standardize, Customize & Automate), with a search field that matches tool names and the items inside each tool, in English or the UI language. Choosing a tile opens that tool's panel; Collapse, Esc or another workspace puts the view away. `--tools full` opens it from the command line and the control channel. The categories live in the engine catalogue (TOOL_CATEGORIES), with a test that every tool group is in exactly one. Six new strings are translated in all 22 catalogues. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
afa8e1843c
commit
3ec7ce8aae
+22
-22
@@ -7,7 +7,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Greek UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "cefa955aa92790d6773cb1d1e15e19019b3165a00528d57d6617362e1d1988ab"
|
||||
sha256 = "d779dbb265c576d68cd804d0a0505ac5821d74f2d4e5afb663516d8801e0fbbc"
|
||||
|
||||
# ATTRIBUTION.toml: one entry per asset (AGENTS.md §1). The source of truth for provenance and licences.
|
||||
# ATTRIBUTION.md is generated from this file: `cargo xtask assets --write`. Checked by `cargo xtask assets` (part of `xtask ci`).
|
||||
@@ -30,7 +30,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Simplified Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "1de29a6cc089be31cb6206bf41e0715f8ddcf74ef887b45ccee235d743bed223"
|
||||
sha256 = "69a7a36b9b8fbe6cd04d7f287a77deb01c243cc0f1a438511cf35748dde6b3df"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/zh-hant.tsv"
|
||||
@@ -41,7 +41,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Traditional Chinese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "8c6d5b1505d76bc7ba606c98660afa60b1152c5b4c2e7d345104a6ef3d280ed2"
|
||||
sha256 = "12a568bf7a626ff3e34009150894eabe3c0927589756d8635fc9bae19638a512"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/cs.tsv"
|
||||
@@ -52,7 +52,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Czech UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "8a8aed18bd8fceabd1389580361ba75b0dccf141d845650a353d8dfe19c95536"
|
||||
sha256 = "0fd03fafffc2d75bf484186a7dd6ab15ab95d79448e0e798f57519515d73ac4e"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/pt-br.tsv"
|
||||
@@ -63,7 +63,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Brazilian Portuguese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "1c197ac045810950aceb733152a296f2224f38857b1169032fdc7092ab4aa3f7"
|
||||
sha256 = "d3292e186768f75b9cb87097688ff4909c26c9810a7e6542c127aad9fbce5af3"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/es.tsv"
|
||||
@@ -74,7 +74,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Spanish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "a9cf0e062b006b40f549ce2316b88d4b0196d70bd9cecd66c12d980d699bf679"
|
||||
sha256 = "14c9f2ba61ffc925b01e6bf31c7f7761fb5e7adcda1751f6768829341a8e3757"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/fr.tsv"
|
||||
@@ -85,7 +85,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "French UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "ef5c84bd13ef8318f7deab7f42136cfe3c14cbef6fd5231014b94167baaecd2a"
|
||||
sha256 = "d2dc6bd5de197eff60a440a05c58c6b7307009ecb08ddf8fbb31ff616633e36e"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/de.tsv"
|
||||
@@ -96,7 +96,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "German UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "be689af8bb22537879269ad9ab9bdcc4b730665cf0b27c6bf4bad560cacf3b69"
|
||||
sha256 = "b6ffc5eda71ea13eaea79f5f3368811cb317f0a43e6f6be167bb4742d8e1ae77"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/te.tsv"
|
||||
@@ -107,7 +107,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Telugu UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "989d2e5f57cf22c21a85951835ca9fbd05e314da67eb4c17332df1f03679fa00"
|
||||
sha256 = "37b60dda614ebc0e2b141cb27c9b2b7d13b49b347c1a5acb4d395147fbbdd246"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/it.tsv"
|
||||
@@ -118,7 +118,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Italian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "425c42acb8d98ac31b216b13c05a285e0676318dd379dcfb9d57cc7329e9d7a5"
|
||||
sha256 = "0055dfb04a35abd2c8da01bf3836855074e17bbd2b6332b2d1cecd16fd816938"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/pl.tsv"
|
||||
@@ -129,7 +129,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Polish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "988bcf2e0322a46c0464ff7b91ab5d90193b0ea7f454812d12595eb843de6fc7"
|
||||
sha256 = "e1c4801f9633f5873f5dc07fa6de01375369b636282fa22e8cd223adb9737b42"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/ru.tsv"
|
||||
@@ -140,7 +140,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Russian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "ebe7aa9152baff38ae7e36aeb4f6a7ed2198166ab93425a612a66d53e43cb363"
|
||||
sha256 = "36bd183e5bb36e76e2eb40ac68d06f2d0dcd962b42998917ba3ad5e7d8ca2b19"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/hu.tsv"
|
||||
@@ -151,7 +151,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Hungarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "69d2da21949f02c3c40f71159e377eef2fdd1a87f749d6c504e1d151ef33f643"
|
||||
sha256 = "c10dab015d7cabc571dd2a462a0ca22a1b1461b9b747c4998e7a7e4e1f9b6b71"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/bg.tsv"
|
||||
@@ -162,7 +162,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Bulgarian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "98359685aa555f391846f2259ac302ce1234c7a180fb4abe07c36e0c1c62211e"
|
||||
sha256 = "7b1db4f5f3ce50c8b995037d84cce86088e3af17942b2e1d0197234a2454ecdd"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/kk.tsv"
|
||||
@@ -173,7 +173,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Kazakh UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "9f6296d9c79c848167fc80bb4cfaacc9e60f72edb70cc1d70f7b6088ada83578"
|
||||
sha256 = "3ef5f6e5c28c8060017b1219d0ae3fe6308eaa4f69baf821816da1ac2b4468cd"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/ja.tsv"
|
||||
@@ -184,7 +184,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Japanese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "3528e85afd4117de2c22b9f37d32a380a073a49834fa5a3063d21b803606ffbf"
|
||||
sha256 = "d2b91bcf778610861b515865339a487f279f68188617fd2729e0d8d8455d7a2b"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/uk.tsv"
|
||||
@@ -195,7 +195,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Ukrainian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "4db7e23074d44305f4584e2cd8b9a0fc35b433cb187dad493c8f7d78a8cd4ad2"
|
||||
sha256 = "b3a0c1563ba9c67ffbebf805769bae9c5a809cd14fd37a0441a30e19cacb28c8"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/ar.tsv"
|
||||
@@ -206,7 +206,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Arabic UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "2af01de9509db4b4ae61193f41ff0f7f3b70ca5f91cd2afda667e90d34980b25"
|
||||
sha256 = "15dde8ef0f0d20a6e99b82c7f5297b41130e9f0d8f11494fcdc09c69bcbfb43c"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/tr.tsv"
|
||||
@@ -217,7 +217,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Turkish UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "de988b6959572931c4878a0588109c236bf8c5d46ef57c7a406b6ab42de51339"
|
||||
sha256 = "9d879f455313d528d2d8c91e080a1fa199f50d901c7691f7b6dc3f15be73fd1a"
|
||||
|
||||
[[asset]]
|
||||
path = "crates/ui-egui/src/i18n/lt.tsv"
|
||||
@@ -228,7 +228,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Lithuanian UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "63955758227bd57329b22dc7c16ed9cee8b0a15df9453477755849c886424dd5"
|
||||
sha256 = "b300a148c46c122b84ee9b978979ad41c3b4fbb220a488989bb991e0062d9885"
|
||||
|
||||
|
||||
[[asset]]
|
||||
@@ -240,7 +240,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Vietnamese UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "b54adaa6515dbfb0de3859b30989054e5fcc4f56e66e9cc713c7bf509bdbbac3"
|
||||
sha256 = "4c09041b54acbdb7c5fe16409b2fa699d260200fec8600000d668c9af7636f8c"
|
||||
|
||||
[[asset]]
|
||||
path = "assets/icons/accessibility.svg"
|
||||
@@ -3363,7 +3363,7 @@ licence = "MIT OR Apache-2.0"
|
||||
licence_file = "LICENSE-MIT"
|
||||
kind = "translation"
|
||||
usage = "Slovene UI strings, compiled in by crates/ui-egui/src/i18n/mod.rs"
|
||||
sha256 = "5881cc7fbfe9da5f5f611309dacf267f95db3a143b916a113b649839019b292c"
|
||||
sha256 = "bb3a8708b1a2f72782ab41b0ae43e902f089caffd545004f5d1b2112d20df78c"
|
||||
|
||||
[[asset]]
|
||||
path = "vendor/vello_common/assets/probe.png"
|
||||
|
||||
@@ -547,6 +547,23 @@ pub fn group(id: &str) -> Option<&'static ToolGroup> {
|
||||
TOOL_GROUPS.iter().find(|g| g.id == id)
|
||||
}
|
||||
|
||||
/// A heading of the expanded All tools view, as Acrobat files its tools under "Create & Edit",
|
||||
/// "Forms & Signatures" and so on. Every group belongs to exactly one category.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ToolCategory {
|
||||
pub label: &'static str,
|
||||
/// [`ToolGroup::id`]s, in display order.
|
||||
pub groups: &'static [&'static str],
|
||||
}
|
||||
|
||||
pub static TOOL_CATEGORIES: &[ToolCategory] = &[
|
||||
ToolCategory { label: "Create & Edit", groups: &["create", "edit", "export", "combine", "organize", "scan", "compress"] },
|
||||
ToolCategory { label: "Review & Compare", groups: &["comment", "stamp", "compare", "measure"] },
|
||||
ToolCategory { label: "Forms & Signatures", groups: &["fill_sign", "form", "certificate"] },
|
||||
ToolCategory { label: "Protect & Standardize", groups: &["protect", "redact", "accessibility", "standards", "print_production"] },
|
||||
ToolCategory { label: "Customize & Automate", groups: &["actions", "javascript", "search_index", "ai"] },
|
||||
];
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -561,6 +578,18 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_group_is_in_exactly_one_category() {
|
||||
let mut seen = HashSet::new();
|
||||
for c in TOOL_CATEGORIES {
|
||||
for id in c.groups {
|
||||
assert!(group(id).is_some(), "{} lists unknown group {id}", c.label);
|
||||
assert!(seen.insert(*id), "{id} is in two categories");
|
||||
}
|
||||
}
|
||||
assert_eq!(seen.len(), TOOL_GROUPS.len(), "a group is in no category");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commands_are_namespaced() {
|
||||
for g in TOOL_GROUPS {
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
//! The expanded All tools view: every tool, filed under Acrobat-style categories, with a search
|
||||
//! field, filling the workspace instead of the sidebar. The sidebar's expand button opens it;
|
||||
//! its collapse button, Esc or choosing a tool closes it again.
|
||||
|
||||
use egui::{Align2, Color32, CornerRadius, Rect, Sense, Stroke, vec2};
|
||||
use pdfcraft_engine::catalog::{self, Availability, TOOL_CATEGORIES, ToolGroup};
|
||||
|
||||
use crate::theme::{self, Tokens};
|
||||
use crate::{PdfCraftApp, icons, widgets};
|
||||
|
||||
const TILE: egui::Vec2 = vec2(148.0, 118.0);
|
||||
/// Item names a tile lists when the search found the tool by them.
|
||||
const MATCHES_SHOWN: usize = 2;
|
||||
|
||||
/// Whether `group` matches `query` (already trimmed and lower-cased), in English or the UI
|
||||
/// language. `None` is no match; otherwise the items that matched, empty when the tool's own
|
||||
/// name did.
|
||||
fn matches(query: &str, group: &ToolGroup) -> Option<Vec<&'static str>> {
|
||||
let hit = |label: &str| label.to_lowercase().contains(query) || tl!(label).to_lowercase().contains(query);
|
||||
if query.is_empty() || hit(group.label) {
|
||||
return Some(Vec::new());
|
||||
}
|
||||
let items: Vec<_> = group.sections.iter().flat_map(|s| s.items.iter()).map(|i| i.label).filter(|l| hit(l)).collect();
|
||||
(!items.is_empty()).then_some(items)
|
||||
}
|
||||
|
||||
pub fn show(app: &mut PdfCraftApp, ui: &mut egui::Ui) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
if ui.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
app.all_tools_full = false;
|
||||
return;
|
||||
}
|
||||
let mut chosen = None;
|
||||
egui::Frame::NONE.fill(t.panel).show(ui, |ui| {
|
||||
ui.set_min_size(ui.available_size());
|
||||
egui::Frame::NONE.inner_margin(egui::Margin { left: 36, right: 28, top: 20, bottom: 12 }).show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(egui::RichText::new(tl!("All tools")).font(theme::semibold(22.0)).color(t.text));
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
if icons::button(ui, "minimize-2", 28.0, false, tl!("Collapse")).clicked() {
|
||||
app.all_tools_full = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
ui.add_space(10.0);
|
||||
let field = ui.add(
|
||||
widgets::line(&mut app.all_tools_query).hint_text(tl!("Search tools and commands…")).desired_width(ui.available_width().min(520.0)),
|
||||
);
|
||||
// Typing goes straight to the search, as in Acrobat's tools view.
|
||||
if !ui.memory(|m| m.focused().is_some()) {
|
||||
field.request_focus();
|
||||
}
|
||||
});
|
||||
ui.separator();
|
||||
let query = app.all_tools_query.trim().to_lowercase();
|
||||
egui::ScrollArea::vertical().auto_shrink([false, false]).show(ui, |ui| {
|
||||
egui::Frame::NONE.inner_margin(egui::Margin { left: 36, right: 28, top: 8, bottom: 28 }).show(ui, |ui| {
|
||||
ui.set_width(ui.available_width());
|
||||
let mut any = false;
|
||||
for category in TOOL_CATEGORIES {
|
||||
let found: Vec<_> =
|
||||
category.groups.iter().filter_map(|id| catalog::group(id)).filter_map(|g| matches(&query, g).map(|m| (g, m))).collect();
|
||||
if found.is_empty() {
|
||||
continue;
|
||||
}
|
||||
any = true;
|
||||
ui.add_space(12.0);
|
||||
ui.label(egui::RichText::new(tl!(category.label)).font(theme::semibold(16.0)).color(t.text));
|
||||
ui.add_space(10.0);
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.spacing_mut().item_spacing = vec2(14.0, 14.0);
|
||||
for (g, items) in found {
|
||||
if tile(ui, &t, g, &items).clicked() {
|
||||
chosen = Some(g.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
}
|
||||
if !any {
|
||||
ui.add_space(24.0);
|
||||
ui.label(egui::RichText::new(tl!("No tools match your search.")).color(t.text_muted));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
if let Some(id) = chosen {
|
||||
app.all_tools_full = false;
|
||||
app.left_open = true;
|
||||
app.select_tool(id);
|
||||
}
|
||||
}
|
||||
|
||||
fn tile(ui: &mut egui::Ui, t: &Tokens, g: &ToolGroup, items: &[&'static str]) -> egui::Response {
|
||||
let (rect, resp) = ui.allocate_exact_size(TILE, Sense::click());
|
||||
resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, tl!(g.label)));
|
||||
let press = theme::Press::track(ui, &resp);
|
||||
crate::home::card_lift(ui, t, rect, press);
|
||||
ui.painter().rect(rect, CornerRadius::same(10), press.fill(t.card, t.hover, t.pressed), Stroke::new(1.0, t.divider), egui::StrokeKind::Inside);
|
||||
let body = rect.translate(press.offset());
|
||||
let ready = g.availability == Availability::Ready;
|
||||
let hue = Color32::from_rgb(g.hue[0], g.hue[1], g.hue[2]);
|
||||
icons::paint(ui, Rect::from_center_size(body.center_top() + vec2(0.0, 34.0), vec2(32.0, 32.0)), g.icon, 30.0, hue);
|
||||
let mut job =
|
||||
egui::text::LayoutJob::simple(tl!(g.label).to_owned(), theme::medium(13.0), if ready { t.text } else { t.text_muted }, body.width() - 16.0);
|
||||
job.halign = egui::Align::Center;
|
||||
job.wrap.max_rows = 2;
|
||||
let title = ui.fonts_mut(|f| f.layout_job(job));
|
||||
let mut elided = title.elided;
|
||||
let title_h = title.size().y;
|
||||
ui.painter().galley(body.center_top() + vec2(0.0, 60.0), title, t.text);
|
||||
// What found the tool, or else whether it works today.
|
||||
let note = if items.is_empty() {
|
||||
match g.availability {
|
||||
Availability::Ready => String::new(),
|
||||
Availability::Planned(m) => format!("{} · {m}", tl!("Planned")),
|
||||
Availability::Provider => g.badge.map(|b| tl!(b).to_owned()).unwrap_or_default(),
|
||||
}
|
||||
} else {
|
||||
items.iter().take(MATCHES_SHOWN).map(|l| tl!(l)).collect::<Vec<_>>().join(" · ")
|
||||
};
|
||||
if !note.is_empty() {
|
||||
let color = if items.is_empty() { t.text_faint } else { t.accent_text };
|
||||
let mut job = egui::text::LayoutJob::simple_singleline(note.clone(), theme::regular(11.0), color);
|
||||
job.halign = egui::Align::Center;
|
||||
job.wrap = egui::text::TextWrapping { max_width: body.width() - 16.0, max_rows: 1, break_anywhere: true, ..Default::default() };
|
||||
let galley = ui.fonts_mut(|f| f.layout_job(job));
|
||||
elided |= galley.elided;
|
||||
ui.painter().galley(body.center_top() + vec2(0.0, 64.0 + title_h), galley, color);
|
||||
}
|
||||
if let Some(b) = g.badge.filter(|_| g.availability == Availability::Ready) {
|
||||
let font = theme::semibold(9.5);
|
||||
let w = widgets::text_width(ui, tl!(b), &font);
|
||||
let r = Rect::from_min_size(body.right_top() + vec2(-w - 18.0, 8.0), vec2(w + 10.0, 16.0));
|
||||
ui.painter().rect_filled(r, CornerRadius::same(4), t.badge_new);
|
||||
ui.painter().text(r.center(), Align2::CENTER_CENTER, tl!(b), font, Color32::WHITE);
|
||||
}
|
||||
let resp = if elided { resp.on_hover_text(format!("{}\n{note}", tl!(g.label))) } else { resp };
|
||||
theme::hand(resp)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn group(id: &str) -> &'static ToolGroup {
|
||||
catalog::group(id).expect("catalogue group")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search_matches_tool_names_and_their_items() {
|
||||
assert_eq!(matches("", group("organize")), Some(Vec::new()), "an empty query shows everything");
|
||||
assert_eq!(matches("organize", group("organize")), Some(Vec::new()), "the tool's own name");
|
||||
let rotate = matches("rotate", group("organize")).expect("Organize pages lists Rotate");
|
||||
assert!(!rotate.is_empty() && rotate.iter().all(|l| l.to_lowercase().contains("rotate")), "{rotate:?}");
|
||||
assert_eq!(matches("no such tool anywhere", group("organize")), None);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ use crate::{PdfCraftApp, icons, panels::human_size, widgets};
|
||||
const RECOMMENDED: [&str; 5] = ["organize", "comment", "form", "edit", "protect"];
|
||||
|
||||
/// A soft shadow that rises on hover and settles when the card is pressed.
|
||||
fn card_lift(ui: &egui::Ui, t: &Tokens, rect: Rect, press: theme::Press) {
|
||||
pub(crate) fn card_lift(ui: &egui::Ui, t: &Tokens, rect: Rect, press: theme::Press) {
|
||||
let lift = press.hover * (1.0 - press.down);
|
||||
if lift > 0.04 {
|
||||
let shadow = egui::Shadow { offset: [0, 3], blur: (14.0 * lift) as u8, spread: 0, color: t.page_shadow.gamma_multiply(0.85 * lift) };
|
||||
|
||||
@@ -2706,3 +2706,9 @@ certificate Version الإصدار
|
||||
Make properties default جعل الخصائص افتراضية
|
||||
Pages selected الصفحات المحددة
|
||||
Page properties خصائص الصفحة
|
||||
Create & Edit الإنشاء والتحرير
|
||||
Review & Compare المراجعة والمقارنة
|
||||
Forms & Signatures النماذج والتوقيعات
|
||||
Protect & Standardize الحماية والتوحيد القياسي
|
||||
Customize & Automate التخصيص والأتمتة
|
||||
No tools match your search. لا توجد أدوات تطابق بحثك.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2391,3 +2391,9 @@ animation effects Off Изключени
|
||||
Make properties default Задаване като свойства по подразбиране
|
||||
Pages selected Избрани страници
|
||||
Page properties Свойства на страницата
|
||||
Create & Edit Създаване и редактиране
|
||||
Review & Compare Преглед и сравнение
|
||||
Forms & Signatures Формуляри и подписи
|
||||
Protect & Standardize Защита и стандартизация
|
||||
Customize & Automate Персонализиране и автоматизация
|
||||
No tools match your search. Няма инструменти, отговарящи на търсенето.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 8 and column 16.
|
@@ -2502,3 +2502,9 @@ animation effects Off Vypnuto
|
||||
Make properties default Nastavit vlastnosti jako výchozí
|
||||
Pages selected Vybrané stránky
|
||||
Page properties Vlastnosti stránky
|
||||
Create & Edit Vytváření a úpravy
|
||||
Review & Compare Revize a porovnání
|
||||
Forms & Signatures Formuláře a podpisy
|
||||
Protect & Standardize Ochrana a standardizace
|
||||
Customize & Automate Přizpůsobení a automatizace
|
||||
No tools match your search. Hledání neodpovídá žádný nástroj.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2429,3 +2429,9 @@ animation effects Off Aus
|
||||
Make properties default Eigenschaften als Standard festlegen
|
||||
Pages selected Ausgewählte Seiten
|
||||
Page properties Seiteneigenschaften
|
||||
Create & Edit Erstellen & Bearbeiten
|
||||
Review & Compare Prüfen & Vergleichen
|
||||
Forms & Signatures Formulare & Signaturen
|
||||
Protect & Standardize Schützen & Standardisieren
|
||||
Customize & Automate Anpassen & Automatisieren
|
||||
No tools match your search. Keine Werkzeuge entsprechen Ihrer Suche.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 51.
|
@@ -2438,3 +2438,9 @@ animation effects Off Ανενεργά
|
||||
Make properties default Ορισμός ιδιοτήτων ως προεπιλογή
|
||||
Pages selected Επιλεγμένες σελίδες
|
||||
Page properties Ιδιότητες σελίδας
|
||||
Create & Edit Δημιουργία και επεξεργασία
|
||||
Review & Compare Αναθεώρηση και σύγκριση
|
||||
Forms & Signatures Φόρμες και υπογραφές
|
||||
Protect & Standardize Προστασία και τυποποίηση
|
||||
Customize & Automate Προσαρμογή και αυτοματοποίηση
|
||||
No tools match your search. Κανένα εργαλείο δεν ταιριάζει με την αναζήτησή σας.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 476 and column 9.
|
@@ -2568,3 +2568,9 @@ animation effects Off Desactivados
|
||||
Make properties default Usar como propiedades predeterminadas
|
||||
Pages selected Páginas seleccionadas
|
||||
Page properties Propiedades de página
|
||||
Create & Edit Crear y editar
|
||||
Review & Compare Revisar y comparar
|
||||
Forms & Signatures Formularios y firmas
|
||||
Protect & Standardize Proteger y estandarizar
|
||||
Customize & Automate Personalizar y automatizar
|
||||
No tools match your search. Ninguna herramienta coincide con la búsqueda.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 60.
|
@@ -2428,3 +2428,9 @@ animation effects Off Désactivés
|
||||
Make properties default Définir comme propriétés par défaut
|
||||
Pages selected Pages sélectionnées
|
||||
Page properties Propriétés de la page
|
||||
Create & Edit Créer et modifier
|
||||
Review & Compare Réviser et comparer
|
||||
Forms & Signatures Formulaires et signatures
|
||||
Protect & Standardize Protéger et normaliser
|
||||
Customize & Automate Personnaliser et automatiser
|
||||
No tools match your search. Aucun outil ne correspond à votre recherche.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 39.
|
@@ -2427,3 +2427,9 @@ animation effects Off Ki
|
||||
Make properties default Tulajdonságok beállítása alapértelmezettként
|
||||
Pages selected Kijelölt oldalak
|
||||
Page properties Oldaltulajdonságok
|
||||
Create & Edit Létrehozás és szerkesztés
|
||||
Review & Compare Áttekintés és összehasonlítás
|
||||
Forms & Signatures Űrlapok és aláírások
|
||||
Protect & Standardize Védelem és szabványosítás
|
||||
Customize & Automate Testreszabás és automatizálás
|
||||
No tools match your search. Egy eszköz sem felel meg a keresésnek.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 44.
|
@@ -2640,3 +2640,9 @@ certificate Key usage Utilizzo chiave
|
||||
certificate Self-signed Autofirmato
|
||||
certificate SHA-1 digest Impronta SHA-1
|
||||
certificate SHA-256 digest Impronta SHA-256
|
||||
Create & Edit Crea e modifica
|
||||
Review & Compare Revisione e confronto
|
||||
Forms & Signatures Moduli e firme
|
||||
Protect & Standardize Proteggi e standardizza
|
||||
Customize & Automate Personalizza e automatizza
|
||||
No tools match your search. Nessuno strumento corrisponde alla ricerca.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2428,3 +2428,9 @@ animation effects Off オフ
|
||||
Make properties default プロパティをデフォルトに設定
|
||||
Pages selected 選択したページ
|
||||
Page properties ページのプロパティ
|
||||
Create & Edit 作成と編集
|
||||
Review & Compare レビューと比較
|
||||
Forms & Signatures フォームと署名
|
||||
Protect & Standardize 保護と標準化
|
||||
Customize & Automate カスタマイズと自動化
|
||||
No tools match your search. 検索に一致するツールはありません。
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2426,3 +2426,9 @@ animation effects Off Өшірулі
|
||||
Make properties default Қасиеттерді әдепкі ету
|
||||
Pages selected Таңдалған беттер
|
||||
Page properties Бет қасиеттері
|
||||
Create & Edit Жасау және өңдеу
|
||||
Review & Compare Шолу және салыстыру
|
||||
Forms & Signatures Пішіндер және қолтаңбалар
|
||||
Protect & Standardize Қорғау және стандарттау
|
||||
Customize & Automate Баптау және автоматтандыру
|
||||
No tools match your search. Іздеуге сәйкес құралдар жоқ.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 825 and column 9.
|
@@ -2672,3 +2672,9 @@ key Space Tarpas
|
||||
Make properties default Nustatyti ypatybes kaip numatytąsias
|
||||
Pages selected Pasirinkti puslapiai
|
||||
Page properties Puslapio ypatybės
|
||||
Create & Edit Kūrimas ir redagavimas
|
||||
Review & Compare Peržiūra ir palyginimas
|
||||
Forms & Signatures Formos ir parašai
|
||||
Protect & Standardize Apsauga ir standartizavimas
|
||||
Customize & Automate Pritaikymas ir automatizavimas
|
||||
No tools match your search. Paieškos neatitinka joks įrankis.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 404 and column 9.
|
@@ -811,6 +811,9 @@ mod tests {
|
||||
for command in pdfcraft_engine::commands::COMMANDS {
|
||||
assert!(has(JA(), command.label), "missing command: {}", command.label);
|
||||
}
|
||||
for category in pdfcraft_engine::catalog::TOOL_CATEGORIES {
|
||||
assert!(has(JA(), category.label), "missing category: {}", category.label);
|
||||
}
|
||||
for group in pdfcraft_engine::catalog::TOOL_GROUPS {
|
||||
assert!(has(JA(), group.label), "missing group: {}", group.label);
|
||||
for section in group.sections {
|
||||
|
||||
@@ -2408,3 +2408,9 @@ animation effects Off Wyłączone
|
||||
Make properties default Ustaw właściwości jako domyślne
|
||||
Pages selected Zaznaczone strony
|
||||
Page properties Właściwości strony
|
||||
Create & Edit Tworzenie i edycja
|
||||
Review & Compare Recenzja i porównanie
|
||||
Forms & Signatures Formularze i podpisy
|
||||
Protect & Standardize Ochrona i standaryzacja
|
||||
Customize & Automate Dostosowanie i automatyzacja
|
||||
No tools match your search. Żadne narzędzie nie pasuje do wyszukiwania.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2442,3 +2442,9 @@ animation effects Off Desativados
|
||||
Make properties default Tornar propriedades padrão
|
||||
Pages selected Páginas selecionadas
|
||||
Page properties Propriedades da página
|
||||
Create & Edit Criar e editar
|
||||
Review & Compare Revisar e comparar
|
||||
Forms & Signatures Formulários e assinaturas
|
||||
Protect & Standardize Proteger e padronizar
|
||||
Customize & Automate Personalizar e automatizar
|
||||
No tools match your search. Nenhuma ferramenta corresponde à pesquisa.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -2341,3 +2341,9 @@ animation effects Off Выкл
|
||||
Make properties default Сделать свойства стандартными
|
||||
Pages selected Выделенные страницы
|
||||
Page properties Свойства страницы
|
||||
Create & Edit Создание и редактирование
|
||||
Review & Compare Рецензирование и сравнение
|
||||
Forms & Signatures Формы и подписи
|
||||
Protect & Standardize Защита и стандартизация
|
||||
Customize & Automate Настройка и автоматизация
|
||||
No tools match your search. Нет инструментов, соответствующих запросу.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -2433,3 +2433,9 @@ animation effects Off Izklopljeni
|
||||
Make properties default Nastavi lastnosti kot privzete
|
||||
Pages selected Izbrane strani
|
||||
Page properties Lastnosti strani
|
||||
Create & Edit Ustvarjanje in urejanje
|
||||
Review & Compare Pregled in primerjava
|
||||
Forms & Signatures Obrazci in podpisi
|
||||
Protect & Standardize Zaščita in standardizacija
|
||||
Customize & Automate Prilagajanje in avtomatizacija
|
||||
No tools match your search. Iskanju ne ustreza nobeno orodje.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -2341,3 +2341,9 @@ animation effects Off ఆఫ్
|
||||
Make properties default లక్షణాలను డిఫాల్ట్గా చేయి
|
||||
Pages selected ఎంచుకున్న పేజీలు
|
||||
Page properties పేజీ లక్షణాలు
|
||||
Create & Edit సృష్టించు & సవరించు
|
||||
Review & Compare సమీక్షించు & పోల్చు
|
||||
Forms & Signatures ఫారమ్లు & సంతకాలు
|
||||
Protect & Standardize రక్షించు & ప్రామాణీకరించు
|
||||
Customize & Automate అనుకూలీకరించు & ఆటోమేట్ చేయి
|
||||
No tools match your search. మీ శోధనకు సరిపోలే సాధనాలు లేవు.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 13 and column 16.
|
@@ -2424,3 +2424,9 @@ animation effects Off Kapalı
|
||||
Make properties default Özellikleri varsayılan yap
|
||||
Pages selected Seçilen sayfalar
|
||||
Page properties Sayfa özellikleri
|
||||
Create & Edit Oluştur ve Düzenle
|
||||
Review & Compare İncele ve Karşılaştır
|
||||
Forms & Signatures Formlar ve İmzalar
|
||||
Protect & Standardize Koru ve Standartlaştır
|
||||
Customize & Automate Özelleştir ve Otomatikleştir
|
||||
No tools match your search. Aramanızla eşleşen araç yok.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 824 and column 9.
|
@@ -2450,3 +2450,9 @@ animation effects Off Вимкнено
|
||||
Make properties default Зробити властивості типовими
|
||||
Pages selected Вибрані сторінки
|
||||
Page properties Властивості сторінки
|
||||
Create & Edit Створення й редагування
|
||||
Review & Compare Рецензування й порівняння
|
||||
Forms & Signatures Форми й підписи
|
||||
Protect & Standardize Захист і стандартизація
|
||||
Customize & Automate Налаштування й автоматизація
|
||||
No tools match your search. Немає інструментів, що відповідають пошуку.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2615,3 +2615,9 @@ key Space Space
|
||||
Redact Image Xóa nội dung nhạy cảm của hình ảnh
|
||||
Create Link… Tạo liên kết…
|
||||
Recognize Text… Nhận dạng văn bản…
|
||||
Create & Edit Tạo và chỉnh sửa
|
||||
Review & Compare Xem xét và so sánh
|
||||
Forms & Signatures Biểu mẫu và chữ ký
|
||||
Protect & Standardize Bảo vệ và chuẩn hóa
|
||||
Customize & Automate Tùy chỉnh và tự động hóa
|
||||
No tools match your search. Không có công cụ nào khớp với tìm kiếm.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 490 and column 12.
|
@@ -2392,3 +2392,9 @@ animation effects Off 关
|
||||
Make properties default 将属性设为默认
|
||||
Pages selected 选定的页面
|
||||
Page properties 页面属性
|
||||
Create & Edit 创建和编辑
|
||||
Review & Compare 审阅和比较
|
||||
Forms & Signatures 表单和签名
|
||||
Protect & Standardize 保护和标准化
|
||||
Customize & Automate 自定义和自动化
|
||||
No tools match your search. 没有与搜索匹配的工具。
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -2384,3 +2384,9 @@ animation effects Off 關
|
||||
Make properties default 將內容設為預設
|
||||
Pages selected 選取的頁面
|
||||
Page properties 頁面屬性
|
||||
Create & Edit 建立與編輯
|
||||
Review & Compare 審閱與比較
|
||||
Forms & Signatures 表單與簽名
|
||||
Protect & Standardize 保護與標準化
|
||||
Customize & Automate 自訂與自動化
|
||||
No tools match your search. 沒有符合搜尋的工具。
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -30,6 +30,7 @@ macro_rules! tl_ctx {
|
||||
|
||||
mod a11y_ui;
|
||||
mod actions_ui;
|
||||
mod all_tools_ui;
|
||||
mod appearance;
|
||||
pub mod canvas;
|
||||
mod chrome;
|
||||
@@ -563,6 +564,9 @@ pub struct PdfCraftApp {
|
||||
pub palette_open: bool,
|
||||
pub palette_query: String,
|
||||
pub all_tools_expanded: bool,
|
||||
/// The All tools view fills the workspace (its sidebar's expand button).
|
||||
pub all_tools_full: bool,
|
||||
pub all_tools_query: String,
|
||||
pub recent: Vec<RecentFile>,
|
||||
/// Preferences: reopen the files that were open when PdfCraft last closed (#442).
|
||||
pub reopen_last_session: bool,
|
||||
@@ -929,6 +933,8 @@ impl PdfCraftApp {
|
||||
palette_open: false,
|
||||
palette_query: String::new(),
|
||||
all_tools_expanded: false,
|
||||
all_tools_full: false,
|
||||
all_tools_query: String::new(),
|
||||
recent: Vec::new(),
|
||||
reopen_last_session: false,
|
||||
last_session: Default::default(),
|
||||
@@ -2171,6 +2177,10 @@ impl PdfCraftApp {
|
||||
/// that panel. The rail stays in Read mode, and its buttons open panels there too (#932).
|
||||
pub(crate) fn switch_mode(&mut self, mode: Mode, select_tools: bool) {
|
||||
let was_read = self.mode == Mode::Read;
|
||||
// Another workspace puts the expanded All tools view away.
|
||||
if mode != Mode::AllTools {
|
||||
self.all_tools_full = false;
|
||||
}
|
||||
if select_tools {
|
||||
self.select_mode(mode);
|
||||
} else {
|
||||
@@ -2549,7 +2559,14 @@ impl PdfCraftApp {
|
||||
_ => Some(Dialog::About),
|
||||
}
|
||||
}
|
||||
("tools", _) => self.all_tools_expanded = value != "collapsed",
|
||||
("tools", _) if value == "full" => {
|
||||
self.mode = Mode::AllTools;
|
||||
self.all_tools_full = true;
|
||||
}
|
||||
("tools", _) => {
|
||||
self.all_tools_full = false;
|
||||
self.all_tools_expanded = value != "collapsed";
|
||||
}
|
||||
("palette", _) => {
|
||||
self.palette_open = true;
|
||||
self.palette_query = value.to_string();
|
||||
@@ -3145,6 +3162,8 @@ impl eframe::App for PdfCraftApp {
|
||||
None => canvas::document_area(self, index, ui),
|
||||
},
|
||||
}
|
||||
} else if self.mode == Mode::AllTools && self.all_tools_full {
|
||||
all_tools_ui::show(self, ui);
|
||||
} else {
|
||||
docking::show(self, ui);
|
||||
}
|
||||
|
||||
@@ -35,11 +35,13 @@ pub fn left_panel(app: &mut PdfCraftApp, ui: &mut egui::Ui) {
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns whether the leading button (Back, or Expand on All tools) and Close were clicked.
|
||||
fn panel_header(ui: &mut egui::Ui, t: &Tokens, title: &str, back: bool) -> (bool, bool) {
|
||||
let mut go_back = false;
|
||||
let mut close = false;
|
||||
ui.horizontal(|ui| {
|
||||
if back && icons::button(ui, "chevron-left", 26.0, false, tl!("Back to all tools")).clicked() {
|
||||
let (icon, tip) = if back { ("chevron-left", "Back to all tools") } else { ("maximize-2", "Expand") };
|
||||
if icons::button(ui, icon, 26.0, false, tl!(tip)).clicked() {
|
||||
go_back = true;
|
||||
}
|
||||
// Reserve space for Close before laying out the translated title. Long tool names
|
||||
@@ -58,7 +60,11 @@ fn panel_header(ui: &mut egui::Ui, t: &Tokens, title: &str, back: bool) -> (bool
|
||||
}
|
||||
|
||||
fn all_tools(app: &mut PdfCraftApp, ui: &mut egui::Ui, t: &Tokens) {
|
||||
let (_, close) = panel_header(ui, t, "All tools", false);
|
||||
let (expand, close) = panel_header(ui, t, "All tools", false);
|
||||
if expand {
|
||||
app.all_tools_full = true;
|
||||
app.mode = crate::Mode::AllTools;
|
||||
}
|
||||
if close {
|
||||
app.left_open = false;
|
||||
}
|
||||
|
||||
@@ -125,6 +125,50 @@ fn every_catalog_tool_is_listed_after_view_more() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expanded_all_tools_lists_every_tool_by_category_and_searches() {
|
||||
let mut h = harness(|_| {});
|
||||
h.get_by_label("Expand").click();
|
||||
h.run_steps(3);
|
||||
assert!(h.state().all_tools_full);
|
||||
for c in pdfcraft_engine::catalog::TOOL_CATEGORIES {
|
||||
h.get_by_label(c.label);
|
||||
}
|
||||
for g in pdfcraft_engine::catalog::TOOL_GROUPS {
|
||||
assert!(h.query_all_by_label(g.label).count() >= 1, "tool {} missing from the expanded view", g.label);
|
||||
}
|
||||
// An item name finds its tool; the other categories drop out.
|
||||
h.state_mut().all_tools_query = "rotate".into();
|
||||
h.run_steps(3);
|
||||
assert_eq!(h.query_all_by_label("Organize pages").count(), 1, "only the expanded view's tile; the sidebar is gone");
|
||||
assert!(h.query_by_label("Forms & Signatures").is_none());
|
||||
h.state_mut().all_tools_query = "no such tool".into();
|
||||
h.run_steps(3);
|
||||
h.get_by_label("No tools match your search.");
|
||||
// Choosing a tool goes back to the workspace with that tool's panel.
|
||||
h.state_mut().all_tools_query = "organize".into();
|
||||
h.run_steps(3);
|
||||
h.get_by_label("Organize pages").click();
|
||||
h.run_steps(3);
|
||||
assert!(!h.state().all_tools_full);
|
||||
assert_eq!(h.state().left, pdfcraft_ui_egui::LeftPanel::Tool("organize"));
|
||||
h.get_by_label("Back to all tools");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collapse_and_escape_close_the_expanded_all_tools() {
|
||||
let mut h = harness(|app| app.set_option("tools", "full").unwrap());
|
||||
h.get_by_label("Collapse").click();
|
||||
h.run_steps(3);
|
||||
assert!(!h.state().all_tools_full);
|
||||
h.get_by_label("View more");
|
||||
h.get_by_label("Expand").click();
|
||||
h.run_steps(3);
|
||||
h.key_press(egui::Key::Escape);
|
||||
h.run_steps(3);
|
||||
assert!(!h.state().all_tools_full);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opening_a_pdf_shows_comments_and_bookmarks() {
|
||||
let mut h = harness(|app| app.open_bytes("fixture.pdf", None, FIXTURE.to_vec()).expect("fixture opens"));
|
||||
|
||||
Reference in New Issue
Block a user