Skip to content

Commit

Permalink
Merge pull request #290 from GPrimola/extended_draw_rounded_rectangle
Browse files Browse the repository at this point in the history
Support draw rounded rectangles with varying corners.
  • Loading branch information
crertel authored Jun 15, 2024
2 parents 4beaed5 + f63d4e4 commit e7e7e03
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 0 deletions.
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 @@ -273,6 +274,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 @@ -535,6 +540,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 @@ -1510,6 +1550,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 @@ -2261,6 +2314,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

0 comments on commit e7e7e03

Please sign in to comment.