Skip to content

Commit

Permalink
shiny/imageutil: new package.
Browse files Browse the repository at this point in the history
Add an imageutil.Border function, for drawing outlined-but-not-filled
rectangles, such as widget borders, checkboxes, table cells, etc.

Change-Id: I1e55e5fe492a5d2bb4df6f03ab8d14c9cb9db67d
Reviewed-on: https://go-review.googlesource.com/24632
Reviewed-by: David Crawshaw <[email protected]>
  • Loading branch information
nigeltao committed Jul 1, 2016
1 parent 3ca9ecf commit 3cbfd08
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 2 deletions.
8 changes: 6 additions & 2 deletions shiny/example/basic/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"math"

"golang.org/x/exp/shiny/driver"
"golang.org/x/exp/shiny/imageutil"
"golang.org/x/exp/shiny/screen"
"golang.org/x/image/math/f64"
"golang.org/x/mobile/event/key"
Expand Down Expand Up @@ -85,8 +86,11 @@ func main() {
}

case paint.Event:
w.Fill(sz.Bounds(), blue0, screen.Src)
w.Fill(sz.Bounds().Inset(10), blue1, screen.Src)
const inset = 10
for _, r := range imageutil.Border(sz.Bounds(), inset) {
w.Fill(r, blue0, screen.Src)
}
w.Fill(sz.Bounds().Inset(inset), blue1, screen.Src)
w.Upload(image.Point{20, 0}, b, b.Bounds())
w.Fill(image.Rect(50, 50, 350, 120), red, screen.Over)

Expand Down
101 changes: 101 additions & 0 deletions shiny/imageutil/imageutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package imageutil implements some image utility functions.
package imageutil

import (
"image"
)

// TODO: move Border into the standard library's package image?

// Border returns four rectangles that together contain those points between r
// and r.Inset(inset). Visually:
//
// 00000000
// 00000000
// 11....22
// 11....22
// 11....22
// 33333333
// 33333333
//
// The inset may be negative, in which case the points will be outside r.
//
// Some of the returned rectangles may be empty. None of the returned
// rectangles will overlap.
func Border(r image.Rectangle, inset int) [4]image.Rectangle {
if inset == 0 {
return [4]image.Rectangle{}
}
if r.Dx() <= 2*inset || r.Dy() <= 2*inset {
return [4]image.Rectangle{r}
}

x := [4]int{
r.Min.X,
r.Min.X + inset,
r.Max.X - inset,
r.Max.X,
}
y := [4]int{
r.Min.Y,
r.Min.Y + inset,
r.Max.Y - inset,
r.Max.Y,
}
if inset < 0 {
x[0], x[1] = x[1], x[0]
x[2], x[3] = x[3], x[2]
y[0], y[1] = y[1], y[0]
y[2], y[3] = y[3], y[2]
}

// The top and bottom sections are responsible for filling the corners.
// The top and bottom sections go from x[0] to x[3], across the y's.
// The left and right sections go from y[1] to y[2], across the x's.

return [4]image.Rectangle{{
// Top section.
Min: image.Point{
X: x[0],
Y: y[0],
},
Max: image.Point{
X: x[3],
Y: y[1],
},
}, {
// Left section.
Min: image.Point{
X: x[0],
Y: y[1],
},
Max: image.Point{
X: x[1],
Y: y[2],
},
}, {
// Right section.
Min: image.Point{
X: x[2],
Y: y[1],
},
Max: image.Point{
X: x[3],
Y: y[2],
},
}, {
// Bottom section.
Min: image.Point{
X: x[0],
Y: y[2],
},
Max: image.Point{
X: x[3],
Y: y[3],
},
}}
}
74 changes: 74 additions & 0 deletions shiny/imageutil/imageutil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package imageutil

import (
"image"
"testing"
)

func area(r image.Rectangle) int {
dx, dy := r.Dx(), r.Dy()
if dx <= 0 || dy <= 0 {
return 0
}
return dx * dy
}

func TestBorder(t *testing.T) {
r := image.Rect(100, 200, 400, 300)

insets := []int{
-100,
-1,
+0,
+1,
+20,
+49,
+50,
+51,
+149,
+150,
+151,
}

for _, inset := range insets {
border := Border(r, inset)

outer, inner := r, r.Inset(inset)
if inset < 0 {
outer, inner = inner, outer
}

got := 0
for _, b := range border {
got += area(b)
}
want := area(outer) - area(inner)
if got != want {
t.Errorf("inset=%d: total area: got %d, want %d", inset, got, want)
}

for i, bi := range border {
for j, bj := range border {
if i <= j {
continue
}
if !bi.Intersect(bj).Empty() {
t.Errorf("inset=%d: %v and %v overlap", inset, bi, bj)
}
}
}

for _, b := range border {
if got := outer.Intersect(b); got != b {
t.Errorf("inset=%d: outer intersection: got %v, want %v", inset, got, b)
}
if got := inner.Intersect(b); !got.Empty() {
t.Errorf("inset=%d: inner intersection: got %v, want empty", inset, got)
}
}
}
}

0 comments on commit 3cbfd08

Please sign in to comment.