aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/features/items/recipes/RecipeScreen.kt
blob: d365c0e7202f219f53d1614b92b8539a2ccd3b67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package moe.nea.firmament.features.items.recipes

import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.renderer.RenderPipelines
import moe.nea.firmament.util.mc.CommonTextures
import moe.nea.firmament.util.render.enableScissorWithTranslation
import moe.nea.firmament.util.tr

class RecipeScreen(
	val recipes: List<RenderableRecipe<*>>,
) : Screen(tr("firmament.recipe.screen", "SkyBlock Recipe")) {

	data class PlacedRecipe(
		val bounds: Rectangle,
		val layoutedRecipe: StandaloneRecipeRenderer,
	) {
		fun moveTo(position: Point) {
			val Δx = position.x - bounds.x
			val Δy = position.y - bounds.y
			bounds.translate(Δx, Δy)
			layoutedRecipe.widgets.forEach { widget ->
				widget.position = widget.position.clone().also {
					it.translate(Δx, Δy)
				}
			}
		}
	}

	lateinit var placedRecipes: List<PlacedRecipe>
	var scrollViewport: Int = 0
	var scrollOffset: Int = 0
	var scrollPortWidth: Int = 0
	var heightEstimate: Int = 0
	val gutter = 10
	override fun init() {// TODO: wrap all of this in a scroll layout
		super.init()
		scrollViewport = minOf(height - 20, 250)
		scrollPortWidth = 0
		heightEstimate = 0
		var offset = height / 2 - scrollViewport / 2
		placedRecipes = recipes.map {
			val effectiveWidth = minOf(it.renderer.displayWidth, width - 20)
			val bounds = Rectangle(
				width / 2 - effectiveWidth / 2,
				offset,
				effectiveWidth,
				it.renderer.displayHeight
			)
			if (heightEstimate > 0)
				heightEstimate += gutter
			heightEstimate += bounds.height
			scrollPortWidth = maxOf(effectiveWidth, scrollPortWidth)
			offset += bounds.height + gutter
			val layoutedRecipe = it.render(bounds)
			layoutedRecipe.widgets.forEach(this::addRenderableWidget)
			PlacedRecipe(bounds, layoutedRecipe)
		}
	}

	fun scrollRect() =
		Rectangle(
			width / 2 - scrollPortWidth / 2, height / 2 - scrollViewport / 2,
			scrollPortWidth, scrollViewport
		)

	fun scissorScrollPort(guiGraphics: GuiGraphics) {
		guiGraphics.enableScissorWithTranslation(scrollRect())
	}

	override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
		if (!scrollRect().contains(mouseX, mouseY))
			return false
		scrollOffset = (scrollOffset + scrollY * -4)
			.coerceAtMost(heightEstimate - scrollViewport.toDouble())
			.coerceAtLeast(.0)
			.toInt()
		var offset = height / 2 - scrollViewport / 2 - scrollOffset
		placedRecipes.forEach {
			it.moveTo(Point(it.bounds.x, offset))
			offset += it.bounds.height + gutter
		}
		return true
	}

	override fun renderBackground(
		guiGraphics: GuiGraphics,
		mouseX: Int,
		mouseY: Int,
		partialTick: Float
	) {
		super.renderBackground(guiGraphics, mouseX, mouseY, partialTick)

		val srect = scrollRect()
		srect.grow(8, 8)
		guiGraphics.blitSprite(
			RenderPipelines.GUI_TEXTURED,
			CommonTextures.genericWidget(),
			srect.x, srect.y,
			srect.width, srect.height
		)

		scissorScrollPort(guiGraphics)
		placedRecipes.forEach {
			guiGraphics.blitSprite(
				RenderPipelines.GUI_TEXTURED,
				CommonTextures.genericWidget(),
				it.bounds.x, it.bounds.y,
				it.bounds.width, it.bounds.height
			)
		}
		guiGraphics.disableScissor()
	}

	override fun render(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
		scissorScrollPort(guiGraphics)
		super.render(guiGraphics, mouseX, mouseY, partialTick)
		guiGraphics.disableScissor()
	}

	override fun tick() {
		super.tick()
		placedRecipes.forEach {
			it.layoutedRecipe.tick()
		}
	}
}