clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

chore/app-model-decomp
puzzletea / export / pdf / render_difficulty.go
render_difficulty.go 3.8K
1package pdfexport23import (4 "math"56 "codeberg.org/go-pdf/fpdf"7)89type difficultyStarState uint81011const (12 difficultyStarEmpty difficultyStarState = iota13 difficultyStarHalf14 difficultyStarFull15)1617type puzzleSubtitleLayout struct {18 labelText string19 labelWidth float6420 starStates []difficultyStarState21 starsWidth float6422 totalWidth float6423}2425func scoreToDifficultyStarStates(score float64) []difficultyStarState {26 score = clampDifficultyScore(score)2728 units := int(math.Round(score * 10))29 states := make([]difficultyStarState, 5)30 for i := range states {31 switch {32 case units >= 2:33 states[i] = difficultyStarFull34 units -= 235 case units == 1:36 states[i] = difficultyStarHalf37 units = 038 default:39 states[i] = difficultyStarEmpty40 }41 }42 return states43}4445func puzzleDifficultySubtitleLayout(pdf *fpdf.Fpdf, puzzle Puzzle) puzzleSubtitleLayout {46 label := "Difficulty:"47 if !isMixedModes(puzzle.ModeSelection) {48 label = "Mode: " + puzzle.ModeSelection + " | " + label49 }5051 layout := puzzleSubtitleLayout{52 labelText: label,53 starStates: scoreToDifficultyStarStates(puzzle.DifficultyScore),54 }55 if pdf == nil {56 return layout57 }5859 setPuzzleSubtitleStyle(pdf)60 layout.labelWidth = pdf.GetStringWidth(label)61 layout.starsWidth = difficultyStarsWidth()62 layout.totalWidth = layout.labelWidth + difficultyTextToStarsGapMM + layout.starsWidth63 return layout64}6566func renderPuzzleDifficultySubtitle(pdf *fpdf.Fpdf, pageW, y float64, puzzle Puzzle) {67 if pdf == nil {68 return69 }7071 layout := puzzleDifficultySubtitleLayout(pdf, puzzle)72 rowHeight := 5.073 startX := (pageW - layout.totalWidth) / 274 if startX < 0 {75 startX = 076 }7778 setPuzzleSubtitleStyle(pdf)79 pdf.SetXY(startX, y)80 pdf.CellFormat(layout.labelWidth, rowHeight, layout.labelText, "", 0, "L", false, 0, "")8182 starX := startX + layout.labelWidth + difficultyTextToStarsGapMM83 starCenterY := y + rowHeight/284 renderDifficultyStars(pdf, starX, starCenterY, layout.starStates)85}8687func renderDifficultyStars(pdf *fpdf.Fpdf, x, centerY float64, states []difficultyStarState) {88 if pdf == nil {89 return90 }9192 textR, textG, textB := pdf.GetTextColor()93 emptyOutline := 13294 pdf.SetLineWidth(difficultyStarOutlineMM)9596 for i, state := range states {97 starX := x + float64(i)*(difficultyStarSizeMM+difficultyStarGapMM)98 points := difficultyStarPoints(starX, centerY, difficultyStarSizeMM)99 top := centerY - difficultyStarSizeMM/2100101 switch state {102 case difficultyStarFull:103 pdf.SetDrawColor(textR, textG, textB)104 fillDifficultyStar(pdf, points, starX, top, difficultyStarSizeMM, difficultyStarSizeMM, textR, textG, textB)105 pdf.Polygon(points, "D")106 case difficultyStarHalf:107 pdf.SetDrawColor(emptyOutline, emptyOutline, emptyOutline)108 pdf.Polygon(points, "D")109 fillDifficultyStar(pdf, points, starX, top, difficultyStarSizeMM/2, difficultyStarSizeMM, textR, textG, textB)110 default:111 pdf.SetDrawColor(emptyOutline, emptyOutline, emptyOutline)112 pdf.Polygon(points, "D")113 }114 }115}116117func fillDifficultyStar(118 pdf *fpdf.Fpdf,119 points []fpdf.PointType,120 x,121 y,122 w,123 h float64,124 r,125 g,126 b int,127) {128 if pdf == nil || len(points) == 0 || w <= 0 || h <= 0 {129 return130 }131132 pdf.ClipPolygon(points, false)133 pdf.ClipRect(x, y, w, h, false)134 pdf.SetFillColor(r, g, b)135 pdf.Rect(x, y, w, h, "F")136 pdf.ClipEnd()137 pdf.ClipEnd()138}139140func difficultyStarsWidth() float64 {141 return float64(5)*difficultyStarSizeMM + float64(4)*difficultyStarGapMM142}143144func difficultyStarPoints(x, centerY, size float64) []fpdf.PointType {145 cx := x + size/2146 cy := centerY147 outer := size / 2148 inner := outer * 0.48149 points := make([]fpdf.PointType, 0, 10)150151 for i := range 10 {152 radius := outer153 if i%2 == 1 {154 radius = inner155 }156157 angle := -math.Pi/2 + float64(i)*math.Pi/5158 points = append(points, fpdf.PointType{159 X: cx + math.Cos(angle)*radius,160 Y: cy + math.Sin(angle)*radius,161 })162 }163164 return points165}