diff --git a/card.go b/card.go index b246cd2..44fbb7d 100644 --- a/card.go +++ b/card.go @@ -34,7 +34,7 @@ func Card(c *ui.Context, opts CardOptions, body func()) *ui.Element { } if opts.Decorated { card.Border(theme.BorderWidth, k.Ornament).DrawOver(func(p *ui.Painter, r ui.Rect) { - cardOrnament(p, r, k.Ornament) + internal.Frame(p, r, cardInset, 9, k.Ornament) }) } else { card.Border(theme.BorderWidth, k.Border) @@ -44,10 +44,7 @@ func Card(c *ui.Context, opts CardOptions, body func()) *ui.Element { ui.Text(c, opts.Title).Font(theme.SerifFont).FontSize(FontSize(c, theme.H3Size)).FontWeight(600).LineHeight(1.3) if opts.Decorated { ui.Box(c).Height(7).FillWidth().Shrink(0).Draw(func(p *ui.Painter, r ui.Rect) { - cy := r.Y + r.H/2 - p.Line(r.X, cy, r.X+r.W/2-6, cy, 1, k.Ornament) - p.Line(r.X+r.W/2+6, cy, r.X+r.W, cy, 1, k.Ornament) - p.FillPath(internal.Diamond(internal.Snap(p, r.X+r.W/2), internal.Snap(p, cy), 7), k.Ornament) + internal.RuleDiamond(p, r, 6, 7, k.Ornament) }) } } @@ -59,12 +56,3 @@ func Card(c *ui.Context, opts CardOptions, body func()) *ui.Element { }) return card } - -// cardOrnament draws the inner line and the four corner diamonds. -func cardOrnament(p *ui.Painter, r ui.Rect, col ui.Color) { - in := ui.Rect{X: r.X + cardInset, Y: r.Y + cardInset, W: r.W - 2*cardInset, H: r.H - 2*cardInset} - p.Stroke(in, col, 1, 1) - for _, pt := range [4][2]float32{{in.X, in.Y}, {in.X + in.W, in.Y}, {in.X, in.Y + in.H}, {in.X + in.W, in.Y + in.H}} { - p.FillPath(internal.Diamond(internal.Snap(p, pt[0]), internal.Snap(p, pt[1]), 9), col) - } -} diff --git a/dialog.go b/dialog.go index f242804..b368286 100644 --- a/dialog.go +++ b/dialog.go @@ -91,23 +91,11 @@ func dialogPanel(c *ui.Context, panel *ui.Element, width float32, decorated bool panel.Width(width).MaxWidth(w-32).MaxHeight(h-32).Padding(u*6).Gap(u*3).Margin(8*(1-p), 0, 0, 0) if decorated { panel.Border(theme.BorderWidth, k.Ornament).Padding(u*6 + 6).DrawOver(func(pt *ui.Painter, r ui.Rect) { - dialogOrnaments(pt, r, k.Ornament, k.Surface) + internal.Frame(pt, r, 5, 7, k.Ornament) }) } } -// dialogOrnaments draws the inner frame and the four corner diamonds. -func dialogOrnaments(p *ui.Painter, r ui.Rect, ink, ground ui.Color) { - const in = 5 - f := ui.Rect{X: r.X + in, Y: r.Y + in, W: r.W - 2*in, H: r.H - 2*in} - p.Stroke(f, ink, 1, 1) - for _, pt := range [4][2]float32{{f.X, f.Y}, {f.X + f.W, f.Y}, {f.X, f.Y + f.H}, {f.X + f.W, f.Y + f.H}} { - x, y := internal.Snap(p, pt[0]), internal.Snap(p, pt[1]) - p.FillPath(internal.Diamond(x, y, 11), ground) - p.FillPath(internal.Diamond(x, y, 7), ink) - } -} - // dialogHeader builds the title and close button; it reports a close click. func dialogHeader(c *ui.Context, title string, decorated, closable bool, closeKey string) bool { k := Tokens(c) @@ -130,10 +118,7 @@ func dialogHeader(c *ui.Context, title string, decorated, closable bool, closeKe // dialogRule is the ornament line under a decorated title. func dialogRule(c *ui.Context, ink ui.Color) { ui.Box(c).FillWidth().Height(9).Margin(2, 0, 2, 0).Draw(func(p *ui.Painter, r ui.Rect) { - y, cx := r.Y+r.H/2, r.X+r.W/2 - p.Line(r.X, y, cx-10, y, 1, ink) - p.Line(cx+10, y, r.X+r.W, y, 1, ink) - p.FillPath(internal.Diamond(internal.Snap(p, cx), internal.Snap(p, y), 7), ink) + internal.RuleDiamond(p, r, 10, 7, ink) }) } diff --git a/divider.go b/divider.go index b2443c5..2d0ed68 100644 --- a/divider.go +++ b/divider.go @@ -37,6 +37,12 @@ func Divider(c *ui.Context, opts DividerOptions) *ui.Element { } return e.Height(theme.BorderWidth) } + if opts.Label == "" && !opts.Vertical { + gap := Density(c).Unit()*2 + dividerDiamond/2 + return ui.Box(c).Height(dividerDiamond).Shrink(0).AlignSelf(ui.Stretch).Draw(func(p *ui.Painter, r ui.Rect) { + internal.RuleDiamond(p, r, gap, dividerDiamond, line) + }) + } e := ui.Row(c).Gap(Density(c).Unit() * 2).Shrink(0).AlignSelf(ui.Stretch) if opts.Vertical { e.Column().AlignItems(ui.Center) diff --git a/heading.go b/heading.go index 6766865..87a6ba1 100644 --- a/heading.go +++ b/heading.go @@ -31,7 +31,7 @@ func Heading(c *ui.Context, title string, opts HeadingOptions) *ui.Element { } if opts.Divider { ui.Box(c).FillWidth().Height(9).Margin(u, 0, 0, 0).Draw(func(p *ui.Painter, r ui.Rect) { - headingOrnament(p, r, k.Ornament) + internal.RuleDiamond(p, r, 6, 7, k.Ornament) }) } }) @@ -49,12 +49,3 @@ func headingSize(level int) float32 { } panic("mujica: Heading Level must be 1, 2 or 3") } - -// headingOrnament draws symmetric rules around a center diamond. -func headingOrnament(p *ui.Painter, r ui.Rect, c ui.Color) { - cx, cy := r.X+r.W/2, r.Y+r.H/2 - const d, gap = 7, 6 - internal.Rule(p, r.X, cx-gap, cy, c) - internal.Rule(p, cx+gap, r.X+r.W, cy, c) - p.FillPath(internal.Diamond(cx, cy, d), c) -} diff --git a/internal/display.go b/internal/display.go index 90d7740..a04de3e 100644 --- a/internal/display.go +++ b/internal/display.go @@ -17,11 +17,33 @@ func Fade(e *ui.Element, d time.Duration) *ui.Element { // Rule draws a pixel-aligned 1 DIP horizontal line at y. func Rule(p *ui.Painter, x0, x1, y float32, c ui.Color) { + yy := ruleY(p, y) + p.Line(x0, yy, x1, yy, 1, c) +} + +// ruleY moves y to where a 1 DIP line fills whole device pixels. +func ruleY(p *ui.Painter, y float32) float32 { s := float64(p.Scale()) px := math.Floor(float64(y) * s) if int(math.Round(s))%2 == 1 { px += 0.5 } - yy := float32(px / s) - p.Line(x0, yy, x1, yy, 1, c) + return float32(px / s) +} + +// RuleDiamond draws a rule across the middle of r, broken by gap on each side of a size diamond. +func RuleDiamond(p *ui.Painter, r ui.Rect, gap, size float32, col ui.Color) { + cx, cy := r.X+r.W/2, ruleY(p, r.Y+r.H/2) + p.Line(r.X, cy, cx-gap, cy, 1, col) + p.Line(cx+gap, cy, r.X+r.W, cy, 1, col) + p.FillPath(Diamond(Snap(p, cx), Snap(p, cy), size), col) +} + +// Frame strokes a 1 DIP line inset inside r with a size diamond on each corner. +func Frame(p *ui.Painter, r ui.Rect, inset, size float32, col ui.Color) { + f := ui.Rect{X: r.X + inset, Y: r.Y + inset, W: r.W - 2*inset, H: r.H - 2*inset} + p.Stroke(f, col, 1, 1) + for _, pt := range [4][2]float32{{f.X, f.Y}, {f.X + f.W, f.Y}, {f.X, f.Y + f.H}, {f.X + f.W, f.Y + f.H}} { + p.FillPath(Diamond(Snap(p, pt[0]), Snap(p, pt[1]), size), col) + } } diff --git a/result.go b/result.go index 537cc19..3ba96f1 100644 --- a/result.go +++ b/result.go @@ -87,10 +87,6 @@ func Result(c *ui.Context, opts ResultOptions) ResultResult { // resultOrnament draws two hairlines meeting a diamond, in ornament gold. func resultOrnament(c *ui.Context, k theme.Tokens) { ui.Box(c).Size(160, 12).Role(ui.RoleNone).Draw(func(p *ui.Painter, r ui.Rect) { - cy := float32(int(r.Y+r.H/2)) + 0.5 - cx := r.X + r.W/2 - p.Line(r.X, cy, cx-9, cy, 1, k.Ornament) - p.Line(cx+9, cy, r.X+r.W, cy, 1, k.Ornament) - p.FillPath(internal.Diamond(cx, cy, 8), k.Ornament) + internal.RuleDiamond(p, r, 9, 8, k.Ornament) }) } diff --git a/testdata/snapshots/darwin/card-comfortable-dark.png b/testdata/snapshots/darwin/card-comfortable-dark.png index 10d4d65..b1e7cb5 100644 Binary files a/testdata/snapshots/darwin/card-comfortable-dark.png and b/testdata/snapshots/darwin/card-comfortable-dark.png differ diff --git a/testdata/snapshots/darwin/card-comfortable-light.png b/testdata/snapshots/darwin/card-comfortable-light.png index c4168ec..4613831 100644 Binary files a/testdata/snapshots/darwin/card-comfortable-light.png and b/testdata/snapshots/darwin/card-comfortable-light.png differ diff --git a/testdata/snapshots/darwin/card-compact-dark.png b/testdata/snapshots/darwin/card-compact-dark.png index dd1317f..a297107 100644 Binary files a/testdata/snapshots/darwin/card-compact-dark.png and b/testdata/snapshots/darwin/card-compact-dark.png differ diff --git a/testdata/snapshots/darwin/card-compact-light.png b/testdata/snapshots/darwin/card-compact-light.png index bafc0a0..c269bdf 100644 Binary files a/testdata/snapshots/darwin/card-compact-light.png and b/testdata/snapshots/darwin/card-compact-light.png differ diff --git a/testdata/snapshots/darwin/card-dark.png b/testdata/snapshots/darwin/card-dark.png index 5c1aca2..aaef0b1 100644 Binary files a/testdata/snapshots/darwin/card-dark.png and b/testdata/snapshots/darwin/card-dark.png differ diff --git a/testdata/snapshots/darwin/card-light.png b/testdata/snapshots/darwin/card-light.png index 227f964..d6e02f7 100644 Binary files a/testdata/snapshots/darwin/card-light.png and b/testdata/snapshots/darwin/card-light.png differ diff --git a/testdata/snapshots/darwin/dialog-comfortable-dark.png b/testdata/snapshots/darwin/dialog-comfortable-dark.png index 860367f..648a7b4 100644 Binary files a/testdata/snapshots/darwin/dialog-comfortable-dark.png and b/testdata/snapshots/darwin/dialog-comfortable-dark.png differ diff --git a/testdata/snapshots/darwin/dialog-comfortable-light.png b/testdata/snapshots/darwin/dialog-comfortable-light.png index d00b726..7c713ee 100644 Binary files a/testdata/snapshots/darwin/dialog-comfortable-light.png and b/testdata/snapshots/darwin/dialog-comfortable-light.png differ diff --git a/testdata/snapshots/darwin/dialog-dark.png b/testdata/snapshots/darwin/dialog-dark.png index 2c22caf..30983c8 100644 Binary files a/testdata/snapshots/darwin/dialog-dark.png and b/testdata/snapshots/darwin/dialog-dark.png differ diff --git a/testdata/snapshots/darwin/dialog-light.png b/testdata/snapshots/darwin/dialog-light.png index 7c8c7ee..ef23bd5 100644 Binary files a/testdata/snapshots/darwin/dialog-light.png and b/testdata/snapshots/darwin/dialog-light.png differ