Compare commits
3 Commits
4be5154df0
...
f386684454
Author | SHA1 | Date | |
---|---|---|---|
f386684454 | |||
76bd2837d3 | |||
de12ee6bcd |
28
debug/debug.go
Normal file
28
debug/debug.go
Normal file
@ -0,0 +1,28 @@
|
||||
package debug
|
||||
|
||||
import "image/draw"
|
||||
import "image/color"
|
||||
import "golang.org/x/image/math/fixed"
|
||||
import "git.tebibyte.media/tomo/typeset"
|
||||
import "git.tebibyte.media/tomo/typeset/internal"
|
||||
|
||||
// DrawBounds draws the LayoutBounds, MinimumSize, and LayoutBoundsSpace of a
|
||||
// TypeSetter to the given image using these colors:
|
||||
// - Red: LayoutBounds
|
||||
// - Green: MinimumSize
|
||||
// - Blue: LayoutBoundsSpace
|
||||
func DrawBounds (destination draw.Image, setter *typeset.TypeSetter, offset fixed.Point26_6) {
|
||||
blue := color.RGBA { B: 255, A: 255 }
|
||||
red := color.RGBA { R: 255, A: 255 }
|
||||
green := color.RGBA { G: 255, A: 255 }
|
||||
|
||||
layoutBoundsSpace := setter.LayoutBoundsSpace()
|
||||
layoutBounds := setter.LayoutBounds()
|
||||
|
||||
minimum := setter.MinimumSize()
|
||||
minimumRect := internal.RoundRect(fixed.Rectangle26_6 { Max: minimum }.Add(offset).Add(layoutBounds.Min))
|
||||
internal.DrawRectangleOutline(destination, minimumRect, green)
|
||||
|
||||
internal.DrawRectangleOutline(destination, internal.RoundRect(layoutBoundsSpace.Add(offset)), blue)
|
||||
internal.DrawRectangleOutline(destination, internal.RoundRect(layoutBounds.Add(offset)), red)
|
||||
}
|
47
draw.go
47
draw.go
@ -6,6 +6,7 @@ import "image/draw"
|
||||
import "image/color"
|
||||
import "golang.org/x/image/font"
|
||||
import "golang.org/x/image/math/fixed"
|
||||
import "git.tebibyte.media/tomo/typeset/internal"
|
||||
|
||||
// Draw draws the contents of a TypeSetter to an image at the given offset. It
|
||||
// returns a rectangle containing all pixels in the image that were updated.
|
||||
@ -49,27 +50,6 @@ func Draw (destination draw.Image, setter *TypeSetter, offset fixed.Point26_6, c
|
||||
return updatedRegion
|
||||
}
|
||||
|
||||
// DrawBounds draws the LayoutBounds, MinimumSize, and LayoutBoundsSpace of a
|
||||
// TypeSetter to the given image using these colors:
|
||||
// - Red: LayoutBounds
|
||||
// - Green: MinimumSize
|
||||
// - Blue: LayoutBoundsSpace
|
||||
func DrawBounds (destination draw.Image, setter *TypeSetter, offset fixed.Point26_6) {
|
||||
blue := color.RGBA { B: 255, A: 255 }
|
||||
red := color.RGBA { R: 255, A: 255 }
|
||||
green := color.RGBA { G: 255, A: 255 }
|
||||
|
||||
layoutBoundsSpace := setter.LayoutBoundsSpace()
|
||||
layoutBounds := setter.LayoutBounds()
|
||||
|
||||
minimum := setter.MinimumSize()
|
||||
minimumRect := roundRect(fixed.Rectangle26_6 { Max: minimum }.Add(offset).Add(layoutBounds.Min))
|
||||
drawRectangleOutline(destination, minimumRect, green)
|
||||
|
||||
drawRectangleOutline(destination, roundRect(layoutBoundsSpace.Add(offset)), blue)
|
||||
drawRectangleOutline(destination, roundRect(layoutBounds.Add(offset)), red)
|
||||
}
|
||||
|
||||
func drawTofu (
|
||||
char rune,
|
||||
destination draw.Image,
|
||||
@ -78,29 +58,8 @@ func drawTofu (
|
||||
col color.Color,
|
||||
) {
|
||||
bounds, _ := tofuBounds(face)
|
||||
rectBounds := roundRect(bounds).Add(image.Pt (
|
||||
rectBounds := internal.RoundRect(bounds).Add(image.Pt (
|
||||
position.X.Round(),
|
||||
position.Y.Round()))
|
||||
drawRectangleOutline(destination, rectBounds, col)
|
||||
}
|
||||
|
||||
func drawRectangleOutline (destination draw.Image, bounds image.Rectangle, col color.Color) {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
|
||||
destination.Set(x, bounds.Min.Y, col)
|
||||
}
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
|
||||
destination.Set(bounds.Min.X, y, col)
|
||||
destination.Set(bounds.Max.X - 1, y, col)
|
||||
}
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
|
||||
destination.Set(x, bounds.Max.Y - 1, col)
|
||||
}
|
||||
}
|
||||
|
||||
func roundRect (rectangle fixed.Rectangle26_6) image.Rectangle {
|
||||
return image.Rect (
|
||||
rectangle.Min.X.Round(),
|
||||
rectangle.Min.Y.Round(),
|
||||
rectangle.Max.X.Round(),
|
||||
rectangle.Max.Y.Round())
|
||||
internal.DrawRectangleOutline(destination, rectBounds, col)
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import "image/color"
|
||||
import "golang.org/x/image/math/fixed"
|
||||
import "git.tebibyte.media/tomo/typeset"
|
||||
import "golang.org/x/image/font/basicfont"
|
||||
import "git.tebibyte.media/tomo/typeset/debug"
|
||||
|
||||
func main () {
|
||||
img := image.NewRGBA(image.Rect(0, 0, 2048, 1024))
|
||||
@ -122,7 +123,7 @@ func drawText (destination subDrawImage, setter *typeset.TypeSetter, bounds imag
|
||||
Y: metrics.Ascent + fixed.I(bounds.Min.Y),
|
||||
}
|
||||
// typeset.Draw(destination, setter, offset, color.Black)
|
||||
typeset.DrawBounds(subImage, setter, offset)
|
||||
debug.DrawBounds(subImage, setter, offset)
|
||||
typeset.Draw(subImage, setter, offset, color.Black)
|
||||
|
||||
}
|
||||
|
27
internal/draw.go
Normal file
27
internal/draw.go
Normal file
@ -0,0 +1,27 @@
|
||||
package internal
|
||||
|
||||
import "image"
|
||||
import "image/draw"
|
||||
import "image/color"
|
||||
import "golang.org/x/image/math/fixed"
|
||||
|
||||
func DrawRectangleOutline (destination draw.Image, bounds image.Rectangle, col color.Color) {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
|
||||
destination.Set(x, bounds.Min.Y, col)
|
||||
}
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
|
||||
destination.Set(bounds.Min.X, y, col)
|
||||
destination.Set(bounds.Max.X - 1, y, col)
|
||||
}
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
|
||||
destination.Set(x, bounds.Max.Y - 1, col)
|
||||
}
|
||||
}
|
||||
|
||||
func RoundRect (rectangle fixed.Rectangle26_6) image.Rectangle {
|
||||
return image.Rect (
|
||||
rectangle.Min.X.Round(),
|
||||
rectangle.Min.Y.Round(),
|
||||
rectangle.Max.X.Round(),
|
||||
rectangle.Max.Y.Round())
|
||||
}
|
@ -89,6 +89,34 @@ type TypeSetter struct {
|
||||
layoutBoundsSpace fixed.Rectangle26_6
|
||||
}
|
||||
|
||||
// AtPosition returns the index of the rune at the specified position.
|
||||
func (this *TypeSetter) AtPosition (position fixed.Point26_6) int {
|
||||
metrics := this.face.Metrics()
|
||||
lastValidIndex := 0
|
||||
index := 0
|
||||
for _, tok := range this.tokens {
|
||||
pos := tok.position
|
||||
yValid :=
|
||||
position.Y >= pos.Y - metrics.Ascent &&
|
||||
position.Y <= pos.Y + metrics.Descent
|
||||
if !yValid { index += len(tok.runes); continue }
|
||||
|
||||
for _, runl := range tok.runes {
|
||||
x := pos.X + runl.x
|
||||
xValid := position.X >= pos.X + runl.x
|
||||
if xValid {
|
||||
lastValidIndex = index
|
||||
} else if x > position.X {
|
||||
return lastValidIndex
|
||||
}
|
||||
|
||||
index ++
|
||||
}
|
||||
}
|
||||
index ++
|
||||
return lastValidIndex
|
||||
}
|
||||
|
||||
// Runes returns an iterator for all runes in the TypeSetter, and their positions.
|
||||
func (this *TypeSetter) Runes () RuneIter {
|
||||
this.needFlow()
|
||||
|
Loading…
Reference in New Issue
Block a user