mirror of
https://github.com/penpot/penpot.git
synced 2025-07-10 12:47:18 +02:00
🔧 Add vertical alignment for text shapes
This commit is contained in:
parent
0010d61ae2
commit
134fb1ab4c
8 changed files with 2436 additions and 1 deletions
2365
frontend/playwright/data/render-wasm/get-file-text-align.json
Normal file
2365
frontend/playwright/data/render-wasm/get-file-text-align.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -162,3 +162,16 @@ test("Renders a file with multiple emoji", async ({ page }) => {
|
||||||
await workspace.waitForFirstRender();
|
await workspace.waitForFirstRender();
|
||||||
await expect(workspace.canvas).toHaveScreenshot();
|
await expect(workspace.canvas).toHaveScreenshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Renders a file with texts with different alignments", async ({ page }) => {
|
||||||
|
const workspace = new WasmWorkspacePage(page);
|
||||||
|
await workspace.setupEmptyFile();
|
||||||
|
await workspace.mockGetFile("render-wasm/get-file-text-align.json");
|
||||||
|
|
||||||
|
await workspace.goToWorkspace({
|
||||||
|
id: "692f368b-63ca-8141-8006-62925640b827",
|
||||||
|
pageId: "692f368b-63ca-8141-8006-62925640b828",
|
||||||
|
});
|
||||||
|
await workspace.waitForFirstRender();
|
||||||
|
await expect(workspace.canvas).toHaveScreenshot();
|
||||||
|
});
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
|
@ -236,6 +236,7 @@
|
||||||
|
|
||||||
(defn set-shape-text-images
|
(defn set-shape-text-images
|
||||||
[shape-id content]
|
[shape-id content]
|
||||||
|
|
||||||
(let [paragraph-set (first (get content :children))
|
(let [paragraph-set (first (get content :children))
|
||||||
paragraphs (get paragraph-set :children)]
|
paragraphs (get paragraph-set :children)]
|
||||||
(->> paragraphs
|
(->> paragraphs
|
||||||
|
@ -357,6 +358,10 @@
|
||||||
;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html
|
;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html
|
||||||
(h/call wasm/internal-module "_set_shape_blend_mode" (sr/translate-blend-mode blend-mode)))
|
(h/call wasm/internal-module "_set_shape_blend_mode" (sr/translate-blend-mode blend-mode)))
|
||||||
|
|
||||||
|
(defn set-shape-vertical-align
|
||||||
|
[vertical-align]
|
||||||
|
(h/call wasm/internal-module "_set_shape_vertical_align" (sr/serialize-vertical-align vertical-align)))
|
||||||
|
|
||||||
(defn set-shape-opacity
|
(defn set-shape-opacity
|
||||||
[opacity]
|
[opacity]
|
||||||
(h/call wasm/internal-module "_set_shape_opacity" (or opacity 1)))
|
(h/call wasm/internal-module "_set_shape_opacity" (or opacity 1)))
|
||||||
|
@ -630,6 +635,8 @@
|
||||||
(defn set-shape-text-content
|
(defn set-shape-text-content
|
||||||
[shape-id content]
|
[shape-id content]
|
||||||
(h/call wasm/internal-module "_clear_shape_text")
|
(h/call wasm/internal-module "_clear_shape_text")
|
||||||
|
(set-shape-vertical-align (dm/get-prop content :vertical-align))
|
||||||
|
|
||||||
(let [paragraph-set (first (dm/get-prop content :children))
|
(let [paragraph-set (first (dm/get-prop content :children))
|
||||||
paragraphs (dm/get-prop paragraph-set :children)
|
paragraphs (dm/get-prop paragraph-set :children)
|
||||||
fonts (fonts/get-content-fonts content)
|
fonts (fonts/get-content-fonts content)
|
||||||
|
@ -752,6 +759,7 @@
|
||||||
(when (some? shadows) (set-shape-shadows shadows))
|
(when (some? shadows) (set-shape-shadows shadows))
|
||||||
(when (= type :text)
|
(when (= type :text)
|
||||||
(set-shape-grow-type grow-type))
|
(set-shape-grow-type grow-type))
|
||||||
|
|
||||||
(when (or (ctl/any-layout? shape)
|
(when (or (ctl/any-layout? shape)
|
||||||
(ctl/any-layout-immediate-child? objects shape))
|
(ctl/any-layout-immediate-child? objects shape))
|
||||||
(set-layout-child shape))
|
(set-layout-child shape))
|
||||||
|
|
|
@ -295,6 +295,10 @@
|
||||||
[value enum-map]
|
[value enum-map]
|
||||||
(get enum-map value 0))
|
(get enum-map value 0))
|
||||||
|
|
||||||
|
(defn serialize-vertical-align
|
||||||
|
[vertical-align]
|
||||||
|
(serialize-enum vertical-align {"top" 0 "center" 1 "bottom" 2}))
|
||||||
|
|
||||||
(defn serialize-text-align
|
(defn serialize-text-align
|
||||||
[text-align]
|
[text-align]
|
||||||
(serialize-enum text-align {"left" 0 "center" 1 "right" 2 "justify" 3}))
|
(serialize-enum text-align {"left" 0 "center" 1 "right" 2 "justify" 3}))
|
||||||
|
|
|
@ -19,6 +19,7 @@ use math::{Bounds, Matrix};
|
||||||
use mem::SerializableResult;
|
use mem::SerializableResult;
|
||||||
use shapes::{
|
use shapes::{
|
||||||
BoolType, ConstraintH, ConstraintV, StructureEntry, StructureEntryType, TransformEntry, Type,
|
BoolType, ConstraintH, ConstraintV, StructureEntry, StructureEntryType, TransformEntry, Type,
|
||||||
|
VerticalAlign,
|
||||||
};
|
};
|
||||||
use skia_safe as skia;
|
use skia_safe as skia;
|
||||||
use state::State;
|
use state::State;
|
||||||
|
@ -346,6 +347,13 @@ pub extern "C" fn set_shape_blend_mode(mode: i32) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn set_shape_vertical_align(align: u8) {
|
||||||
|
with_current_shape!(state, |shape: &mut Shape| {
|
||||||
|
shape.set_vertical_align(VerticalAlign::from(align));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn set_shape_opacity(opacity: f32) {
|
pub extern "C" fn set_shape_opacity(opacity: f32) {
|
||||||
with_current_shape!(state, |shape: &mut Shape| {
|
with_current_shape!(state, |shape: &mut Shape| {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::{RenderState, Shape, SurfaceId};
|
use super::{RenderState, Shape, SurfaceId};
|
||||||
|
use crate::shapes::VerticalAlign;
|
||||||
use skia_safe::{textlayout::Paragraph, Paint, Path};
|
use skia_safe::{textlayout::Paragraph, Paint, Path};
|
||||||
|
|
||||||
pub fn render(
|
pub fn render(
|
||||||
|
@ -11,8 +12,16 @@ pub fn render(
|
||||||
.surfaces
|
.surfaces
|
||||||
.canvas(surface_id.unwrap_or(SurfaceId::Fills));
|
.canvas(surface_id.unwrap_or(SurfaceId::Fills));
|
||||||
|
|
||||||
|
let container_height = shape.selrect().height();
|
||||||
for group in paragraphs {
|
for group in paragraphs {
|
||||||
let mut offset_y = 0.0;
|
let total_paragraphs_height: f32 = group.iter().map(|p| p.height()).sum();
|
||||||
|
|
||||||
|
let mut offset_y = match shape.vertical_align() {
|
||||||
|
VerticalAlign::Center => (container_height - total_paragraphs_height) / 2.0,
|
||||||
|
VerticalAlign::Bottom => container_height - total_paragraphs_height,
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
for skia_paragraph in group {
|
for skia_paragraph in group {
|
||||||
let xy = (shape.selrect().x(), shape.selrect.y() + offset_y);
|
let xy = (shape.selrect().x(), shape.selrect.y() + offset_y);
|
||||||
skia_paragraph.paint(canvas, xy);
|
skia_paragraph.paint(canvas, xy);
|
||||||
|
|
|
@ -156,6 +156,24 @@ impl ConstraintH {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
|
pub enum VerticalAlign {
|
||||||
|
Top,
|
||||||
|
Center,
|
||||||
|
Bottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerticalAlign {
|
||||||
|
pub fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Self::Top,
|
||||||
|
1 => Self::Center,
|
||||||
|
2 => Self::Bottom,
|
||||||
|
_ => Self::Top,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
pub enum ConstraintV {
|
pub enum ConstraintV {
|
||||||
Top,
|
Top,
|
||||||
|
@ -195,6 +213,7 @@ pub struct Shape {
|
||||||
pub fills: Vec<Fill>,
|
pub fills: Vec<Fill>,
|
||||||
pub strokes: Vec<Stroke>,
|
pub strokes: Vec<Stroke>,
|
||||||
pub blend_mode: BlendMode,
|
pub blend_mode: BlendMode,
|
||||||
|
pub vertical_align: VerticalAlign,
|
||||||
pub blur: Blur,
|
pub blur: Blur,
|
||||||
pub opacity: f32,
|
pub opacity: f32,
|
||||||
pub hidden: bool,
|
pub hidden: bool,
|
||||||
|
@ -221,6 +240,7 @@ impl Shape {
|
||||||
fills: Vec::with_capacity(1),
|
fills: Vec::with_capacity(1),
|
||||||
strokes: Vec::with_capacity(1),
|
strokes: Vec::with_capacity(1),
|
||||||
blend_mode: BlendMode::default(),
|
blend_mode: BlendMode::default(),
|
||||||
|
vertical_align: VerticalAlign::Top,
|
||||||
opacity: 1.,
|
opacity: 1.,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
blur: Blur::default(),
|
blur: Blur::default(),
|
||||||
|
@ -312,6 +332,14 @@ impl Shape {
|
||||||
self.opacity = opacity;
|
self.opacity = opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_vertical_align(&mut self, align: VerticalAlign) {
|
||||||
|
self.vertical_align = align;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vertical_align(&self) -> VerticalAlign {
|
||||||
|
self.vertical_align
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_constraint_h(&mut self, constraint: Option<ConstraintH>) {
|
pub fn set_constraint_h(&mut self, constraint: Option<ConstraintH>) {
|
||||||
self.constraint_h = constraint;
|
self.constraint_h = constraint;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue