Skip to content

Commit

Permalink
Added support for specifying color transparency with #rgba and #rrggb…
Browse files Browse the repository at this point in the history
…baa. (#152)
  • Loading branch information
henryso authored Feb 5, 2022
1 parent ab52861 commit 655cf67
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 103 deletions.
4 changes: 4 additions & 0 deletions docs/widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ The easiest way to get started is probably to take a look at some of
the [examples](../examples/), and then refer to the detailed Widget
documentation (this document) when the need arises.

A quick note about colors. When specifying colors, use a CSS-like
hexdecimal color specification. Pixlet supports "#rgb", "#rrggbb",
"#rgba", and "#rrggbbaa" color specifications.


## Animation
Animations turns a list of children into an animation, where each
Expand Down
46 changes: 24 additions & 22 deletions encode/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ def assert(success, message=None):
fail(message or "assertion failed")
# Font tests
assert(render.fonts["6x13"] == "6x13")
assert(render.fonts["Dina_r400-6"] == "Dina_r400-6")
assert(render.fonts["6x13"] == "6x13", 'render.fonts["6x13"] == "6x13"')
assert(render.fonts["Dina_r400-6"] == "Dina_r400-6", 'render.fonts["Dina_r400-6"] == "Dina_r400-6"')
# Box tests
b1 = render.Box(
Expand All @@ -29,15 +29,17 @@ b1 = render.Box(
color = "#000",
)
assert(b1.width == 64)
assert(b1.height == 32)
assert(b1.color == "#000000")
assert(b1.width == 64, "b1.width == 64")
assert(b1.height == 32, "b1.height == 32")
assert(b1.color == "#000", 'b1.color == "#000"')
b2 = render.Box(
child = b1,
color = "#0f0d",
)
assert(b2.child == b1)
assert(b2.child == b1, "b2.child == b1")
assert(b2.color == "#0f0d", 'b2.color == "#0f0d"')
# Text tests
t1 = render.Text(
Expand All @@ -46,11 +48,11 @@ t1 = render.Text(
color = "#fff",
content = "foo",
)
assert(t1.height == 10)
assert(t1.font == "6x13")
assert(t1.color == "#ffffff")
assert(0 < t1.size()[0])
assert(0 < t1.size()[1])
assert(t1.height == 10, "t1.height == 10")
assert(t1.font == "6x13", 't1.font == "6x13"')
assert(t1.color == "#fff", 't1.color == "#fff"')
assert(0 < t1.size()[0], "0 < t1.size()[0]")
assert(0 < t1.size()[1], "0 < t1.size()[1]")
# WrappedText
tw = render.WrappedText(
Expand All @@ -71,8 +73,8 @@ f = render.Root(
),
)
assert(f.child.width == 123)
assert(f.child.child.content == "hello")
assert(f.child.width == 123, "f.child.width == 123")
assert(f.child.child.content == "hello", 'f.child.child.content == "hello"')
# Padding
p = render.Padding(pad=3, child=render.Box(width=1, height=2))
Expand All @@ -82,9 +84,9 @@ p3 = render.Padding(pad=1, child=render.Box(width=1, height=2), expanded=True)
# Image tests
png_src = base64.decode("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/AAAZ4gk3AAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==")
img = render.Image(src = png_src)
assert(img.src == png_src)
assert(0 < img.size()[0])
assert(0 < img.size()[1])
assert(img.src == png_src, "img.src == png_src")
assert(0 < img.size()[0], "0 < img.size()[0]")
assert(0 < img.size()[1], "0 < img.size()[1]")
# Row and Column
r1 = render.Row(
Expand All @@ -106,12 +108,12 @@ r1 = render.Row(
],
)
assert(r1.main_align == "space_evenly")
assert(r1.cross_align == "center")
assert(r1.children[1].main_align == "start")
assert(r1.children[1].cross_align == "end")
assert(len(r1.children) == 2)
assert(len(r1.children[1].children) == 3)
assert(r1.main_align == "space_evenly", 'r1.main_align == "space_evenly"')
assert(r1.cross_align == "center", 'r1.cross_align == "center"')
assert(r1.children[1].main_align == "start", 'r1.children[1].main_align == "start"')
assert(r1.children[1].cross_align == "end", 'r1.children[1].cross_align == "end"')
assert(len(r1.children) == 2, "len(r1.children) == 2")
assert(len(r1.children[1].children) == 3, "len(r1.children[1].children) == 3")
def main():
return render.Root(child=r1)
Expand Down
67 changes: 67 additions & 0 deletions render/colors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package render

import (
"fmt"
"image/color"
)

func ParseColor(scol string) (color.Color, error) {
var format string
var fourBits bool
var hasAlpha bool

switch len(scol) {
case 4:
format = "#%1x%1x%1x"
fourBits = true
hasAlpha = false
case 5:
format = "#%1x%1x%1x%1x"
fourBits = true
hasAlpha = true
case 7:
format = "#%02x%02x%02x"
fourBits = false
hasAlpha = false
case 9:
format = "#%02x%02x%02x%02x"
fourBits = false
hasAlpha = true
default:
return color.Gray{0}, fmt.Errorf("color: %v is not a hex-color", scol)
}

var r, g, b, a uint8

if hasAlpha {
n, err := fmt.Sscanf(scol, format, &r, &g, &b, &a)
if err != nil {
return color.Gray{0}, err
}
if n != 4 {
return color.Gray{0}, fmt.Errorf("color: %v is not a hex-color", scol)
}
} else {
n, err := fmt.Sscanf(scol, format, &r, &g, &b)
if err != nil {
return color.Gray{0}, err
}
if n != 3 {
return color.Gray{0}, fmt.Errorf("color: %v is not a hex-color", scol)
}
if fourBits {
a = 15
} else {
a = 255
}
}

if fourBits {
r |= r << 4
g |= g << 4
b |= b << 4
a |= a << 4
}

return color.NRGBA{r, g, b, a}, nil
}
57 changes: 57 additions & 0 deletions render/colors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package render

import (
"testing"

"github.com/stretchr/testify/assert"
)

func ParseAndAssertColor(
t *testing.T,
scol string,
expectedR uint32,
expectedG uint32,
expectedB uint32,
expectedA uint32,
) {
c, err := ParseColor(scol)
assert.Nil(t, err)
r, g, b, a := c.RGBA()
assert.Equal(t, expectedR, r)
assert.Equal(t, expectedG, g)
assert.Equal(t, expectedB, b)
assert.Equal(t, expectedA, a)
}

func TestParseColorRGB(t *testing.T) {
ParseAndAssertColor(t, "#5ad", 0x5555, 0xaaaa, 0xdddd, 0xffff)
}

func TestParseColorRGBA(t *testing.T) {
ParseAndAssertColor(t, "#5ad8", 0x2d82, 0x5b05, 0x7653, 0x8888)
}

func TestParseColorRRGGBB(t *testing.T) {
ParseAndAssertColor(t, "#257adb", 0x2525, 0x7a7a, 0xdbdb, 0xffff)
}

func TestParseColorRRGGBBAA(t *testing.T) {
ParseAndAssertColor(t, "#257adb75", 0x110a, 0x3831, 0x64df, 0x7575)
}

func TestParseColorBadValue(t *testing.T) {
_, err := ParseColor("5ad")
assert.NotNil(t, err)

_, err = ParseColor("#5a")
assert.NotNil(t, err)

_, err = ParseColor("#5ad8f")
assert.NotNil(t, err)

_, err = ParseColor("#5ad8f33da")
assert.NotNil(t, err)

_, err = ParseColor("#xyz")
assert.NotNil(t, err)
}
4 changes: 4 additions & 0 deletions runtime/gen/docs.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ The easiest way to get started is probably to take a look at some of
the [examples](../examples/), and then refer to the detailed Widget
documentation (this document) when the need arises.

A quick note about colors. When specifying colors, use a CSS-like
hexdecimal color specification. Pixlet supports "#rgb", "#rrggbb",
"#rgba", and "#rrggbbaa" color specifications.

{{range .}}{{$widgetName := .Name}}
## {{.Name}}
{{.Documentation}}
Expand Down
1 change: 0 additions & 1 deletion runtime/gen/header.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"sync"

"github.com/lucasb-eyer/go-colorful"
"github.com/mitchellh/hashstructure/v2"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
Expand Down
15 changes: 6 additions & 9 deletions runtime/gen/widget.tmpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
type {{.Name}} struct {
Widget
render.{{.Name}}
{{range .AttrColor}}
starlark{{.Render}} starlark.String
{{end}}
{{range .AttrChild}}
starlark{{.Render}} starlark.Value
{{end}}
Expand Down Expand Up @@ -58,8 +61,9 @@ func new{{.Name}}(
{{end}}

{{range .AttrColor}}{{if not .ReadOnly}}
w.starlark{{.Render}} = {{.Starlark}}
if {{.Starlark}}.Len() > 0 {
c, err := colorful.Hex({{.Starlark}}.GoString())
c, err := render.ParseColor({{.Starlark}}.GoString())
if err != nil {
return nil, fmt.Errorf("{{.Starlark}} is not a valid hex string: %s", {{.Starlark}}.String())
}
Expand Down Expand Up @@ -175,14 +179,7 @@ func (w *{{.Name}}) Attr(name string) (starlark.Value, error) {
{{end}}
{{range .AttrColor}}
case "{{.Starlark}}":
if w.{{.Render}} == nil {
return nil, nil
}
c, ok := colorful.MakeColor(w.{{.Render}})
if !ok {
return nil, nil
}
return starlark.String(c.Hex()), nil
return w.starlark{{.Render}}, nil
{{end}}
{{range .AttrBool}}
case "{{.Starlark}}":
Expand Down
Loading

0 comments on commit 655cf67

Please sign in to comment.