mirror of
https://github.com/Dvorinka/Devour.git
synced 2026-06-03 20:13:03 +00:00
230 lines
5.4 KiB
Go
230 lines
5.4 KiB
Go
package scorecard
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
"image/draw"
|
|
"strconv"
|
|
|
|
"golang.org/x/image/font"
|
|
"golang.org/x/image/font/basicfont"
|
|
"golang.org/x/image/math/fixed"
|
|
)
|
|
|
|
type DrawContext struct {
|
|
Img *image.RGBA
|
|
Scale int
|
|
}
|
|
|
|
func NewDrawContext(img *image.RGBA, scale int) *DrawContext {
|
|
return &DrawContext{Img: img, Scale: scale}
|
|
}
|
|
|
|
func (dc *DrawContext) S(v int) int {
|
|
return v * dc.Scale
|
|
}
|
|
|
|
func (dc *DrawContext) FillRect(x, y, w, h int, c color.RGBA) {
|
|
for dy := 0; dy < h; dy++ {
|
|
for dx := 0; dx < w; dx++ {
|
|
px, py := x+dx, y+dy
|
|
if px >= 0 && px < dc.Img.Bounds().Dx() && py >= 0 && py < dc.Img.Bounds().Dy() {
|
|
dc.Img.Set(px, py, c)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (dc *DrawContext) DrawRect(x1, y1, x2, y2 int, c color.RGBA, width int) {
|
|
for i := 0; i < width; i++ {
|
|
dc.DrawHLine(x1, y1+i, x2, c)
|
|
dc.DrawHLine(x1, y2-i, x2, c)
|
|
dc.DrawVLine(x1+i, y1, y2, c)
|
|
dc.DrawVLine(x2-i, y1, y2, c)
|
|
}
|
|
}
|
|
|
|
func (dc *DrawContext) DrawHLine(x1, y, x2 int, c color.RGBA) {
|
|
if y < 0 || y >= dc.Img.Bounds().Dy() {
|
|
return
|
|
}
|
|
if x1 > x2 {
|
|
x1, x2 = x2, x1
|
|
}
|
|
for x := x1; x <= x2; x++ {
|
|
if x >= 0 && x < dc.Img.Bounds().Dx() {
|
|
dc.Img.Set(x, y, c)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (dc *DrawContext) DrawVLine(x, y1, y2 int, c color.RGBA) {
|
|
if x < 0 || x >= dc.Img.Bounds().Dx() {
|
|
return
|
|
}
|
|
if y1 > y2 {
|
|
y1, y2 = y2, y1
|
|
}
|
|
for y := y1; y <= y2; y++ {
|
|
if y >= 0 && y < dc.Img.Bounds().Dy() {
|
|
dc.Img.Set(x, y, c)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (dc *DrawContext) DrawRoundedRect(x, y, w, h, r int, c color.RGBA) {
|
|
dc.FillRect(x+r, y, w-2*r, h, c)
|
|
dc.FillRect(x, y+r, w, h-2*r, c)
|
|
for dy := -r; dy <= 0; dy++ {
|
|
for dx := -r; dx <= 0; dx++ {
|
|
if dx*dx+dy*dy >= r*r {
|
|
continue
|
|
}
|
|
dc.Img.Set(x+r+dx, y+r+dy, c)
|
|
dc.Img.Set(x+w-r-1-dx, y+r+dy, c)
|
|
dc.Img.Set(x+r+dx, y+h-r-1-dy, c)
|
|
dc.Img.Set(x+w-r-1-dx, y+h-r-1-dy, c)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (dc *DrawContext) DrawRoundedRectWithOutline(x, y, w, h, r int, fill, outline color.RGBA, outlineWidth int) {
|
|
dc.DrawRoundedRect(x, y, w, h, r, fill)
|
|
rr := r - outlineWidth
|
|
if rr < 0 {
|
|
rr = 0
|
|
}
|
|
for i := 0; i < outlineWidth; i++ {
|
|
ri := r - i
|
|
if ri < 0 {
|
|
ri = 0
|
|
}
|
|
dc.DrawHLine(x+ri, y+i, x+w-ri-1, outline)
|
|
dc.DrawHLine(x+ri, y+h-i-1, x+w-ri-1, outline)
|
|
dc.DrawVLine(x+i, y+ri, y+h-ri-1, outline)
|
|
dc.DrawVLine(x+w-i-1, y+ri, y+h-ri-1, outline)
|
|
}
|
|
}
|
|
|
|
func (dc *DrawContext) DrawDiamond(cx, cy, size int, c color.RGBA) {
|
|
for dy := -size; dy <= size; dy++ {
|
|
for dx := -size; dx <= size; dx++ {
|
|
if abs(dx)+abs(dy) <= size {
|
|
px, py := cx+dx, cy+dy
|
|
if px >= 0 && px < dc.Img.Bounds().Dx() && py >= 0 && py < dc.Img.Bounds().Dy() {
|
|
dc.Img.Set(px, py, c)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (dc *DrawContext) DrawRuleWithOrnament(y, x1, x2, cx int, lineColor, ornamentColor color.RGBA) {
|
|
gap := dc.S(8)
|
|
dc.DrawHLine(x1, y, cx-gap, lineColor)
|
|
dc.DrawHLine(cx+gap, y, x2, lineColor)
|
|
dc.DrawDiamond(cx, y, dc.S(3), ornamentColor)
|
|
}
|
|
|
|
func (dc *DrawContext) DrawVertRuleWithOrnament(x, y1, y2, cy int, lineColor, ornamentColor color.RGBA) {
|
|
gap := dc.S(8)
|
|
dc.DrawVLine(x, y1, cy-gap, lineColor)
|
|
dc.DrawVLine(x, cy+gap, y2, lineColor)
|
|
dc.DrawDiamond(x, cy, dc.S(3), ornamentColor)
|
|
}
|
|
|
|
func (dc *DrawContext) DrawText(text string, x, y int, face font.Face, c color.RGBA) {
|
|
d := font.Drawer{
|
|
Dst: dc.Img,
|
|
Src: &image.Uniform{c},
|
|
Face: face,
|
|
Dot: fixed.Point26_6{X: fixed.I(x), Y: fixed.I(y)},
|
|
}
|
|
d.DrawString(text)
|
|
}
|
|
|
|
func (dc *DrawContext) DrawCenteredText(text string, cx, y int, face font.Face, c color.RGBA) {
|
|
advance := font.MeasureString(face, text)
|
|
x := cx - (advance.Ceil() / 2)
|
|
dc.DrawText(text, x, y, face, c)
|
|
}
|
|
|
|
func (dc *DrawContext) DrawRightAlignedText(text string, rx, y int, face font.Face, c color.RGBA) {
|
|
advance := font.MeasureString(face, text)
|
|
x := rx - advance.Ceil()
|
|
dc.DrawText(text, x, y, face, c)
|
|
}
|
|
|
|
func (dc *DrawContext) FillBackground(c color.RGBA) {
|
|
draw.Draw(dc.Img, dc.Img.Bounds(), &image.Uniform{c}, image.Point{}, draw.Src)
|
|
}
|
|
|
|
func (dc *DrawContext) DrawDoubleFrame(x1, y1, x2, y2 int, outerColor, innerColor color.RGBA, outerWidth, innerWidth int) {
|
|
dc.DrawRect(x1, y1, x2, y2, outerColor, outerWidth)
|
|
innerX1 := x1 + outerWidth + 2
|
|
innerY1 := y1 + outerWidth + 2
|
|
innerX2 := x2 - outerWidth - 2
|
|
innerY2 := y2 - outerWidth - 2
|
|
dc.DrawRect(innerX1, innerY1, innerX2, innerY2, innerColor, innerWidth)
|
|
}
|
|
|
|
func (dc *DrawContext) TextWidth(text string, face font.Face) int {
|
|
return font.MeasureString(face, text).Ceil()
|
|
}
|
|
|
|
func (dc *DrawContext) TextBounds(text string, face font.Face) (width, height, offsetY int) {
|
|
advance := font.MeasureString(face, text)
|
|
width = advance.Ceil()
|
|
metrics := face.Metrics()
|
|
height = (metrics.Ascent + metrics.Descent).Ceil()
|
|
offsetY = -metrics.Ascent.Ceil()
|
|
return
|
|
}
|
|
|
|
func (dc *DrawContext) TruncateText(text string, maxWidth int, face font.Face) string {
|
|
if dc.TextWidth(text, face) <= maxWidth {
|
|
return text
|
|
}
|
|
ellipsis := "…"
|
|
ellipsisWidth := dc.TextWidth(ellipsis, face)
|
|
for len(text) > 0 {
|
|
text = text[:len(text)-1]
|
|
if dc.TextWidth(text, face)+ellipsisWidth <= maxWidth {
|
|
return text + ellipsis
|
|
}
|
|
}
|
|
return ellipsis
|
|
}
|
|
|
|
func GetFont() font.Face {
|
|
return basicfont.Face7x13
|
|
}
|
|
|
|
func FmtScore(score float64) string {
|
|
if score == float64(int(score)) {
|
|
return strconv.Itoa(int(score))
|
|
}
|
|
return strconv.FormatFloat(score, 'f', 1, 64)
|
|
}
|
|
|
|
func abs(x int) int {
|
|
if x < 0 {
|
|
return -x
|
|
}
|
|
return x
|
|
}
|
|
|
|
func max(a, b int) int {
|
|
if a > b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|