Both tools join the Marquee flyout (no key, outside the M / Shift+M cycle, as in Photoshop). A click selects the one-pixel row (column) under the pointer across the whole canvas; a press-drag moves the line until the release. The selection goes through select.rect, so Shift adds, Alt subtracts, Shift+Alt intersects and the options-bar modes apply; Feather applies, Anti-alias and Style/Width/Height are greyed. Selection-mode cursor badges, the selection right-click menu and snapping cover them. Original row/column glyphs with an ATTRIBUTION.md row; tool names in all catalogs; README tool list and the G6 / ui-parity rows updated. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
parent
9d3ba499ad
commit
325c5b3194
|
|
@ -20,9 +20,10 @@ next to them.
|
|||
| `crates/ui-egui/src/i18n/uk.tsv` | Ukrainian UI translations | PhotoCraft contributors | Original translations of PhotoCraft's English labels | MIT OR Apache-2.0, [`LICENSE-translations.txt`](crates/ui-egui/src/i18n/LICENSE-translations.txt) |
|
||||
| `assets/fonts/Inter-Regular.ttf`, `Inter-Medium.ttf`, `Inter-SemiBold.ttf` | Inter 4.001 (UI font) | The Inter Project Authors (Rasmus Andersson) | <https://github.com/rsms/inter> | SIL OFL 1.1, [`assets/fonts/OFL-Inter.txt`](assets/fonts/OFL-Inter.txt) |
|
||||
| `assets/fonts/JetBrainsMono-Regular.ttf` | JetBrains Mono 2.305 (numeric font) | The JetBrains Mono Project Authors | <https://github.com/JetBrains/JetBrainsMono> | SIL OFL 1.1, [`assets/fonts/OFL-JetBrainsMono.txt`](assets/fonts/OFL-JetBrainsMono.txt) |
|
||||
| `assets/icons/*.svg` except `slice-knife.svg`, `clip-below.svg`, `clip-release.svg`, `layer-mask.svg`, `adjustment-layer.svg`, `eraser-background.svg`, `eraser-magic.svg`, `lasso-magnetic.svg`, `direct-select.svg`, `bandage-sparkle.svg`, `painting-symmetry.svg` and `symmetry-*.svg` (110 files) | Lucide icons | Lucide Icons and Contributors | <https://github.com/lucide-icons/lucide> (`icons/<name>.svg`; `align-*` are now named `text-align-*` upstream) | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) |
|
||||
| `assets/icons/*.svg` except `slice-knife.svg`, `clip-below.svg`, `clip-release.svg`, `layer-mask.svg`, `adjustment-layer.svg`, `eraser-background.svg`, `eraser-magic.svg`, `lasso-magnetic.svg`, `direct-select.svg`, `bandage-sparkle.svg`, `painting-symmetry.svg`, `symmetry-*.svg` and `marquee-{row,column}.svg` (110 files) | Lucide icons | Lucide Icons and Contributors | <https://github.com/lucide-icons/lucide> (`icons/<name>.svg`; `align-*` are now named `text-align-*` upstream) | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) |
|
||||
| `assets/icons/{check,chevron-down,chevron-right,chevron-up,chevrons-left,chevrons-right,circle,clock,compass,info,link,link-2,lock,minus,monitor,moon,move,navigation,plus,search,square,trash,triangle,type,x,zoom-in}.svg` | Lucide icons derived from Feather (subset of the row above) | Cole Bemis (Feather), Lucide Contributors | <https://github.com/feathericons/feather> via Lucide | MIT (Feather) and ISC (Lucide), [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) |
|
||||
| `assets/icons/slice-knife.svg` | Slice tool glyph | PhotoCraft contributors | Original work | MIT OR Apache-2.0 |
|
||||
| `assets/icons/marquee-row.svg`, `assets/icons/marquee-column.svg` | Single Row and Single Column Marquee tool glyphs: a dashed row (column) between two edge bars, drawn on Lucide's 24 px grid and stroke | PhotoCraft contributors | Original work | MIT OR Apache-2.0 |
|
||||
| `assets/icons/clip-below.svg`, `assets/icons/clip-release.svg` | Clipping-mask cursors (⌥ over the line between two layers): a hooked arrow onto the layer below; the same with a small "no" badge to release | PhotoCraft contributors | Original work | MIT OR Apache-2.0 |
|
||||
| `assets/icons/layer-mask.svg`, `assets/icons/adjustment-layer.svg` | Layers panel footer glyphs: Add a mask (a frame around a solid disc) and New Fill or Adjustment Layer (a circle, one half solid), drawn on Lucide's 24 px grid and stroke | PhotoCraft contributors | Original work | MIT OR Apache-2.0 |
|
||||
| `assets/icons/eraser-background.svg`, `assets/icons/eraser-magic.svg` | Background Eraser and Magic Eraser tool glyphs: Lucide `eraser` plus added marks | Lucide Icons and Contributors; marks by PhotoCraft contributors | Derived from <https://github.com/lucide-icons/lucide> `icons/eraser.svg` | ISC, [`assets/icons/LICENSE-lucide.txt`](assets/icons/LICENSE-lucide.txt) |
|
||||
|
|
|
|||
|
|
@ -178,8 +178,8 @@ Every screenshot here is the real app at work on public-domain art, rendered off
|
|||
<table>
|
||||
<tr>
|
||||
<td width="33%" valign="top">
|
||||
<h4>🧰 53 tools</h4>
|
||||
Move · Rectangular and Elliptical Marquee · Lasso · Polygonal Lasso · Magnetic Lasso · Object Selection · Quick Selection · Magic Wand · Crop · Slice · Slice Select · Eyedropper · Ruler · Note · Count · Remove · Spot Healing Brush · Healing Brush · Patch · Content-Aware Move · Red Eye · Brush · Pencil · Mixer Brush · Clone Stamp · Pattern Stamp · History Brush · Eraser · Background Eraser · Magic Eraser · Gradient · Paint Bucket · Blur · Sharpen · Smudge · Dodge · Burn · Sponge · Pen · Horizontal and Vertical Type · Path Selection · Direct Selection · Rectangle · Ellipse · Triangle · Polygon · Line · Custom Shape · Hand · Rotate View · Zoom
|
||||
<h4>🧰 55 tools</h4>
|
||||
Move · Rectangular and Elliptical Marquee · Single Row Marquee · Single Column Marquee · Lasso · Polygonal Lasso · Magnetic Lasso · Object Selection · Quick Selection · Magic Wand · Crop · Slice · Slice Select · Eyedropper · Ruler · Note · Count · Remove · Spot Healing Brush · Healing Brush · Patch · Content-Aware Move · Red Eye · Brush · Pencil · Mixer Brush · Clone Stamp · Pattern Stamp · History Brush · Eraser · Background Eraser · Magic Eraser · Gradient · Paint Bucket · Blur · Sharpen · Smudge · Dodge · Burn · Sponge · Pen · Horizontal and Vertical Type · Path Selection · Direct Selection · Rectangle · Ellipse · Triangle · Polygon · Line · Custom Shape · Hand · Rotate View · Zoom
|
||||
</td>
|
||||
<td width="33%" valign="top">
|
||||
<h4>🖌️ A real brush engine</h4>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<!-- PhotoCraft's own Single Column Marquee glyph: a dashed column from edge to edge. -->
|
||||
<path d="M8 3h8" />
|
||||
<path d="M8 21h8" />
|
||||
<path d="M12 6.5v1" />
|
||||
<path d="M12 11.5v1" />
|
||||
<path d="M12 16.5v1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 422 B |
|
|
@ -0,0 +1,18 @@
|
|||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<!-- PhotoCraft's own Single Row Marquee glyph: a dashed row from edge to edge. -->
|
||||
<path d="M3 8v8" />
|
||||
<path d="M21 8v8" />
|
||||
<path d="M6.5 12h1" />
|
||||
<path d="M11.5 12h1" />
|
||||
<path d="M16.5 12h1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 416 B |
|
|
@ -217,6 +217,35 @@ pub fn marquee_px(a: [f64; 2], b: [f64; 2]) -> [f64; 4] {
|
|||
[a[0].min(b[0]).floor(), a[1].min(b[1]).floor(), a[0].max(b[0]).ceil(), a[1].max(b[1]).ceil()]
|
||||
}
|
||||
|
||||
/// The one-pixel line `[x0, y0, x1, y1]` a Single Row (Single Column) Marquee at `p` selects: the
|
||||
/// pixel row (column) under `p`, kept on the canvas, across the whole `size`. `None` for other
|
||||
/// tools, an empty canvas or a point that is not a number.
|
||||
pub(crate) fn single_line_px(tool: Tool, size: [u32; 2], p: [f64; 2]) -> Option<[f64; 4]> {
|
||||
let [w, h] = size.map(f64::from);
|
||||
if w < 1.0 || h < 1.0 || !p[0].is_finite() || !p[1].is_finite() {
|
||||
return None;
|
||||
}
|
||||
match tool {
|
||||
Tool::SingleRowMarquee => {
|
||||
let y = p[1].floor().clamp(0.0, h - 1.0);
|
||||
Some([0.0, y, w, y + 1.0])
|
||||
}
|
||||
Tool::SingleColumnMarquee => {
|
||||
let x = p[0].floor().clamp(0.0, w - 1.0);
|
||||
Some([x, 0.0, x + 1.0, h])
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The line a Single Row / Single Column Marquee gesture `d` selects so far: it follows the
|
||||
/// pointer until the release.
|
||||
fn single_line_drag_px(app: &PhotocraftApp, d: &Drag) -> Option<[f64; 4]> {
|
||||
let st = app.session.active()?;
|
||||
let last = d.points.last().map_or(d.start, |p| [p[0], p[1]]);
|
||||
single_line_px(d.tool, [st.doc.size.width, st.doc.size.height], last)
|
||||
}
|
||||
|
||||
/// The marching ants of a marquee drag: its rectangle, or the ellipse inscribed in it, built in
|
||||
/// document space and mapped point by point through the view, so the hinting lands where the
|
||||
/// release commits the selection.
|
||||
|
|
@ -2732,7 +2761,7 @@ pub fn canvas_view(app: &mut PhotocraftApp, ui: &mut egui::Ui, idx: usize, rect:
|
|||
}
|
||||
// Capture intent at the press, before egui's drag threshold: Type transforms keep
|
||||
// Command, and marquee add/subtract must not become a live Shift/Alt constraint.
|
||||
let capture_press = tool.is_type() || matches!(tool, Tool::RectMarquee | Tool::EllipseMarquee);
|
||||
let capture_press = tool.is_type() || matches!(tool, Tool::RectMarquee | Tool::EllipseMarquee | Tool::SingleRowMarquee | Tool::SingleColumnMarquee);
|
||||
let tool_press = egui::Id::new(("tool-pointer-press-modifiers", idx));
|
||||
if capture_press
|
||||
&& let Some((p, press_mods)) = ui.input(|i| {
|
||||
|
|
@ -3743,6 +3772,13 @@ fn draw_drag_preview(app: &mut PhotocraftApp, painter: &egui::Painter, xf: &View
|
|||
trail.draw(painter, doc_rect, xf.flip, col);
|
||||
}
|
||||
t if crate::vector_ui::is_shape_tool(t) => crate::vector_ui::draw_shape_preview(app, painter, xf, t, d.start, last, d.live),
|
||||
Tool::SingleRowMarquee | Tool::SingleColumnMarquee => {
|
||||
// Mapped corner by corner like the other marquees, so a rotated view shows the line
|
||||
// where the release commits it (#2512).
|
||||
if let Some([x0, y0, x1, y1]) = single_line_drag_px(app, d) {
|
||||
crate::tool_feedback::draw_ants(painter, &marquee_ants(xf, d.tool, [x0, y0], [x1, y1]), true);
|
||||
}
|
||||
}
|
||||
// Nothing selected yet: no outline, as the release would deselect.
|
||||
Tool::RectMarquee | Tool::EllipseMarquee if marquee.is_none() => {}
|
||||
Tool::RectMarquee | Tool::EllipseMarquee | Tool::ObjectSelection => {
|
||||
|
|
@ -4444,6 +4480,14 @@ pub(crate) fn finish_gesture(app: &mut PhotocraftApp, d: Drag) {
|
|||
let (aa, feather) = (app.ui.tool_options.anti_alias, app.ui.tool_options.feather);
|
||||
let _ = app.run("select.rect", json!({"x": x0, "y": y0, "width": x1 - x0, "height": y1 - y0, "mode": mode, "ellipse": d.tool == Tool::EllipseMarquee, "antiAlias": aa, "feather": feather}));
|
||||
}
|
||||
// A click (or the end of a drag) selects the line under the pointer, never deselects.
|
||||
Tool::SingleRowMarquee | Tool::SingleColumnMarquee => {
|
||||
let Some([x0, y0, x1, y1]) = single_line_drag_px(app, &d) else { return };
|
||||
let mode = selection_mode(app, d.modifiers);
|
||||
let feather = app.ui.tool_options.feather;
|
||||
let _ =
|
||||
app.run("select.rect", json!({"x": x0, "y": y0, "width": x1 - x0, "height": y1 - y0, "mode": mode, "antiAlias": false, "feather": feather}));
|
||||
}
|
||||
Tool::Patch if crate::retouch_ui::patch_drags_selection(app, d.start, d.modifiers) => crate::retouch_ui::finish_patch(app, d.start, [end[0], end[1]]),
|
||||
Tool::ContentAwareMove if crate::retouch_ui::patch_drags_selection(app, d.start, d.modifiers) => {
|
||||
crate::retouch_ui::finish_content_aware_move(app, d.start, [end[0], end[1]])
|
||||
|
|
|
|||
|
|
@ -135,7 +135,16 @@ pub const PEN_MENU: &[Row] = &[
|
|||
pub fn applies(tool: Tool) -> bool {
|
||||
matches!(
|
||||
tool,
|
||||
Tool::RectMarquee | Tool::EllipseMarquee | Tool::Lasso | Tool::PolygonLasso | Tool::MagneticLasso | Tool::MagicWand | Tool::ObjectSelection | Tool::Pen
|
||||
Tool::RectMarquee
|
||||
| Tool::EllipseMarquee
|
||||
| Tool::SingleRowMarquee
|
||||
| Tool::SingleColumnMarquee
|
||||
| Tool::Lasso
|
||||
| Tool::PolygonLasso
|
||||
| Tool::MagneticLasso
|
||||
| Tool::MagicWand
|
||||
| Tool::ObjectSelection
|
||||
| Tool::Pen
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1605,6 +1605,8 @@
|
|||
Efficiency: 100% Efektivita: 100 %
|
||||
Ellipse Tool Nástroj elipsa
|
||||
Elliptical Marquee Tool Nástroj eliptický výběr
|
||||
Single Row Marquee Tool Nástroj výběr jednoho řádku
|
||||
Single Column Marquee Tool Nástroj výběr jednoho sloupce
|
||||
Emboss Reliéf
|
||||
Eraser Guma
|
||||
Eraser Tool Nástroj guma
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1580,6 +1580,8 @@
|
|||
Efficiency: 100% Effizienz: 100 %
|
||||
Ellipse Tool Ellipsen-Werkzeug
|
||||
Elliptical Marquee Tool Ellipsenauswahl-Werkzeug
|
||||
Single Row Marquee Tool Auswahlwerkzeug (einzelne Zeile)
|
||||
Single Column Marquee Tool Auswahlwerkzeug (einzelne Spalte)
|
||||
Emboss Relief
|
||||
Eraser Radiergummi
|
||||
Eraser Tool Radiergummi-Werkzeug
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -3223,6 +3223,8 @@ cameraRaw Yellow Κίτρινο
|
|||
Dodge Tool Φωτισμός (Dodge Tool)
|
||||
Ellipse Tool Έλλειψη (Ellipse Tool)
|
||||
Elliptical Marquee Tool Ελλειπτική επιλογή (Elliptical Marquee Tool)
|
||||
Single Row Marquee Tool Επιλογή μίας γραμμής (Single Row Marquee Tool)
|
||||
Single Column Marquee Tool Επιλογή μίας στήλης (Single Column Marquee Tool)
|
||||
Eraser Tool Γόμα (Eraser Tool)
|
||||
Eyedropper Tool Σταγονόμετρο (Eyedropper Tool)
|
||||
Gradient Tool Διαβάθμιση (Gradient Tool)
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 5.
|
|
|
@ -1588,6 +1588,8 @@
|
|||
Efficiency: 100% Eficiencia: 100%
|
||||
Ellipse Tool Herramienta Elipse
|
||||
Elliptical Marquee Tool Herramienta Marco elíptico
|
||||
Single Row Marquee Tool Herramienta Marco de fila única
|
||||
Single Column Marquee Tool Herramienta Marco de columna única
|
||||
Emboss Relieve
|
||||
Eraser Borrador
|
||||
Eraser Tool Herramienta Borrador
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 4 and column 47.
|
|
|
@ -1566,6 +1566,8 @@
|
|||
Efficiency: 100% Efficacité : 100 %
|
||||
Ellipse Tool Outil Ellipse
|
||||
Elliptical Marquee Tool Outil Sélection elliptique
|
||||
Single Row Marquee Tool Outil Sélection de ligne unique
|
||||
Single Column Marquee Tool Outil Sélection de colonne unique
|
||||
Emboss Relief
|
||||
Eraser Gomme
|
||||
Eraser Tool Outil Gomme
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1560,6 +1560,8 @@
|
|||
Efficiency: 100% Efisiensi: 100%
|
||||
Ellipse Tool Alat Ellipse
|
||||
Elliptical Marquee Tool Alat Elliptical Marquee
|
||||
Single Row Marquee Tool Alat Single Row Marquee
|
||||
Single Column Marquee Tool Alat Single Column Marquee
|
||||
Emboss Emboss
|
||||
Eraser Penghapus
|
||||
Eraser Tool Alat Penghapus
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 4 and column 47.
|
|
|
@ -1586,6 +1586,8 @@
|
|||
Efficiency: 100% Efficienza: 100%
|
||||
Ellipse Tool Strumento Ellisse
|
||||
Elliptical Marquee Tool Strumento Selezione ellittica
|
||||
Single Row Marquee Tool Strumento Selezione singola riga
|
||||
Single Column Marquee Tool Strumento Selezione singola colonna
|
||||
Emboss Rilievo
|
||||
Eraser Gomma
|
||||
Eraser Tool Strumento Gomma
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 14.
|
|
|
@ -1591,6 +1591,8 @@
|
|||
Efficiency: 100% 効率: 100%
|
||||
Ellipse Tool 楕円形ツール
|
||||
Elliptical Marquee Tool 楕円形選択ツール
|
||||
Single Row Marquee Tool 一行選択ツール
|
||||
Single Column Marquee Tool 一列選択ツール
|
||||
Emboss エンボス
|
||||
Eraser 消しゴム
|
||||
Eraser Tool 消しゴムツール
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1559,6 +1559,8 @@
|
|||
Efficiency: 100% 효율: 100%
|
||||
Ellipse Tool 타원 도구
|
||||
Elliptical Marquee Tool 원형 선택 윤곽 도구
|
||||
Single Row Marquee Tool 단일 행 선택 윤곽 도구
|
||||
Single Column Marquee Tool 단일 열 선택 윤곽 도구
|
||||
Emboss 엠보스
|
||||
Eraser 지우개
|
||||
Eraser Tool 지우개 도구
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 10.
|
|
|
@ -1570,6 +1570,8 @@
|
|||
Efficiency: 100% Efficiëntie: 100%
|
||||
Ellipse Tool Ellipsgereedschap
|
||||
Elliptical Marquee Tool Ovaal selectiekader
|
||||
Single Row Marquee Tool Selectiekader enkele rij
|
||||
Single Column Marquee Tool Selectiekader enkele kolom
|
||||
Emboss Reliëf
|
||||
Eraser Gum
|
||||
Eraser Tool Gumgereedschap
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 8 and column 34.
|
|
|
@ -1584,6 +1584,8 @@
|
|||
Efficiency: 100% Wydajność: 100%
|
||||
Ellipse Tool Narzędzie Elipsa
|
||||
Elliptical Marquee Tool Narzędzie Zaznaczenie eliptyczne
|
||||
Single Row Marquee Tool Narzędzie Zaznaczenie pojedynczego wiersza
|
||||
Single Column Marquee Tool Narzędzie Zaznaczenie pojedynczej kolumny
|
||||
Emboss Płaskorzeźba
|
||||
Eraser Gumka
|
||||
Eraser Tool Narzędzie Gumka
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1565,6 +1565,8 @@
|
|||
Efficiency: 100% Eficiência: 100%
|
||||
Ellipse Tool Ferramenta Elipse
|
||||
Elliptical Marquee Tool Ferramenta Letreiro elíptico
|
||||
Single Row Marquee Tool Ferramenta Letreiro de linha única
|
||||
Single Column Marquee Tool Ferramenta Letreiro de coluna única
|
||||
Emboss Entalhe
|
||||
Eraser Borracha
|
||||
Eraser Tool Ferramenta Borracha
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1528,6 +1528,8 @@
|
|||
Could not complete the Free Transform command because the layer is locked. Не удалось выполнить команду «Свободное трансформирование», потому что слой заблокирован.
|
||||
Rectangular Marquee Tool Прямоугольная область
|
||||
Elliptical Marquee Tool Овальная область
|
||||
Single Row Marquee Tool Область (горизонтальная строка)
|
||||
Single Column Marquee Tool Область (вертикальная строка)
|
||||
Brush Tool Кисть
|
||||
Pencil Tool Карандаш
|
||||
Eraser Tool Ластик
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -1510,6 +1510,8 @@
|
|||
Could not complete the Free Transform command because the layer is locked. Не вдалося виконати команду «Вільна трансформація», бо шар заблоковано.
|
||||
Rectangular Marquee Tool Інструмент «Прямокутне виділення»
|
||||
Elliptical Marquee Tool Інструмент «Еліптичне виділення»
|
||||
Single Row Marquee Tool Інструмент «Виділення одного рядка»
|
||||
Single Column Marquee Tool Інструмент «Виділення одного стовпця»
|
||||
Brush Tool Інструмент «Пензель»
|
||||
Pencil Tool Інструмент «Олівець»
|
||||
Eraser Tool Інструмент «Гумка»
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 12.
|
|
|
@ -1600,6 +1600,8 @@
|
|||
Efficiency: 100% 效率:100%
|
||||
Ellipse Tool 椭圆工具
|
||||
Elliptical Marquee Tool 椭圆选框工具
|
||||
Single Row Marquee Tool 单行选框工具
|
||||
Single Column Marquee Tool 单列选框工具
|
||||
Emboss 浮雕
|
||||
Eraser 橡皮擦
|
||||
Eraser Tool 橡皮擦工具
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 14.
|
|
|
@ -1595,6 +1595,8 @@
|
|||
Efficiency: 100% 效率:100%
|
||||
Ellipse Tool 橢圓工具
|
||||
Elliptical Marquee Tool 橢圓選取畫面工具
|
||||
Single Row Marquee Tool 單列選取畫面工具
|
||||
Single Column Marquee Tool 單欄選取畫面工具
|
||||
Emboss 浮雕
|
||||
Eraser 橡皮擦
|
||||
Eraser Tool 橡皮擦工具
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
|
|
@ -64,6 +64,9 @@ pub static ICONS: &[(&str, &[u8])] = &[
|
|||
("lock", include_bytes!("../../../assets/icons/lock.svg")),
|
||||
("lock-open", include_bytes!("../../../assets/icons/lock-open.svg")),
|
||||
("lollipop", include_bytes!("../../../assets/icons/lollipop.svg")),
|
||||
// PhotoCraft originals: the Single Row / Single Column Marquee glyphs.
|
||||
("marquee-column", include_bytes!("../../../assets/icons/marquee-column.svg")),
|
||||
("marquee-row", include_bytes!("../../../assets/icons/marquee-row.svg")),
|
||||
("maximize-2", include_bytes!("../../../assets/icons/maximize-2.svg")),
|
||||
("message-square", include_bytes!("../../../assets/icons/message-square.svg")),
|
||||
("minus", include_bytes!("../../../assets/icons/minus.svg")),
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ pub fn tool_icon(t: Tool) -> &'static str {
|
|||
Tool::Move => "move",
|
||||
Tool::RectMarquee => "square-dashed",
|
||||
Tool::EllipseMarquee => "circle-dashed",
|
||||
Tool::SingleRowMarquee => "marquee-row",
|
||||
Tool::SingleColumnMarquee => "marquee-column",
|
||||
Tool::Brush => "brush",
|
||||
Tool::Pencil => "pencil",
|
||||
Tool::MixerBrush => "palette",
|
||||
|
|
|
|||
|
|
@ -679,6 +679,61 @@ fn selection_cursor_follows_the_modifiers_and_the_floating_piece() {
|
|||
assert_eq!(selection_cursor(&app, Tool::RectMarquee, [30.0, 20.0], none), Some(SelCursor::Outline));
|
||||
}
|
||||
|
||||
/// A click with `tool` at document point `(x, y)`, as the canvas sends it.
|
||||
fn click_with(app: &mut PhotocraftApp, tool: Tool, x: f64, y: f64, m: Modifiers) {
|
||||
use crate::canvas::{ToolEvent, tool_event};
|
||||
app.ui.tool = tool;
|
||||
tool_event(app, ToolEvent::Down { x, y, pressure: 1.0 }, m);
|
||||
tool_event(app, ToolEvent::Up { x, y }, m);
|
||||
}
|
||||
|
||||
/// Single Row / Single Column Marquee (#2837): a click selects one pixel row (column) across the
|
||||
/// whole canvas; ⇧ adds, ⌥ subtracts, as with the other marquees.
|
||||
#[test]
|
||||
fn single_row_and_column_marquee_select_one_pixel_lines() {
|
||||
let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 100})).unwrap();
|
||||
app.ui.extras.snap = false;
|
||||
let bounds = |app: &PhotocraftApp| app.session.active().unwrap().doc.selection.as_ref().map_or(Rect::EMPTY, |s| s.content_bounds());
|
||||
let at = |app: &PhotocraftApp, x: i32, y: i32| app.session.active().unwrap().doc.selection.as_ref().map_or(0.0, |s| s.sample_channel(x, y, 0));
|
||||
|
||||
click_with(&mut app, Tool::SingleRowMarquee, 120.3, 37.6, Modifiers::NONE);
|
||||
assert_eq!(bounds(&app), Rect::new(0, 37, 200, 38));
|
||||
click_with(&mut app, Tool::SingleRowMarquee, 15.0, 60.2, Modifiers::SHIFT);
|
||||
assert_eq!(bounds(&app), Rect::new(0, 37, 200, 61));
|
||||
assert!(at(&app, 5, 37) > 0.99 && at(&app, 199, 60) > 0.99 && at(&app, 100, 50) < 0.01, "two rows, nothing between");
|
||||
|
||||
click_with(&mut app, Tool::SingleColumnMarquee, 42.9, 80.0, Modifiers::NONE);
|
||||
assert_eq!(bounds(&app), Rect::new(42, 0, 43, 100));
|
||||
click_with(&mut app, Tool::SingleColumnMarquee, 150.5, 3.0, Modifiers::SHIFT);
|
||||
assert_eq!(bounds(&app), Rect::new(42, 0, 151, 100));
|
||||
click_with(&mut app, Tool::SingleColumnMarquee, 42.0, 10.0, Modifiers::ALT);
|
||||
assert_eq!(bounds(&app), Rect::new(150, 0, 151, 100), "⌥ subtracts the column");
|
||||
}
|
||||
|
||||
/// The two single-line marquees sit in the Marquee flyout but M (⇧M) cycles only the
|
||||
/// Rectangular and Elliptical Marquee, as in Photoshop; automation picks them by name.
|
||||
#[test]
|
||||
fn m_cycles_only_the_rectangular_and_elliptical_marquee() {
|
||||
let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());
|
||||
let ctx = egui::Context::default();
|
||||
app.ui.tool = Tool::SingleRowMarquee;
|
||||
let mut seen = Vec::new();
|
||||
for _ in 0..4 {
|
||||
let raw = egui::RawInput {
|
||||
events: vec![egui::Event::Key { key: egui::Key::M, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::NONE }],
|
||||
..Default::default()
|
||||
};
|
||||
ctx.begin_pass(raw);
|
||||
crate::shortcuts::handle(&mut app, &ctx);
|
||||
ctx.end_pass().textures_delta.clear();
|
||||
seen.push(app.ui.tool);
|
||||
}
|
||||
assert_eq!(seen, [Tool::RectMarquee, Tool::EllipseMarquee, Tool::RectMarquee, Tool::EllipseMarquee]);
|
||||
assert_eq!(Tool::from_name("SingleRowMarquee"), Some(Tool::SingleRowMarquee));
|
||||
assert_eq!(Tool::from_name("Single Column Marquee Tool"), Some(Tool::SingleColumnMarquee));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn size_readout_follows_the_ruler_unit() {
|
||||
use photocraft_engine::prefs::{Unit, UnitsAndRulers};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use crate::{PhotocraftApp, icons, widgets};
|
|||
const TOOL_SECTIONS: &[&[&[Tool]]] = &[
|
||||
&[&[Tool::Move]],
|
||||
&[
|
||||
&[Tool::RectMarquee, Tool::EllipseMarquee],
|
||||
&[Tool::RectMarquee, Tool::EllipseMarquee, Tool::SingleRowMarquee, Tool::SingleColumnMarquee],
|
||||
&[Tool::Lasso, Tool::PolygonLasso, Tool::MagneticLasso],
|
||||
&[Tool::ObjectSelection, Tool::QuickSelection, Tool::MagicWand],
|
||||
&[Tool::Crop, Tool::Slice, Tool::SliceSelect],
|
||||
|
|
@ -936,7 +936,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
|
|||
widgets::vline(ui, 22.0);
|
||||
widgets::checkbox(ui, &mut b.mixer.sample_all_layers, tl!("Sample All Layers"));
|
||||
}
|
||||
Tool::RectMarquee | Tool::EllipseMarquee if t.pro => {
|
||||
Tool::RectMarquee | Tool::EllipseMarquee | Tool::SingleRowMarquee | Tool::SingleColumnMarquee if t.pro => {
|
||||
ui.spacing_mut().item_spacing.x = 2.0;
|
||||
for (i, (icon, tip)) in [
|
||||
("square", tl!("New selection").to_string()),
|
||||
|
|
@ -962,16 +962,18 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
|
|||
// Photoshop greys Anti-alias for the Rectangular Marquee (its edges are always hard).
|
||||
ui.add_enabled_ui(app.ui.tool == Tool::EllipseMarquee, |ui| widgets::checkbox(ui, &mut o.anti_alias, tl!("Anti-alias")));
|
||||
widgets::vline(ui, 22.0);
|
||||
opt_label(ui, tl!("Style"));
|
||||
// A single row or column has no style or size: Photoshop greys them.
|
||||
let sized = matches!(app.ui.tool, Tool::RectMarquee | Tool::EllipseMarquee);
|
||||
ui.add_enabled_ui(sized, |ui| opt_label(ui, tl!("Style")));
|
||||
let styles = [
|
||||
("normal".to_string(), tl!("Normal")),
|
||||
("fixedRatio".to_string(), tl!("Fixed Ratio")),
|
||||
("fixedSize".to_string(), tl!("Fixed Size")),
|
||||
];
|
||||
if widgets::dropdown(ui, "marquee-style", &mut o.marquee_style, &styles, 96.0) {
|
||||
if ui.add_enabled_ui(sized, |ui| widgets::dropdown(ui, "marquee-style", &mut o.marquee_style, &styles, 96.0)).inner {
|
||||
(o.marquee_width, o.marquee_height) = if o.marquee_style == "fixedSize" { (64.0, 64.0) } else { (1.0, 1.0) };
|
||||
}
|
||||
let fixed = o.marquee_style != "normal";
|
||||
let fixed = sized && o.marquee_style != "normal";
|
||||
let (unit, range) = if o.marquee_style == "fixedSize" { ("px", 1.0..=300_000.0) } else { ("", 0.001..=999.0) };
|
||||
ui.add_enabled_ui(fixed, |ui| {
|
||||
opt_label(ui, tl!("Width"));
|
||||
|
|
@ -1210,6 +1212,15 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
|
|||
crate::shortcuts::pretty("Shift+Alt")
|
||||
),
|
||||
),
|
||||
Tool::SingleRowMarquee | Tool::SingleColumnMarquee => hint(
|
||||
ui,
|
||||
&format!(
|
||||
"Click to select a one-pixel line · {} add · {} subtract · {} intersect",
|
||||
crate::shortcuts::pretty("Shift"),
|
||||
crate::shortcuts::pretty("Alt"),
|
||||
crate::shortcuts::pretty("Shift+Alt")
|
||||
),
|
||||
),
|
||||
Tool::Move => {
|
||||
// The Studio themes keep Photoshop's Auto-Select toggle too (#1275).
|
||||
widgets::checkbox(ui, &mut app.ui.tool_options.move_auto_select, tl!("Auto-Select:"));
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ fn is_point_tool(t: Tool) -> bool {
|
|||
t,
|
||||
Tool::RectMarquee
|
||||
| Tool::EllipseMarquee
|
||||
| Tool::SingleRowMarquee
|
||||
| Tool::SingleColumnMarquee
|
||||
| Tool::Crop
|
||||
| Tool::ObjectSelection
|
||||
| Tool::Pen
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ pub enum Tool {
|
|||
Move,
|
||||
RectMarquee,
|
||||
EllipseMarquee,
|
||||
/// Selects one pixel row across the whole canvas at the clicked y (Photoshop's flyout only:
|
||||
/// no key, not in the ⇧M cycle).
|
||||
SingleRowMarquee,
|
||||
/// Selects one pixel column down the whole canvas at the clicked x.
|
||||
SingleColumnMarquee,
|
||||
Lasso,
|
||||
PolygonLasso,
|
||||
MagneticLasso,
|
||||
|
|
@ -118,10 +123,12 @@ pub enum Tool {
|
|||
}
|
||||
|
||||
impl Tool {
|
||||
pub const ALL: [Tool; 53] = [
|
||||
pub const ALL: [Tool; 55] = [
|
||||
Tool::Move,
|
||||
Tool::RectMarquee,
|
||||
Tool::EllipseMarquee,
|
||||
Tool::SingleRowMarquee,
|
||||
Tool::SingleColumnMarquee,
|
||||
Tool::Lasso,
|
||||
Tool::PolygonLasso,
|
||||
Tool::MagneticLasso,
|
||||
|
|
@ -179,6 +186,8 @@ impl Tool {
|
|||
Tool::Move => "Move Tool",
|
||||
Tool::RectMarquee => "Rectangular Marquee Tool",
|
||||
Tool::EllipseMarquee => "Elliptical Marquee Tool",
|
||||
Tool::SingleRowMarquee => "Single Row Marquee Tool",
|
||||
Tool::SingleColumnMarquee => "Single Column Marquee Tool",
|
||||
Tool::Brush => "Brush Tool",
|
||||
Tool::Pencil => "Pencil Tool",
|
||||
Tool::MixerBrush => "Mixer Brush Tool",
|
||||
|
|
@ -278,6 +287,8 @@ impl Tool {
|
|||
Tool::CloneStamp | Tool::PatternStamp => 'S',
|
||||
Tool::HistoryBrush => 'Y',
|
||||
Tool::Blur | Tool::Sharpen | Tool::Smudge => '\0',
|
||||
// In the Marquee flyout, but M cycles only the Rectangular and Elliptical Marquee.
|
||||
Tool::SingleRowMarquee | Tool::SingleColumnMarquee => '\0',
|
||||
Tool::Dodge | Tool::Burn | Tool::Sponge => 'O',
|
||||
Tool::QuickSelection | Tool::ObjectSelection => 'W',
|
||||
Tool::Pen => 'P',
|
||||
|
|
@ -1180,7 +1191,7 @@ mod tests {
|
|||
assert!(!Tool::RedEye.is_brushlike());
|
||||
assert_eq!(Tool::from_name("patternStamp"), Some(Tool::PatternStamp));
|
||||
assert_eq!(Tool::from_name("Pattern Stamp Tool"), Some(Tool::PatternStamp));
|
||||
assert_eq!(Tool::ALL.len(), 53);
|
||||
assert_eq!(Tool::ALL.len(), 55);
|
||||
assert_eq!(Tool::from_name("Remove Tool"), Some(Tool::Remove));
|
||||
assert_eq!(Tool::Remove.key(), 'J');
|
||||
assert!(Tool::Remove.is_brushlike());
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ pub fn is_selection_tool(tool: Tool) -> bool {
|
|||
tool,
|
||||
Tool::RectMarquee
|
||||
| Tool::EllipseMarquee
|
||||
| Tool::SingleRowMarquee
|
||||
| Tool::SingleColumnMarquee
|
||||
| Tool::Lasso
|
||||
| Tool::PolygonLasso
|
||||
| Tool::MagneticLasso
|
||||
|
|
|
|||
|
|
@ -54,10 +54,10 @@ what an agent can't finish alone.
|
|||
scripted check there) is the only real oracle.
|
||||
|
||||
### G6. Missing tools
|
||||
- **Missing (15 of 68):** Artboard, Single Row Marquee, Single Column Marquee, Perspective Crop,
|
||||
Frame, Color Sampler (#1046), Color Replacement (engine command exists), Art History Brush,
|
||||
Freeform Pen and Curvature Pen (#1054), Add Anchor Point, Delete Anchor Point, Convert Point
|
||||
(only as Pen + ⌥), Horizontal Type Mask, Vertical Type Mask.
|
||||
- **Missing (13 of 68):** Artboard, Perspective Crop, Frame, Color Sampler (#1046), Color
|
||||
Replacement (engine command exists), Art History Brush, Freeform Pen and Curvature Pen (#1054),
|
||||
Add Anchor Point, Delete Anchor Point, Convert Point (only as Pen + ⌥), Horizontal Type Mask,
|
||||
Vertical Type Mask.
|
||||
- **Evidence:** `Tool` enum (`crates/ui-egui/src/state.rs`) against the 67 `<tool>` entries of
|
||||
Photoshop's `Default Keyboard Shortcuts.kys` plus Remove, Triangle and Curvature Pen.
|
||||
- **Impact:** users look for them by name and shortcut; several are daily tools for designers.
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ parity for the area and are already contained in the dimension rows above.
|
|||
| Area | % | Hours | Notes |
|
||||
|---|---:|---:|---|
|
||||
| Layers, groups, masks, blend modes, smart objects, layer styles | 65% | 150–250 | Broad and GPU-accelerated. Open: multi-layer Smart Object conversion (#2604, #2648), layer clipboard between documents (UI-217-23), Stamp Visible, contour editor, smart-object perspective (FILE-215-6), mask targeting by command (#2458) |
|
||||
| Selections, Select and Mask, channels | 55% | 120–200 | All selection tools except single row/column marquee. Select and Mask is a generic dialog (TOOL-214-1), no Refine Hair (#2671); Select Subject/Sky classical, 559 ms p50 on 24 MP vs a 100 ms budget |
|
||||
| Selections, Select and Mask, channels | 55% | 120–200 | All selection tools, single row/column marquee included (#2837). Select and Mask is a generic dialog (TOOL-214-1), no Refine Hair (#2671); Select Subject/Sky classical, 559 ms p50 on 24 MP vs a 100 ms budget |
|
||||
| Painting and brush engine | 55% | 150–250 | Every Brush Settings section exists; feel is the gap: lag on big brushes, pressure jumps, smoothing and edge quality reports ([brush-parity.md](brush-parity.md)) |
|
||||
| Retouching (healing, clone, patch, remove, content-aware) | 50% | 100–180 | Remove tool non-generative; Content-Aware Fill has no workspace (TOOL-214-15); live stroke preview only for Brush/Eraser (TOOL-213-7) |
|
||||
| Transform, warp, puppet, perspective, liquify | 55% | 100–180 | Free Transform modifiers right; no transform context menu (TOOL-214-5), no skew fields, puppet mesh is a block grid (TOOL-214-6), Liquify called "useless" by a user (#2606) |
|
||||
|
|
@ -431,7 +431,7 @@ filled bar. This extends UI reachability and does not claim Photoshop-authored s
|
|||
| Smart filters / text / effect shapes in PSDs | Measured on our Photoshop-authored set (https://github.com/storytold/photocraft-corpus, `corpus/photoshop`, 258 files): see the per-group floors in `crates/io/tests/corpus.rs` and `crates/engine/tests/photoshop_oracles.rs`. Smart objects and smart filters now survive PSD save and open (41 corpus files, 206 smart objects, round trip strict; Photoshop opens our exports with live filters); re-rendering Photoshop's smart filters with ours matches 5/30 (was 1/30) | low–medium | Remaining re-render gaps are filter maths (Gaussian/Motion Blur, Unsharp Mask, Emboss, Add Noise RNG) and bicubic placement. |
|
||||
| Core editing (layers, masks, selections, adjustments, filters, transforms) | Broad engine coverage; many interaction bugs fixed after 0.2.0 (adjustment dialogs, Curves, crop, Move/Transform modifiers, gesture origin) | medium | Fixes not yet user-validated. |
|
||||
| UI / UX polish | Shortcut audit 214 → 0 failures; dock, Layers rows and menus reworked; first visual-QA sweep found 14 defects (#147–#157). 2026-10-07: the keyboard-only shortcuts with no menu item (⌥[ ⌥] ⌥, ⌥. layer navigation, ⇧⌥[ ⇧⌥] to extend the selection, 1–0 for opacity and ⇧ for flow or fill, ⇧[ ⇧] hardness, ⌥⌘T to transform a copy and ⌥⇧⌘T to step and repeat), ⌥-click colour sampling with painting tools, double-click a Layers row for Layer Style, File › New from Clipboard, a centred main window and remembered Liquify settings (#352, #417, #350, #368, #419, #418). 2026-10-09: canvas zoom is physical at any display scale — 100% is one document pixel per physical display pixel, and every screen-space overlay, cursor, scrollbar, navigator and fit follows it (#1943) | low–medium | Needs recurring visual QA with realistic documents. |
|
||||
| Tools | 2026-10-09: Pencil, Mixer Brush, Patch, Content-Aware Move, Vertical Type, Pattern Stamp and Rotate View are toolbar tools. Remaining missing tools include Red Eye, Art History Brush, Freeform/Curvature Pen, Add/Delete Anchor Point tools, single row/column marquee, Color Sampler, Perspective Crop, type masks and Frame | low–medium | Patch has a live healing preview. Content-Aware Move is partial: Move/Extend, Structure/Color and Sample All Layers exist; Transform On Drop and a live result preview remain missing (`TOOL-213-4` in the scorecard). Magic/Background Eraser added; live gradients in progress (#180). Magnetic Lasso added 2026-10-08 (live-wire edge tracing, Width/Contrast/Frequency, `select.magneticLasso`). Pattern Stamp added 2026-10-08 (S flyout, `paint.patternStamp`, Aligned / Impressionist). Rotate View (2026-10-09) turns the canvas camera around its centre without rewriting pixels; Reset View and Match Rotation copy the angle. Crop rotation (2026-10-09, #1792): dragging outside the crop frame turns it (⇧ 15° steps, angle readout), and ↵ rotates the document and crops in one undo step (`image.crop` `angle`); the frame turns over the image as in Photoshop's Classic Mode, and the options-bar Straighten is still missing. |
|
||||
| Tools | 2026-10-09: Pencil, Mixer Brush, Patch, Content-Aware Move, Vertical Type, Pattern Stamp and Rotate View are toolbar tools. Remaining missing tools include Red Eye, Art History Brush, Freeform/Curvature Pen, Add/Delete Anchor Point tools, Color Sampler, Perspective Crop, type masks and Frame | low–medium | Patch has a live healing preview. Content-Aware Move is partial: Move/Extend, Structure/Color and Sample All Layers exist; Transform On Drop and a live result preview remain missing (`TOOL-213-4` in the scorecard). Magic/Background Eraser added; live gradients in progress (#180). Magnetic Lasso added 2026-10-08 (live-wire edge tracing, Width/Contrast/Frequency, `select.magneticLasso`). Pattern Stamp added 2026-10-08 (S flyout, `paint.patternStamp`, Aligned / Impressionist). Rotate View (2026-10-09) turns the canvas camera around its centre without rewriting pixels; Reset View and Match Rotation copy the angle. Crop rotation (2026-10-09, #1792): dragging outside the crop frame turns it (⇧ 15° steps, angle readout), and ↵ rotates the document and crops in one undo step (`image.crop` `angle`); the frame turns over the image as in Photoshop's Classic Mode, and the options-bar Straighten is still missing. |
|
||||
| Painting | Brush model and Brush Settings panel near Photoshop; .abr/.grd import; persistent presets; pen pressure/tilt on Windows, web, macOS and X11 | medium | Native Wayland pen input open (#79; a pen opens the window through Xwayland meanwhile); X11 pressure confirmed by a user, macOS not yet verified on tablet hardware. |
|
||||
| Text / typography | Engine works; caret placement and size editing fixed; OpenType features, text-on-path editing, composer parity partial | medium-low | Measure with the Photoshop-authored set. |
|
||||
| Colour management | Colour-managed canvas (document → monitor), embedded CMYK profiles, linear EXR/HDR, 16-bit float canvas | medium-high | Monitor profile follows only at launch. |
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ Triangle and Curvature Pen (minus legacy Rounded Rectangle and Targeted Adjustme
|
|||
| Group | Present | Missing |
|
||||
|---|---|---|
|
||||
| Move, artboard | Move | Artboard (commands `layer.new.artboard*` exist) |
|
||||
| Marquee | Rectangular, Elliptical | Single Row, Single Column |
|
||||
| Marquee | Rectangular, Elliptical, Single Row, Single Column | |
|
||||
| Lasso | Lasso, Polygonal, Magnetic | |
|
||||
| Selection | Object Selection, Quick Selection, Magic Wand | |
|
||||
| Crop and slice | Crop, Slice, Slice Select | Perspective Crop |
|
||||
|
|
|
|||
Loading…
Reference in New Issue