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 all 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 @@ defmodule Scenic.Script do
@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 @@ defmodule Scenic.Script do
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 @@ defmodule Scenic.Script do
[{: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
upper_left_radius = smallest([r1, width / 2, height / 2])
upper_right_radius = smallest([r2, width / 2, height / 2])
lower_right_radius = smallest([r3, width / 2, height / 2])
lower_left_radius = smallest([r4, width / 2, height / 2])

[
{:draw_rrectv,
{width, height, upper_left_radius, upper_right_radius, lower_right_radius, lower_left_radius, 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 @@ defmodule Scenic.Script do
]
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 @@ defmodule Scenic.Script do
{{: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