Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support draw rounded rectangles with varying corners. #290

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions lib/scenic/script.ex
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
@op_draw_ellipse 0x09
@op_draw_text 0x0A
@op_draw_sprites 0x0B
@op_draw_rrectv 0x0C
@op_draw_script 0x0F

@op_begin_path 0x20
Expand Down Expand Up @@ -272,6 +273,10 @@
x3 :: number, y3 :: number, fill_stroke()}}
| {:draw_rect, {width :: number, height :: number, fill_stroke()}}
| {:draw_rrect, {width :: number, height :: number, radius :: number, fill_stroke()}}
| {:draw_rrectv,
{width :: number, height :: number, upperLeftRadius :: number,
upperRightRadius :: number, lowerRightRadius :: number, lowerLeftRadius :: number,
fill_stroke()}}
| {:draw_sector, {radius :: number, radians :: number, fill_stroke()}}
| {:draw_arc, {radius :: number, radians :: number, fill_stroke()}}
| {:draw_circle, {radius :: number, fill_stroke()}}
Expand Down Expand Up @@ -534,6 +539,41 @@
[{:draw_rrect, {width, height, radius, flag}} | ops]
end

@doc """
Draw a rounded rectangle defined by height, width, radius1, radius2, radius3 and radius4. Can be filled or stroked.

Radii values will be set as follow:

- Upper left corner: radius1
- Upper right corner: radius2
- Lower right corner: radius3
- Lower left corner: radius4

Creates a new path and draws it.
"""
@spec draw_variable_rounded_rectangle(
ops :: t(),
width :: number,
height :: number,
r1 :: number,
r2 :: number,
r3 :: number,
r4 :: number,
fill_stroke_flags :: fill_stroke()
) :: ops :: t()
def draw_variable_rounded_rectangle(ops, width, height, r1, r2, r3, r4, flag) do
upperLeftRadius = smallest([r1, width / 2, height / 2])

Check warning on line 565 in lib/scenic/script.ex

View workflow job for this annotation

GitHub Actions / build (1.11.4, 24.2)

Variable names should be written in snake_case.
upperRightRadius = smallest([r2, width / 2, height / 2])

Check warning on line 566 in lib/scenic/script.ex

View workflow job for this annotation

GitHub Actions / build (1.11.4, 24.2)

Variable names should be written in snake_case.
lowerRightRadius = smallest([r3, width / 2, height / 2])

Check warning on line 567 in lib/scenic/script.ex

View workflow job for this annotation

GitHub Actions / build (1.11.4, 24.2)

Variable names should be written in snake_case.
lowerLeftRadius = smallest([r4, width / 2, height / 2])

Check warning on line 568 in lib/scenic/script.ex

View workflow job for this annotation

GitHub Actions / build (1.11.4, 24.2)

Variable names should be written in snake_case.

[
{:draw_rrectv,
{width, height, upperLeftRadius, upperRightRadius, lowerRightRadius, lowerLeftRadius, flag}}
| ops
]
end

@doc """
Draw a sector defined by radius and an angle. Can be filled or stroked.

Expand Down Expand Up @@ -1481,6 +1521,19 @@
]
end

defp serialize_op({:draw_rrectv, {w, h, ulR, urR, lrR, llR, flag}}) do
<<
@op_draw_rrectv::16-big,
to_flag(flag)::16-big,
w::float-32-big,
h::float-32-big,
ulR::float-32-big,
urR::float-32-big,
lrR::float-32-big,
llR::float-32-big
>>
end

defp serialize_op({:script, id}) do
[
<<
Expand Down Expand Up @@ -2214,6 +2267,20 @@
{{:draw_sprites, {id, cmds}}, bin}
end

defp deserialize_op(<<
@op_draw_rrectv::16-big,
flag::16-big,
w::float-32-big,
h::float-32-big,
ulR::float-32-big,
urR::float-32-big,
lrR::float-32-big,
llR::float-32-big,
bin::binary
>>) do
{{:draw_rrectv, {w, h, ulR, urR, lrR, llR, from_flag(flag)}}, bin}
end

defp deserialize_op(<<
@op_draw_script::16-big,
id_size::16,
Expand Down
26 changes: 26 additions & 0 deletions test/scenic/script_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,32 @@ defmodule Scenic.ScriptTest do
[{:draw_rrect, {13.0, 12.0, 6.0, :stroke}}]
end

test "draw_variable_rounded_rectangle varying all corners works" do
expected = [{:draw_rrectv, {10.0, 11.0, 2.0, 3.0, 4.0, 5.0, :fill}}]
assert Script.draw_variable_rounded_rectangle([], 10, 11, 2, 3, 4, 5, :fill) == expected
assert expected == Script.serialize(expected) |> Script.deserialize()

assert Script.draw_variable_rounded_rectangle([], 10, 11, 2, 3, 4, 5, :stroke) ==
[{:draw_rrectv, {10.0, 11.0, 2.0, 3.0, 4.0, 5.0, :stroke}}]

assert Script.draw_variable_rounded_rectangle([], 10, 11, 2, 3, 4, 5, :fill_stroke) ==
[{:draw_rrectv, {10.0, 11.0, 2.0, 3.0, 4.0, 5.0, :fill_stroke}}]
end

test "draw_variable_rounded_rectangle varying all corners shrinks radius if too big" do
assert Script.draw_variable_rounded_rectangle([], 10, 12, 30, 40, 50, 4, :fill) ==
[{:draw_rrectv, {10.0, 12.0, 5.0, 5.0, 5.0, 4.0, :fill}}]

assert Script.draw_variable_rounded_rectangle([], 13, 12, 30, 40, 5, 60, :stroke) ==
[{:draw_rrectv, {13.0, 12.0, 6.0, 6.0, 5.0, 6.0, :stroke}}]

assert Script.draw_variable_rounded_rectangle([], 13, 12, 30, 4, 50, 60, :stroke) ==
[{:draw_rrectv, {13.0, 12.0, 6.0, 4.0, 6.0, 6.0, :stroke}}]

assert Script.draw_variable_rounded_rectangle([], 13, 12, 3, 40, 50, 60, :stroke) ==
[{:draw_rrectv, {13.0, 12.0, 3.0, 6.0, 6.0, 6.0, :stroke}}]
end

test "draw_sector works" do
expected = [{:draw_sector, {10.0, 3.0, :fill}}]
assert Script.draw_sector([], 10, 3, :fill) == expected
Expand Down
Loading