make pumkin alllll better!

This commit is contained in:
Sasha Koshka 2023-09-15 15:22:44 -04:00
parent 14deec24f5
commit 92cb318972
2 changed files with 44 additions and 37 deletions

View File

@ -8,12 +8,11 @@ import "golang.org/x/image/math/fixed"
type Align int
const (
// AlignLeft aligns the start of each line to the beginning point
// of each dot.
AlignLeft Align = iota
AlignRight
AlignCenter
AlignJustify
// X | Y
AlignStart Align = iota // left | top
AlignMiddle // center | center
AlignEnd // right | bottom
AlignEven // justified | evenly spaced
)
// RuneLayout contains layout information for a single rune relative to its
@ -150,11 +149,7 @@ func DoLine (text []rune, face font.Face, wrap bool, width fixed.Int26_6) (line
// set the width of the line's content.
line.ContentWidth = lastWord.X + lastWord.Width
if wrap {
line.Width = width
} else {
line.Width = line.ContentWidth
}
line.Width = width
line.SpaceAfter = lastWord.SpaceAfter
return
}
@ -174,17 +169,17 @@ func (line *LineLayout) Length () int {
// method.
func (line *LineLayout) Align (align Align) {
if len(line.Words) == 0 { return }
if align == AlignJustify {
if align == AlignEven {
line.justify()
return
}
leftOffset := -line.Words[0].X
if align == AlignCenter {
if align == AlignMiddle {
leftOffset += (line.Width - line.ContentWidth) / 2
} else if align == AlignRight {
} else if align == AlignEnd {
leftOffset += line.Width - line.ContentWidth
}
@ -195,7 +190,7 @@ func (line *LineLayout) Align (align Align) {
func (line *LineLayout) justify () {
if len(line.Words) < 2 {
line.Align(AlignLeft)
line.Align(AlignStart)
return
}

View File

@ -14,11 +14,10 @@ type TypeSetter struct {
layoutClean bool
alignClean bool
align Align
face font.Face
maxWidth int
maxHeight int
wrap bool
hAlign, vAlign Align
face font.Face
width, height int
wrap bool
minWidth fixed.Int26_6
layoutBounds image.Rectangle
@ -34,14 +33,15 @@ func (setter *TypeSetter) needLayout () {
setter.layoutBounds = image.Rectangle { }
setter.layoutBoundsSpace = image.Rectangle { }
setter.minWidth = 0
if setter.face == nil { return }
if setter.face == nil { return }
horizontalExtent := fixed.Int26_6(0)
horizontalExtentSpace := fixed.Int26_6(0)
metrics := setter.face.Metrics()
remaining := setter.text
y := fixed.Int26_6(0)
// function to add line and update bounds statistics
addLine := func (line LineLayout) {
line.Y = y
y += metrics.Height
@ -59,7 +59,7 @@ func (setter *TypeSetter) needLayout () {
for len(remaining) > 0 {
line, remainingFromLine := DoLine (
remaining, setter.face, setter.wrap,
fixed.I(setter.maxWidth))
fixed.I(setter.width))
remaining = remainingFromLine
addLine(line)
}
@ -71,13 +71,19 @@ func (setter *TypeSetter) needLayout () {
setter.lines[len(setter.lines) - 1].BreakAfter
if needBlankLine { addLine(LineLayout { }) }
// if we are wrapping text, the width must be the user-set width
if setter.wrap {
horizontalExtent = fixed.I(setter.width)
horizontalExtentSpace = fixed.I(setter.width)
}
// calculate layout boundaries
setter.minWidth = horizontalExtentSpace
setter.layoutBounds.Max.X = horizontalExtent.Round()
setter.layoutBoundsSpace.Max.X = horizontalExtentSpace.Round()
y -= metrics.Height
if setter.maxHeight == 0 {
if setter.height == 0 {
setter.layoutBounds.Min.Y = -metrics.Ascent.Round()
setter.layoutBounds.Max.Y =
y.Round() +
@ -85,7 +91,7 @@ func (setter *TypeSetter) needLayout () {
} else {
setter.layoutBounds.Min.Y = -metrics.Ascent.Round()
setter.layoutBounds.Max.Y =
setter.maxHeight -
setter.height -
metrics.Ascent.Round()
}
setter.layoutBoundsSpace.Min.Y = setter.layoutBounds.Min.Y
@ -98,13 +104,18 @@ func (setter *TypeSetter) needAlignedLayout () {
setter.alignClean = true
for index := range setter.lines {
align := setter.align
if align == AlignJustify {
align := setter.hAlign
// if the horizontal align is even, align lines with breaks
// after them to the left anyways
if align == AlignEven {
except :=
index == len(setter.lines) - 1 ||
setter.lines[index].BreakAfter
if except { align = AlignLeft }
if except { align = AlignStart }
}
// align line
setter.lines[index].Align(align)
}
}
@ -118,9 +129,10 @@ func (setter *TypeSetter) SetWrap (wrap bool) {
// SetAlign sets the alignment method of the typesetter.
func (setter *TypeSetter) SetAlign (horizontal, vertical Align) {
if setter.align == horizontal { return }
if setter.hAlign == horizontal && setter.vAlign == vertical { return }
setter.alignClean = false
setter.align = horizontal
setter.hAlign = horizontal
setter.vAlign = vertical
}
// SetText sets the text content of the typesetter.
@ -141,20 +153,20 @@ func (setter *TypeSetter) SetFace (face font.Face) {
// SetWidth sets the width of the typesetter. Text will still be able
// to overflow outside of this width if wrapping is disabled.
func (setter *TypeSetter) SetWidth (width int) {
if setter.maxWidth == width { return }
if setter.width == width { return }
setter.layoutClean = false
setter.alignClean = false
setter.maxWidth = width
setter.width = width
}
// SetHeight sets the height of the typesetter. If the height is greater than
// zero, no lines will be laid out past it. If the height is zero, the text's
// maximum height will not be constrained.
func (setter *TypeSetter) SetHeight (heignt int) {
if setter.maxHeight == heignt { return }
if setter.height == heignt { return }
setter.layoutClean = false
setter.alignClean = false
setter.maxHeight = heignt
setter.height = heignt
}
// Em returns the width of one emspace according to the typesetter's font, which
@ -173,12 +185,12 @@ func (setter *TypeSetter) LineHeight () fixed.Int26_6 {
// Width returns the height of the typesetter as set by SetWidth.
func (setter *TypeSetter) Width () int {
return setter.maxWidth
return setter.width
}
// Height returns the height of the typesetter as set by SetHeight.
func (setter *TypeSetter) Height () int {
return setter.maxHeight
return setter.height
}
// Face returns the TypeSetter's font face as set by SetFace.