mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 14:41:52 +00:00
Merge pull request #7406 from dotCooCoo/feat/task-bar-blank-canvas
Contextual Task Bar: a blank canvas offers Draw (Pencil) and Place Image
This commit is contained in:
@@ -55,6 +55,42 @@ fn selection_tool_with_selection(app: &VectorcraftApp) -> bool {
|
||||
&& app.session.active().is_some_and(|st| !st.selection.is_empty())
|
||||
}
|
||||
|
||||
/// Whether the bar shows its blank canvas actions, Draw (Pencil) and Place Image: a selection tool is
|
||||
/// in use and the active document has no artwork, only layers and guides.
|
||||
fn blank_canvas(app: &VectorcraftApp) -> bool {
|
||||
fn no_art(nodes: &[std::sync::Arc<vectorcraft_doc::Node>]) -> bool {
|
||||
nodes.iter().all(|n| n.is_guide() || (n.is_layer() && n.children().is_none_or(|c| no_art(c))))
|
||||
}
|
||||
matches!(app.session.tool_id(), "selection" | "directSelection" | "groupSelection")
|
||||
&& app.session.active().is_some_and(|st| st.selection.is_empty() && no_art(&st.doc.layers))
|
||||
}
|
||||
|
||||
/// Where the bar's top edge centers, on screen: under the lowest corner on screen of the selected
|
||||
/// artboards or the selection, centered on them (the view may be rotated); on a blank canvas, which
|
||||
/// has no selection, [`blank_canvas_anchor`]. None with nothing to sit under.
|
||||
fn bar_anchor(app: &mut VectorcraftApp, xf: &Xf, on_artboards: bool, blank: bool) -> Option<Pos2> {
|
||||
if blank {
|
||||
return Some(blank_canvas_anchor(app, xf));
|
||||
}
|
||||
let b = if on_artboards { picked_artboards_bounds(app) } else { app.selection_bounds() }?;
|
||||
let lowest = xf.quad(b).iter().map(|c| c.y).fold(f32::NEG_INFINITY, f32::max);
|
||||
Some(pos2(xf.to_screen(b.center()).x, lowest))
|
||||
}
|
||||
|
||||
/// Where the blank canvas bar's top edge centers, on screen: under the bottom of the active artboard
|
||||
/// when part of it is in view, else the canvas's center.
|
||||
fn blank_canvas_anchor(app: &VectorcraftApp, xf: &Xf) -> Pos2 {
|
||||
let board = app.session.active().and_then(|st| {
|
||||
let last = st.doc.artboards.len().checked_sub(1)?;
|
||||
st.doc.artboards.get(app.view().map_or(0, |v| v.artboard).min(last)).map(|a| a.rect)
|
||||
});
|
||||
let shown = board.map(|b| (b, xf.quad(b))).filter(|(_, q)| egui::Rect::from_points(q).intersects(xf.rect));
|
||||
match shown {
|
||||
Some((b, q)) => pos2(xf.to_screen(b.center()).x, q.iter().map(|c| c.y).fold(f32::NEG_INFINITY, f32::max)),
|
||||
None => xf.rect.center(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a Type tool edits type, or has type selected: its bar then shows only the text
|
||||
/// formatting controls.
|
||||
fn type_tool_on_type(app: &VectorcraftApp) -> bool {
|
||||
@@ -75,6 +111,8 @@ pub(crate) fn task_bar_shows_type(app: &VectorcraftApp) -> bool {
|
||||
/// While a Type tool edits type, or has type selected, the bar shows only those controls and the
|
||||
/// Fill. When one row would be wider than the canvas, the font controls take a row of their own,
|
||||
/// narrowed to fit it, and the actions wrap onto rows under the handle's ([`bar_layout`]).
|
||||
/// On a blank canvas, a document with no artwork and a selection tool in use, it sits under the
|
||||
/// active artboard and offers Draw (Pencil) and Place Image.
|
||||
/// Its handle drags it anywhere on the canvas; unpinned it keeps that offset as it follows the
|
||||
/// selection, pinned it stays put ([`crate::state::TaskBarPlace`]).
|
||||
pub(super) fn task_bar(app: &mut VectorcraftApp, ui: &mut Ui, xf: &Xf) {
|
||||
@@ -83,13 +121,15 @@ pub(super) fn task_bar(app: &mut VectorcraftApp, ui: &mut Ui, xf: &Xf) {
|
||||
// Text added with a Type tool shows its formatting controls, as the help page describes
|
||||
// (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html>).
|
||||
let typing = type_tool_on_type(app);
|
||||
if !(on_artboards || typing || selection_tool_with_selection(app)) {
|
||||
// A blank canvas offers Draw (Pencil) and Place Image, as the same help page describes.
|
||||
let blank = !on_artboards && blank_canvas(app);
|
||||
if !(on_artboards || typing || blank || selection_tool_with_selection(app)) {
|
||||
return;
|
||||
}
|
||||
// Selected type has the font controls too, as the help page describes
|
||||
// (<https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/font-options-overview.html>).
|
||||
let fonts = task_bar_shows_type(app);
|
||||
let Some(b) = (if on_artboards { picked_artboards_bounds(app) } else { app.selection_bounds() }) else { return };
|
||||
let Some(anchor) = bar_anchor(app, xf, on_artboards, blank) else { return };
|
||||
let Some(st) = app.session.active() else { return };
|
||||
let n = st.selection.len();
|
||||
let first = st.selection.objects.first().and_then(|id| st.doc.node(*id));
|
||||
@@ -137,6 +177,10 @@ pub(super) fn task_bar(app: &mut VectorcraftApp, ui: &mut Ui, xf: &Xf) {
|
||||
items.push((tl!("Rearrange All"), "dc-rearrange", TASK_BAR_REARRANGE_ARTBOARDS, none()));
|
||||
}
|
||||
items.push((tl!("Export"), "share-2", "file.exportForScreens", none()));
|
||||
} else if blank {
|
||||
// Draw (Pencil) switches to the Pencil tool; Place Image picks files for the Place dialog.
|
||||
items.push((tl!("Draw (Pencil)"), "pencil", "tool.select", json!({"tool": "pencil"})));
|
||||
items.push((tl!("Place Image"), "image", "file.place", none()));
|
||||
} else if !typing {
|
||||
// The selection tools' object actions. A Type tool's bar leaves them out, Create Outlines
|
||||
// and the type conversions included.
|
||||
@@ -234,27 +278,20 @@ pub(super) fn task_bar(app: &mut VectorcraftApp, ui: &mut Ui, xf: &Xf) {
|
||||
let paints = chip_paints(app, ui.ctx());
|
||||
let colored = has_colors(&st.doc, &st.selection.objects);
|
||||
let doc = st.uid;
|
||||
// Under the selection's lowest corner on screen, centered on the selection (the view may be
|
||||
// rotated).
|
||||
let lowest = xf.quad(b).iter().map(|c| c.y).fold(f32::NEG_INFINITY, f32::max);
|
||||
let anchor = pos2(xf.to_screen(b.center()).x, lowest);
|
||||
let bounds = xf.rect.shrink(8.0);
|
||||
// The canvas's width less the frame's margins and stroke.
|
||||
let room = bounds.width() - BAR_FRAME;
|
||||
// On a canvas too narrow for the type controls at their narrowest, the bar leaves them out.
|
||||
let fonts = fonts && room >= crate::panels::character::task_bar_min_room();
|
||||
// The selected objects' Fill, Stroke, Recolor Artwork (when they have colours to recolour) and
|
||||
// Lock (a basic shape's properties instead), left out with the Artboard tool. A Type tool's bar
|
||||
// has the Fill alone.
|
||||
let chips: Vec<Chip> = [
|
||||
(!on_artboards, Chip::Fill),
|
||||
(!on_artboards && !typing, Chip::Stroke),
|
||||
(!on_artboards && !typing && colored, Chip::Recolor),
|
||||
(!on_artboards && !typing, Chip::Lock),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|(shown, chip)| shown.then_some(chip))
|
||||
.collect();
|
||||
// Lock (a basic shape's properties instead), left out with the Artboard tool and on a blank
|
||||
// canvas, which have no selected objects. A Type tool's bar has the Fill alone.
|
||||
let objects = !on_artboards && !blank;
|
||||
let chips: Vec<Chip> =
|
||||
[(objects, Chip::Fill), (objects && !typing, Chip::Stroke), (objects && !typing && colored, Chip::Recolor), (objects && !typing, Chip::Lock)]
|
||||
.into_iter()
|
||||
.filter_map(|(shown, chip)| shown.then_some(chip))
|
||||
.collect();
|
||||
let widths: Vec<f32> = items.iter().map(|(label, ..)| action_width(ui, label)).collect();
|
||||
let font_w = fonts.then(|| {
|
||||
let w = crate::panels::character::TASK_BAR_WIDTHS;
|
||||
|
||||
@@ -10333,7 +10333,7 @@ fn task_bar_labels(app: &mut VectorcraftApp, ctx: &egui::Context) -> Vec<(String
|
||||
/// With the Artboard tool, the Contextual Task Bar sits under the selected artboards and offers
|
||||
/// Resize, Duplicate, Rearrange All (with two or more artboards) and Export instead of the
|
||||
/// selected objects' actions. With the Selection tool it offers the objects' actions again, and
|
||||
/// with nothing selected it doesn't show.
|
||||
/// with nothing in the document the blank canvas actions.
|
||||
#[test]
|
||||
fn the_task_bar_offers_the_artboard_tools_actions() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
@@ -10341,7 +10341,7 @@ fn the_task_bar_offers_the_artboard_tools_actions() {
|
||||
app.select_tool("selection");
|
||||
let ctx = egui::Context::default();
|
||||
let names = |app: &mut VectorcraftApp| task_bar_labels(app, &ctx).into_iter().map(|(t, _)| t).collect::<Vec<_>>();
|
||||
assert!(names(&mut app).is_empty() && task_bar_rect(&ctx).is_none(), "nothing selected: no bar");
|
||||
assert_eq!(names(&mut app), ["Draw (Pencil)", "Place Image"], "a blank canvas");
|
||||
|
||||
app.select_tool("artboard");
|
||||
crate::panels::artboards::select(&mut app, 1);
|
||||
|
||||
@@ -691,6 +691,8 @@ font-technology Variable Променливи
|
||||
Crop Image Изрязване на изображение
|
||||
Image Tools Инструменти за изображения
|
||||
Remove Background… Премахване на фона…
|
||||
Draw (Pencil) Рисуване (Молив)
|
||||
Place Image Вмъкване на изображение
|
||||
Remove Background Премахване на фона
|
||||
Background Фон
|
||||
Edge Color Цвят на ръба
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -201,6 +201,8 @@
|
||||
Crop Image Izreži sliku
|
||||
Image Tools Alati za slike
|
||||
Remove Background… Ukloni pozadinu…
|
||||
Draw (Pencil) Crtaj (olovka)
|
||||
Place Image Postavi sliku
|
||||
Remove Background Ukloni pozadinu
|
||||
Background Pozadina
|
||||
Edge Color Boja ruba
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1006,6 +1006,8 @@ antiAlias Sharp Nítid
|
||||
Crop Image Retalla la imatge
|
||||
Image Tools Eines d’imatge
|
||||
Remove Background… Elimina el fons…
|
||||
Draw (Pencil) Dibuixa (llapis)
|
||||
Place Image Col·loca una imatge
|
||||
Remove Background Elimina el fons
|
||||
Background Fons
|
||||
Edge Color Color de la vora
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -207,6 +207,8 @@
|
||||
Crop Image Oříznout obraz
|
||||
Image Tools Nástroje obrazu
|
||||
Remove Background… Odstranit pozadí…
|
||||
Draw (Pencil) Kreslit (tužka)
|
||||
Place Image Umístit obraz
|
||||
Remove Background Odstranit pozadí
|
||||
Background Pozadí
|
||||
Edge Color Barva okraje
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -194,6 +194,8 @@
|
||||
Crop Image Beskær billede
|
||||
Image Tools Billedværktøjer
|
||||
Remove Background… Fjern baggrund…
|
||||
Draw (Pencil) Tegn (blyant)
|
||||
Place Image Placér billede
|
||||
Remove Background Fjern baggrund
|
||||
Background Baggrund
|
||||
Edge Color Kantfarve
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -684,6 +684,8 @@ font-technology Variable Variabel
|
||||
Crop Image Bild beschneiden
|
||||
Image Tools Bildwerkzeuge
|
||||
Remove Background… Hintergrund entfernen…
|
||||
Draw (Pencil) Zeichnen (Buntstift)
|
||||
Place Image Bild platzieren
|
||||
Remove Background Hintergrund entfernen
|
||||
Background Hintergrund
|
||||
Edge Color Randfarbe
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -665,6 +665,8 @@ font-technology Variable Μεταβλητές
|
||||
Crop Image Περικοπή εικόνας
|
||||
Image Tools Εργαλεία εικόνας
|
||||
Remove Background… Αφαίρεση φόντου…
|
||||
Draw (Pencil) Σχεδίαση (μολύβι)
|
||||
Place Image Τοποθέτηση εικόνας
|
||||
Remove Background Αφαίρεση φόντου
|
||||
Background Φόντο
|
||||
Edge Color Χρώμα άκρης
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -705,6 +705,8 @@ font-technology Variable Variables
|
||||
Crop Image Recortar imagen
|
||||
Image Tools Herramientas de imagen
|
||||
Remove Background… Quitar fondo…
|
||||
Draw (Pencil) Dibujar (Lápiz)
|
||||
Place Image Colocar imagen
|
||||
Remove Background Quitar fondo
|
||||
Background Fondo
|
||||
Edge Color Color del borde
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -214,6 +214,8 @@
|
||||
Crop Image Rajaa kuva
|
||||
Image Tools Kuvatyökalut
|
||||
Remove Background… Poista tausta…
|
||||
Draw (Pencil) Piirrä (lyijykynä)
|
||||
Place Image Sijoita kuva
|
||||
Remove Background Poista tausta
|
||||
Background Tausta
|
||||
Edge Color Reunan väri
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -707,6 +707,8 @@ font-technology Variable Variables
|
||||
Crop Image Recadrer l’image
|
||||
Image Tools Outils d’image
|
||||
Remove Background… Supprimer l’arrière-plan…
|
||||
Draw (Pencil) Dessiner (Crayon)
|
||||
Place Image Importer une image
|
||||
Remove Background Supprimer l’arrière-plan
|
||||
Background Arrière-plan
|
||||
Edge Color Couleur du bord
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1140,6 +1140,8 @@ antiAlias Sharp शार्प
|
||||
Crop Image इमेज क्रॉप करें
|
||||
Image Tools इमेज टूल
|
||||
Remove Background… पृष्ठभूमि हटाएँ…
|
||||
Draw (Pencil) ड्रा (पेंसिल)
|
||||
Place Image इमेज प्लेस करें
|
||||
Remove Background पृष्ठभूमि हटाएँ
|
||||
Background पृष्ठभूमि
|
||||
Edge Color किनारे का रंग
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -906,6 +906,8 @@ font-technology Variable Változó
|
||||
Crop Image Kép körülvágása
|
||||
Image Tools Képeszközök
|
||||
Remove Background… Háttér eltávolítása…
|
||||
Draw (Pencil) Rajzolás (Ceruza)
|
||||
Place Image Kép elhelyezése
|
||||
Remove Background Háttér eltávolítása
|
||||
Background Háttér
|
||||
Edge Color Szélszín
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -194,6 +194,8 @@
|
||||
Crop Image Pangkas gambar
|
||||
Image Tools Alat Gambar
|
||||
Remove Background… Hapus latar belakang…
|
||||
Draw (Pencil) Menggambar (pensil)
|
||||
Place Image Tempatkan gambar
|
||||
Remove Background Hapus latar belakang
|
||||
Background Latar belakang
|
||||
Edge Color Warna tepi
|
||||
|
||||
|
@@ -705,6 +705,8 @@ font-technology Variable Variabili
|
||||
Crop Image Ritaglia immagine
|
||||
Image Tools Strumenti immagine
|
||||
Remove Background… Rimuovi sfondo…
|
||||
Draw (Pencil) Disegna (Matita)
|
||||
Place Image Inserisci immagine
|
||||
Remove Background Rimuovi sfondo
|
||||
Background Sfondo
|
||||
Edge Color Colore del bordo
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -242,6 +242,8 @@ digits Malayalam マラヤーラム数字
|
||||
Crop Image 画像の切り抜き
|
||||
Image Tools 画像ツール
|
||||
Remove Background… 背景を削除…
|
||||
Draw (Pencil) 描画 (鉛筆)
|
||||
Place Image 画像を配置
|
||||
Remove Background 背景を削除
|
||||
Background 背景
|
||||
Edge Color 端の色
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -166,6 +166,8 @@
|
||||
Crop Image გამოსახულების ჩამოჭრა
|
||||
Image Tools გამოსახულების ხელსაწყოები
|
||||
Remove Background… ფონის მოშორება…
|
||||
Draw (Pencil) ხატვა (ფანქარი)
|
||||
Place Image გამოსახულების განთავსება
|
||||
Remove Background ფონის მოშორება
|
||||
Background ფონი
|
||||
Edge Color კიდის ფერი
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -235,6 +235,8 @@ digits Malayalam 말라얄람어
|
||||
Crop Image 이미지 자르기
|
||||
Image Tools 이미지 도구
|
||||
Remove Background… 배경 제거…
|
||||
Draw (Pencil) 그리기(연필)
|
||||
Place Image 이미지 가져오기
|
||||
Remove Background 배경 제거
|
||||
Background 배경
|
||||
Edge Color 가장자리 색상
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -712,6 +712,8 @@
|
||||
Crop Image Afbeelding bijsnijden
|
||||
Image Tools Afbeeldingshulpmiddelen
|
||||
Remove Background… Achtergrond verwijderen…
|
||||
Draw (Pencil) Tekenen (Potlood)
|
||||
Place Image Afbeelding plaatsen
|
||||
Remove Background Achtergrond verwijderen
|
||||
Background Achtergrond
|
||||
Edge Color Randkleur
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -171,6 +171,8 @@
|
||||
Crop Image Kadruj obraz
|
||||
Image Tools Narzędzia obrazu
|
||||
Remove Background… Usuń tło…
|
||||
Draw (Pencil) Rysuj (ołówek)
|
||||
Place Image Umieść obraz
|
||||
Remove Background Usuń tło
|
||||
Background Tło
|
||||
Edge Color Kolor krawędzi
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -631,6 +631,8 @@ antiAlias Sharp Nítido
|
||||
Crop Image Recortar Imagem
|
||||
Image Tools Ferramentas de imagem
|
||||
Remove Background… Remover Fundo…
|
||||
Draw (Pencil) Desenhar (Lápis)
|
||||
Place Image Colocar Imagem
|
||||
Remove Background Remover Fundo
|
||||
Background Fundo
|
||||
Edge Color Cor da Borda
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -703,6 +703,8 @@ font-technology Variable Вариативные
|
||||
Crop Image Обрезать изображение
|
||||
Image Tools Инструменты изображения
|
||||
Remove Background… Удалить фон…
|
||||
Draw (Pencil) Рисовать (Карандаш)
|
||||
Place Image Поместить изображение
|
||||
Remove Background Удалить фон
|
||||
Background Фон
|
||||
Edge Color Цвет края
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -693,6 +693,8 @@ font-technology Variable Variabla
|
||||
Crop Image Beskär bild
|
||||
Image Tools Bildverktyg
|
||||
Remove Background… Ta bort bakgrund…
|
||||
Draw (Pencil) Rita (blyertspenna)
|
||||
Place Image Placera bild
|
||||
Remove Background Ta bort bakgrund
|
||||
Background Bakgrund
|
||||
Edge Color Kantfärg
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -685,6 +685,8 @@ font-technology Variable Değişken
|
||||
Crop Image Resmi Kırp
|
||||
Image Tools Resim Araçları
|
||||
Remove Background… Arka Planı Kaldır…
|
||||
Draw (Pencil) Çiz (Kurşun Kalem)
|
||||
Place Image Resim Yerleştir
|
||||
Remove Background Arka Planı Kaldır
|
||||
Background Arka Plan
|
||||
Edge Color Kenar Rengi
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -699,6 +699,8 @@ font-technology Variable Варіативні
|
||||
Crop Image Обрізати зображення
|
||||
Image Tools Інструменти зображення
|
||||
Remove Background… Видалити фон…
|
||||
Draw (Pencil) Малювати (Олівець)
|
||||
Place Image Помістити зображення
|
||||
Remove Background Видалити фон
|
||||
Background Фон
|
||||
Edge Color Колір краю
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -806,6 +806,8 @@ font-technology Variable Biến thiên
|
||||
Crop Image Cắt xén ảnh
|
||||
Image Tools Công cụ hình ảnh
|
||||
Remove Background… Xóa nền…
|
||||
Draw (Pencil) Vẽ (Bút chì)
|
||||
Place Image Đặt hình ảnh
|
||||
Remove Background Xóa nền
|
||||
Background Nền
|
||||
Edge Color Màu cạnh
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 204 and column 5.
|
@@ -650,6 +650,8 @@ antiAlias Sharp 锐利
|
||||
Crop Image 裁剪图像
|
||||
Image Tools 图像工具
|
||||
Remove Background… 移除背景…
|
||||
Draw (Pencil) 绘制 (铅笔)
|
||||
Place Image 置入图像
|
||||
Remove Background 移除背景
|
||||
Background 背景
|
||||
Edge Color 边缘颜色
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -667,6 +667,8 @@ font-technology Variable 可變
|
||||
Crop Image 裁切影像
|
||||
Image Tools 影像工具
|
||||
Remove Background… 移除背景…
|
||||
Draw (Pencil) 繪製 (鉛筆)
|
||||
Place Image 置入影像
|
||||
Remove Background 移除背景
|
||||
Background 背景
|
||||
Edge Color 邊緣顏色
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -536,6 +536,103 @@ fn the_task_bar_follows_the_active_document() {
|
||||
assert!(!locked(&app, rect), "the button doesn't lock the shape");
|
||||
}
|
||||
|
||||
/// A blank canvas, a new document with a selection tool in use, offers Draw (Pencil) and Place
|
||||
/// Image centered under the active artboard (under the canvas's center when the artboard is out of
|
||||
/// view), with the handle and More Options but none of a selection's actions or its Fill, Stroke,
|
||||
/// Recolor Artwork and Lock. Other tools, artwork in the document and a selection each leave the
|
||||
/// blank canvas actions out; ruler guides do not count as artwork.
|
||||
#[test]
|
||||
fn a_blank_canvas_offers_draw_and_place_image() {
|
||||
let mut app = app();
|
||||
let board = app.session.active().unwrap().doc.artboards[0].rect;
|
||||
// The artboard at 50% in the middle of the window, after the first frame fits it in.
|
||||
bar(&mut app);
|
||||
let view = app.view_mut().unwrap();
|
||||
(view.center, view.zoom) = (board.center(), 0.5);
|
||||
for tool in ["selection", "directSelection", "groupSelection"] {
|
||||
app.run("tool.select", json!({ "tool": tool })).unwrap();
|
||||
let (ctx, texts) = bar_texts(&mut app);
|
||||
assert!(at(&texts, "Draw (Pencil)").x < at(&texts, "Place Image").x, "{tool}: {texts:?}");
|
||||
let shown = canvas::task_bar_rect(&ctx).unwrap();
|
||||
let xf = canvas::Xf::new(app.canvas_rect.unwrap(), app.view().unwrap());
|
||||
let bottom = xf.quad(board).iter().map(|c| c.y).fold(f32::NEG_INFINITY, f32::max);
|
||||
let middle = xf.to_screen(board.center()).x;
|
||||
assert!(shown.top() > bottom && (shown.center().x - middle).abs() < 2.0, "{tool}: {shown:?} centered under {board:?}");
|
||||
assert!(app.canvas_rect.unwrap().contains_rect(shown), "{tool}: {shown:?} on the canvas");
|
||||
}
|
||||
// The artboard out of view: under the canvas's center.
|
||||
app.view_mut().unwrap().center = board.center() + vectorcraft_geom::Vec2::new(5000.0, 5000.0);
|
||||
let (ctx, _) = bar(&mut app);
|
||||
let (shown, middle) = (canvas::task_bar_rect(&ctx).unwrap(), app.canvas_rect.unwrap().center());
|
||||
assert!((shown.center().x - middle.x).abs() < 2.0 && shown.top() > middle.y && shown.top() < middle.y + 60.0, "{shown:?} under {middle:?}");
|
||||
app.view_mut().unwrap().center = board.center();
|
||||
|
||||
let tree = crate::widgets::accessibility_tests::tree(|ui| canvas::show(&mut app, ui));
|
||||
for label in ["Draw (Pencil)", "Place Image", "More Options"] {
|
||||
assert_eq!(crate::widgets::accessibility_tests::named(&tree, label).role(), egui::accesskit::Role::Button, "{label}");
|
||||
}
|
||||
let named = |label: &str| tree.iter().any(|n| n.label().is_some_and(|l| l.starts_with(label)));
|
||||
for label in ["Fill", "Stroke", "Recolor Artwork", "Lock", "Duplicate"] {
|
||||
assert!(!named(label), "{label} is left out");
|
||||
}
|
||||
|
||||
for tool in ["pen", "rectangle", "type", "artboard"] {
|
||||
app.run("tool.select", json!({ "tool": tool })).unwrap();
|
||||
let (_, texts) = bar_texts(&mut app);
|
||||
assert!(!has(&texts, "Draw (Pencil)") && !has(&texts, "Place Image"), "{tool}: {texts:?}");
|
||||
}
|
||||
|
||||
app.run("tool.select", json!({"tool": "selection"})).unwrap();
|
||||
let rect = id(app.run("shape.rectangle", json!({"x": 40, "y": 40, "width": 80, "height": 60})).unwrap());
|
||||
select(&mut app, &[rect]);
|
||||
let (_, texts) = bar_texts(&mut app);
|
||||
assert!(has(&texts, "Duplicate") && !has(&texts, "Draw (Pencil)"), "{texts:?}");
|
||||
select(&mut app, &[]);
|
||||
let (ctx, _) = bar(&mut app);
|
||||
assert!(canvas::task_bar_rect(&ctx).is_none(), "artwork with nothing selected: no bar");
|
||||
select(&mut app, &[rect]);
|
||||
app.run("edit.clear", json!({})).unwrap();
|
||||
app.run("guide.add", json!({"pos": 50})).unwrap();
|
||||
assert!(has(&bar_texts(&mut app).1, "Draw (Pencil)"), "a ruler guide is not artwork");
|
||||
}
|
||||
|
||||
/// Draw (Pencil) switches to the Pencil tool. Place Image picks files for the Place dialog;
|
||||
/// canceling the pick leaves the document as it was.
|
||||
#[test]
|
||||
fn the_blank_canvas_bar_draws_with_the_pencil_and_places_an_image() {
|
||||
let mut app = app();
|
||||
app.run("tool.select", json!({"tool": "selection"})).unwrap();
|
||||
click(&mut app, "Draw (Pencil)");
|
||||
assert_eq!(app.session.tool_id(), "pencil");
|
||||
|
||||
app.run("tool.select", json!({"tool": "selection"})).unwrap();
|
||||
app.services.pick_open = Some(Box::new(|_: &crate::FilePick| None));
|
||||
click(&mut app, "Place Image");
|
||||
assert!(app.ui.dialog.is_none(), "canceled: no Place dialog");
|
||||
assert!(app.session.active().unwrap().doc.layers.iter().all(|l| l.children().is_none_or(|c| c.is_empty())), "nothing placed");
|
||||
|
||||
let path = std::env::temp_dir().join("vectorcraft-task-bar-place.png").to_string_lossy().into_owned();
|
||||
let picked = path.clone();
|
||||
app.services.pick_open = Some(Box::new(move |_: &crate::FilePick| Some(picked.clone())));
|
||||
click(&mut app, "Place Image");
|
||||
let d = app.ui.dialog.take().expect("the Place dialog");
|
||||
assert_eq!((d.kind.as_str(), &d.fields["files"]), (crate::dialogs::place::KIND, &json!([{ "path": path }])));
|
||||
}
|
||||
|
||||
/// On a canvas too narrow for one row, the blank canvas bar's actions wrap onto a second row and the
|
||||
/// bar stays whole on the canvas.
|
||||
#[test]
|
||||
fn the_blank_canvas_bar_wraps_on_a_narrow_canvas() {
|
||||
let mut app = app();
|
||||
app.run("tool.select", json!({"tool": "selection"})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let (texts, r, canvas) = bar_texts_on_screen(&mut app, &ctx, vec2(240.0, 400.0), 3);
|
||||
assert!(canvas.contains_rect(r), "{r:?} on {canvas:?}");
|
||||
let (draw, place) = (at(&texts, "Draw (Pencil)"), at(&texts, "Place Image"));
|
||||
assert!(place.y > draw.y + 20.0, "Place Image wraps under Draw (Pencil): {draw:?} {place:?}");
|
||||
}
|
||||
|
||||
/// The Type tools whose bar shows the font and Fill controls.
|
||||
const TYPE_TOOLS: [&str; 6] = ["type", "areaType", "typeOnPath", "verticalType", "verticalAreaType", "verticalTypeOnPath"];
|
||||
|
||||
|
||||
@@ -865,6 +865,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- A click on another object moves the contextual task bar under it without hiding it for the press; it gives way only to a drag (#4681).
|
||||
- With one image selected, the contextual task bar offers Image Trace, which traces the image at once with the Default preset (the Image Trace panel is left as it was), and Crop Image; with an Image Trace object it offers Expand, which keeps only the traced paths. This follows Illustrator's bar: for a selected image it includes Image Trace, Retype and Crop Image, and traced artwork can be expanded from it ([Contextual Task Bar announcement](https://community.adobe.com/announcements-651/contextual-task-bar-in-illustrator-2025-quick-actions-when-you-need-them-1546580)). Offset Path and Simplify, which don't apply to an image, aren't offered for one. Not done: Retype, which the app doesn't have.
|
||||
- With the Artboard tool, the contextual task bar sits under the selected artboards and offers Resize (Artboard Options for the active artboard), Duplicate (each selected artboard, in one undo step, the copies then selected), Rearrange All (with two or more artboards) and Export (Export for Screens with the selected artboards checked). This follows Illustrator's bar: while the Artboard tool is in use, it has options for resizing, duplicating and exporting artboards (the [Contextual Task Bar announcement](https://community.adobe.com/questions-652/contextual-task-bar-in-illustrator-2025-quick-actions-when-you-need-them-1546580); Rearrange and Export on the bar: [Managing Artboards in Illustrator](https://creativepro.com/managing-artboards-in-illustrator/)).
|
||||
- On a blank canvas the contextual task bar offers Draw (Pencil), which switches to the Pencil tool, and Place Image, which picks files for the Place dialog, as the help page lists for a new document (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html>). VectorCraft's own rules: the bar shows them while a selection tool is in use in a document with no artwork (layers and guides only), sits under the active artboard (under the canvas's center when the artboard is out of view), and leaves out the Fill, Stroke, Recolor Artwork and Lock controls. Not done: Generate Vectors. Evidence: `a_blank_canvas_offers_draw_and_place_image`, `the_blank_canvas_bar_draws_with_the_pencil_and_places_an_image` and `the_blank_canvas_bar_wraps_on_a_narrow_canvas` in `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
- The contextual task bar offers more next steps by selection (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html>): an open path Join and Edit Path (the Direct Selection tool), a closed path Edit Path, a compound path Edit Path and Release Compound Path, a clipping group Edit Clipping Path and Release Clipping Mask instead of Ungroup and Isolate, an image selected with vector art Make Clipping Mask instead of Unite, point or area type Convert To Area Type or Convert To Point Type beside Create Outlines, and type on a path, for which the overview names an item to add an effect and rearrange the text, Type on a Path Options (`type.pathOptions`; its options: <https://helpx.adobe.com/illustrator/using/creating-type-path.html>) beside Create Outlines. Evidence: `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
- While a Type tool (Type, Area Type, Type on a Path and their vertical versions) adds or edits type, the contextual task bar shows the font family menu, the font style menu, the Font Size combo and the Fill chip (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/contextual-task-bar-overview.html>); the Touch Type tool shows no bar, as the same page describes. Type selected with a selection tool shows the same three font controls beside its Create Outlines, conversion and Type on a Path items (<https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/font-options-overview.html>). The controls act as the Character panel's do: on the characters a Type tool selects, else on every selected type object, with the size left blank where the sizes differ. VectorCraft's own rules: a Type tool's bar leaves out the object actions, the Stroke chip, Recolor Artwork and Lock; a Type tool shows no bar before it adds type or with other art selected; type selected with other art shows no font controls; the font controls go on a second row when one row would be wider than the canvas, and narrow to fit a canvas narrower than they are; while a Type tool edits type, the Fill chip shows the edited characters' fill ("?" where it differs). Evidence: `the_type_tools_show_font_and_fill_controls`, `the_type_tools_show_no_bar_without_type`, `selected_type_shows_font_controls_beside_its_actions`, `the_task_bars_font_size_sets_what_the_character_panel_would`, `the_type_tools_fill_chip_activates_the_fill`, `the_type_tools_bar_is_named_and_stays_on_the_canvas`, `selected_types_font_controls_take_a_second_row_on_a_narrow_canvas` and `the_type_tools_fill_chip_shows_the_edited_characters_fill` in `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
- The help page describes the contextual task bar as one horizontal row (<https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/workspace-overview.html>) and gives no rule for a canvas narrower than that row. VectorCraft's own rule: the bar stays whole on the canvas. When its actions don't fit in one row, they wrap, in order, onto rows under the row with the handle, the chips and More Options; an action wider than any row, or one that would need a row past the canvas's height, is listed in More Options instead; when the chips don't fit beside the handle and More Options, they take rows after the actions; with no row to spare for the font controls, the bar leaves them out; a canvas too small for the handle and More Options shows no bar. Evidence: `a_task_bars_actions_wrap_on_a_narrow_canvas` and `a_task_bar_action_wider_than_the_canvas_goes_in_more_options` in `crates/ui-egui/src/tests/taskbar.rs`.
|
||||
|
||||
Reference in New Issue
Block a user