From e7ded02d306e715729cbf8e83c1ad01af6040b66 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 4 Oct 2024 13:41:55 +0700 Subject: [PATCH] Charts in storage tooltips --- .../mc/otm/OverdriveThatMatters.java | 3 + .../mc/otm/client/render/ChartRendering.kt | 102 +++++---- .../mc/otm/client/render/MGUIGraphics.kt | 10 +- .../screen/panels/DecimalHistoryChartPanel.kt | 2 +- .../client/screen/widget/MatterGaugePanel.kt | 17 +- .../client/screen/widget/PowerGaugePanel.kt | 11 +- .../dbotthepony/mc/otm/config/ClientConfig.kt | 5 + .../mc/otm/core/util/Formatting.kt | 193 +++++++++++++++++- 8 files changed, 289 insertions(+), 54 deletions(-) diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index b86b95967..77e20d762 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -32,6 +32,7 @@ import ru.dbotthepony.mc.otm.client.MatteryGUI; import ru.dbotthepony.mc.otm.client.model.ExosuitModel; import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel; import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel; +import ru.dbotthepony.mc.otm.client.render.ChartTooltipElement; import ru.dbotthepony.mc.otm.client.render.ShockwaveRenderer; import ru.dbotthepony.mc.otm.client.render.blockentity.BatteryBankRenderer; import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer; @@ -159,6 +160,8 @@ public final class OverdriveThatMatters { bus.addListener(EventPriority.NORMAL, BatteryBankRenderer.Companion::onRegisterAdditionalModels); bus.addListener(EventPriority.NORMAL, MatterBatteryBankRenderer.Companion::onRegisterAdditionalModels); + bus.addListener(EventPriority.NORMAL, ChartTooltipElement.Companion::register); + MBlockColors.INSTANCE.register(bus); } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/ChartRendering.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/ChartRendering.kt index bc55dda65..a1d5fcef7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/ChartRendering.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/ChartRendering.kt @@ -7,12 +7,16 @@ import com.mojang.blaze3d.vertex.ByteBufferBuilder import com.mojang.blaze3d.vertex.DefaultVertexFormat import com.mojang.blaze3d.vertex.PoseStack import com.mojang.blaze3d.vertex.VertexFormat -import it.unimi.dsi.fastutil.floats.Float2ObjectMap import net.minecraft.client.gui.Font +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent import net.minecraft.client.renderer.GameRenderer import net.minecraft.network.chat.Component +import net.minecraft.world.inventory.tooltip.TooltipComponent +import net.neoforged.neoforge.client.event.RegisterClientTooltipComponentFactoriesEvent import org.lwjgl.opengl.GL11.GL_LESS import ru.dbotthepony.kommons.math.RGBAColor +import ru.dbotthepony.mc.otm.client.minecraft import kotlin.math.PI import kotlin.math.acos import kotlin.math.cos @@ -40,7 +44,7 @@ data class ChartMouseLabels( data class ChartLevelLabels( val labels: Map, - val font: Font, + val font: Font? = null, val lineColor: RGBAColor = RGBAColor.DARK_GREEN, val textColor: RGBAColor = RGBAColor.DARK_GREEN, val textGravity: RenderGravity = RenderGravity.TOP_RIGHT, @@ -49,19 +53,44 @@ data class ChartLevelLabels( private val BYTE_BUFFER_BUILDER = ByteBufferBuilder(786_432) +class ChartTooltipElement( + private val normalized: List>, + private val width: Float, + private val height: Float, + private val levelLabels: ChartLevelLabels? = null, +) : ClientTooltipComponent, TooltipComponent { + override fun getHeight(): Int { + return this.height.toInt() + } + + override fun getWidth(font: Font): Int { + return this.width.toInt() + } + + override fun renderImage(font: Font, x: Int, y: Int, graphics: GuiGraphics) { + renderChart(graphics.pose(), normalized, this.width, this.height - 10f, levelLabels = this.levelLabels, x = x.toFloat(), y = y.toFloat() + 10f) + } + + companion object { + fun register(event: RegisterClientTooltipComponentFactoriesEvent) { + event.register(ChartTooltipElement::class.java) { it } + } + } +} + fun renderChart( poseStack: PoseStack, - normalized: FloatArray, + charts: List>, width: Float, height: Float, - color: RGBAColor = RGBAColor.WHITE, labels: ChartMouseLabels? = null, levelLabels: ChartLevelLabels? = null, x: Float = 0f, y: Float = 0f, ) { + require(charts.all { it.first.size == charts[0].first.size }) { "Provided chart data is not of same width" } val builder = BufferBuilder(BYTE_BUFFER_BUILDER, VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR) - val step = width / normalized.size + val step = width / charts[0].first.size val pose = poseStack.last().pose val checkLabels = labels != null && labels.mouseY in 0f .. height && labels.mouseX in 0f .. width @@ -81,40 +110,42 @@ fun renderChart( } } - for (i in 0 until normalized.size - 1) { - val y0 = y + (1f - normalized[i]) * height - val y1 = y + (1f - normalized[i + 1]) * height + for ((normalized, color) in charts) { + for (i in 0 until normalized.size - 1) { + val y0 = y + (1f - normalized[i]) * height + val y1 = y + (1f - normalized[i + 1]) * height - val x0 = x + width - (i + 0.5f) * step - val x1 = x + width - (i + 1.5f) * step + val x0 = x + width - (i + 0.5f) * step + val x1 = x + width - (i + 1.5f) * step - val xDiff = x1 - x0 - val yDiff = y1 - y0 + val xDiff = x1 - x0 + val yDiff = y1 - y0 - if (yDiff.sign == 0f) { - builder.vertex(pose, x0, y0 + LINE_WIDTH / 2f, 0f).color(color) - builder.vertex(pose, x0, y0 - LINE_WIDTH / 2f, 0f).color(color) - builder.vertex(pose, x1, y1 - LINE_WIDTH / 2f, 0f).color(color) - builder.vertex(pose, x1, y1 + LINE_WIDTH / 2f, 0f).color(color) - } else { - val length = (xDiff.pow(2f) + yDiff.pow(2f)).pow(0.5f) - val angle = acos(xDiff / length) * yDiff.sign - PI / 2f // rotate 90 deg + if (yDiff.sign == 0f) { + builder.vertex(pose, x0, y0 + LINE_WIDTH / 2f, 0f).color(color) + builder.vertex(pose, x0, y0 - LINE_WIDTH / 2f, 0f).color(color) + builder.vertex(pose, x1, y1 - LINE_WIDTH / 2f, 0f).color(color) + builder.vertex(pose, x1, y1 + LINE_WIDTH / 2f, 0f).color(color) + } else { + val length = (xDiff.pow(2f) + yDiff.pow(2f)).pow(0.5f) + val angle = acos(xDiff / length) * yDiff.sign - PI / 2f // rotate 90 deg - val xDisp = cos(angle).toFloat() * LINE_WIDTH / 2f - val yDisp = sin(angle).toFloat() * LINE_WIDTH / 2f + val xDisp = cos(angle).toFloat() * LINE_WIDTH / 2f + val yDisp = sin(angle).toFloat() * LINE_WIDTH / 2f - builder.vertex(pose, x0 + xDisp, y0 + yDisp, 0f).color(color) - builder.vertex(pose, x0 - xDisp, y0 - yDisp, 0f).color(color) - builder.vertex(pose, x1 - xDisp, y1 - yDisp, 0f).color(color) - builder.vertex(pose, x1 + xDisp, y1 + yDisp, 0f).color(color) - } + builder.vertex(pose, x0 + xDisp, y0 + yDisp, 0f).color(color) + builder.vertex(pose, x0 - xDisp, y0 - yDisp, 0f).color(color) + builder.vertex(pose, x1 - xDisp, y1 - yDisp, 0f).color(color) + builder.vertex(pose, x1 + xDisp, y1 + yDisp, 0f).color(color) + } - //graphics.renderRect(x0, y0, LINE_WIDTH, LINE_WIDTH) + //graphics.renderRect(x0, y0, LINE_WIDTH, LINE_WIDTH) - if (checkLabels && drawLabel == -1 && labels!!.mouseX in x1 .. x0) { - drawLabel = i - drawPointX = x0 // linearInterpolation(0.5f, x0, x1) - drawPointY = y0 // linearInterpolation(0.5f, y0, y1) + if (checkLabels && drawLabel == -1 && labels!!.mouseX in x1 .. x0) { + drawLabel = i + drawPointX = x0 // linearInterpolation(0.5f, x0, x1) + drawPointY = y0 // linearInterpolation(0.5f, y0, y1) + } } } @@ -130,13 +161,14 @@ fun renderChart( RenderSystem.depthFunc(GL_LESS) if (levelLabels != null && levelLabels.labels.isNotEmpty()) { + val font = levelLabels.font ?: minecraft.font for ((level, label) in levelLabels.labels) { val y0 = y + (1f - level) * height - val tX = x + levelLabels.textGravity.repositionX(width, levelLabels.font.width(label).toFloat()) - 1f - val tY = y0 - LINE_WIDTH - 1f - levelLabels.font.lineHeight + levelLabels.textGravity.repositionY(levelLabels.font.lineHeight * 2f + LINE_WIDTH + 2f, levelLabels.font.lineHeight.toFloat()) + 1f + val tX = x + levelLabels.textGravity.repositionX(width, font.width(label).toFloat()) - 1f + val tY = y0 - LINE_WIDTH - 1f - font.lineHeight + levelLabels.textGravity.repositionY(font.lineHeight * 2f + LINE_WIDTH + 2f, font.lineHeight.toFloat()) + 1f - levelLabels.font.draw( + font.draw( poseStack, label, x = tX, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/MGUIGraphics.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/MGUIGraphics.kt index 6d15bd0d4..ee79d0a17 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/MGUIGraphics.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/MGUIGraphics.kt @@ -1,13 +1,16 @@ package ru.dbotthepony.mc.otm.client.render import com.mojang.blaze3d.vertex.PoseStack +import com.mojang.datafixers.util.Either import net.minecraft.client.gui.Font import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.renderer.MultiBufferSource import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.network.chat.Component +import net.minecraft.network.chat.FormattedText import net.minecraft.resources.ResourceLocation import net.minecraft.util.FormattedCharSequence +import net.minecraft.world.inventory.tooltip.TooltipComponent import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.kommons.math.RGBAColor @@ -78,10 +81,15 @@ class MGUIGraphics(val parent: GuiGraphics) { renderCheckerboard(pose.last().pose(), x, y, width, height, z, color) } - fun renderComponentTooltip(font: Font, lines: MutableList, x: Int, y: Int, itemStack: ItemStack = ItemStack.EMPTY) { + fun renderComponentTooltip(font: Font, lines: List, x: Int, y: Int, itemStack: ItemStack = ItemStack.EMPTY) { parent.renderComponentTooltip(font, lines, x, y, itemStack) } + @JvmName("renderComponentTooltipFromElements") + fun renderComponentTooltip(font: Font, lines: List>, x: Int, y: Int, itemStack: ItemStack = ItemStack.EMPTY) { + parent.renderComponentTooltipFromElements(font, lines, x, y, itemStack) + } + fun flush() { parent.flush() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/DecimalHistoryChartPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/DecimalHistoryChartPanel.kt index 313eacffa..dc45fb2fa 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/DecimalHistoryChartPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/DecimalHistoryChartPanel.kt @@ -58,7 +58,7 @@ open class DecimalHistoryChartPanel>( renderChart( graphics.pose, - normalized, + listOf(normalized to RGBAColor.WHITE), width, height, labels = ChartMouseLabels( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt index 2327d12b6..672c8a8af 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/MatterGaugePanel.kt @@ -4,11 +4,14 @@ import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.BufferUploader import com.mojang.blaze3d.vertex.DefaultVertexFormat import com.mojang.blaze3d.vertex.VertexFormat +import com.mojang.datafixers.util.Either import it.unimi.dsi.fastutil.ints.IntArrayList import net.minecraft.ChatFormatting import net.minecraft.client.gui.screens.Screen import net.minecraft.client.renderer.GameRenderer import net.minecraft.network.chat.Component +import net.minecraft.network.chat.FormattedText +import net.minecraft.world.inventory.tooltip.TooltipComponent import org.lwjgl.opengl.GL11 import ru.dbotthepony.kommons.util.value import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage @@ -52,13 +55,15 @@ open class MatterGaugePanel @JvmOverloads constructor( private var lastDraw = nanoTime private var lastLevel = 0f - protected open fun makeTooltip(): MutableList { + protected open fun makeTooltip(): MutableList> { return mutableListOf( - TranslatableComponent( - "otm.gui.matter.percentage_level", - String.format("%.2f", widget.percentage * 100.0) + Either.left( + TranslatableComponent( + "otm.gui.matter.percentage_level", + String.format("%.2f", widget.percentage * 100.0) + ) ), - formatMatterLevel(widget.level, widget.maxLevel, formatAsReadable = ShiftPressedCond) + Either.left(formatMatterLevel(widget.level, widget.maxLevel, formatAsReadable = ShiftPressedCond)) ) } @@ -145,7 +150,7 @@ open class ProfiledMatterGaugePanel( x: Float = 0f, y: Float = 0f ): MatterGaugePanel(screen, parent, profiledWidget.gauge, x, y) { - override fun makeTooltip(): MutableList { + override fun makeTooltip(): MutableList> { return super.makeTooltip().also { formatHistory( it, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt index 440f741c6..e0a4fbdb6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/widget/PowerGaugePanel.kt @@ -1,7 +1,10 @@ package ru.dbotthepony.mc.otm.client.screen.widget +import com.mojang.datafixers.util.Either import net.minecraft.client.gui.screens.Screen import net.minecraft.network.chat.Component +import net.minecraft.network.chat.FormattedText +import net.minecraft.world.inventory.tooltip.TooltipComponent import ru.dbotthepony.mc.otm.client.render.MGUIGraphics import ru.dbotthepony.mc.otm.client.ShiftPressedCond import ru.dbotthepony.mc.otm.core.TranslatableComponent @@ -25,10 +28,10 @@ open class PowerGaugePanel( scissor = true } - protected open fun makeTooltip(): MutableList { + protected open fun makeTooltip(): MutableList> { return mutableListOf( - TranslatableComponent("otm.gui.power.percentage_level", String.format("%.2f", widget.percentage * 100.0)), - formatPowerLevel(widget.level, widget.maxLevel, formatAsReadable = ShiftPressedCond) + Either.left(TranslatableComponent("otm.gui.power.percentage_level", String.format("%.2f", widget.percentage * 100.0))), + Either.left(formatPowerLevel(widget.level, widget.maxLevel, formatAsReadable = ShiftPressedCond)) ) } @@ -95,7 +98,7 @@ open class ProfiledPowerGaugePanel( width: Float = GAUGE_BACKGROUND.width, height: Float = GAUGE_BACKGROUND.height ) : PowerGaugePanel(screen, parent, profiledWidget.gauge, x, y, width, height) { - override fun makeTooltip(): MutableList { + override fun makeTooltip(): MutableList> { return super.makeTooltip().also { formatHistory( it, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ClientConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ClientConfig.kt index ceef0ed7d..2af9e4458 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ClientConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ClientConfig.kt @@ -48,6 +48,11 @@ object ClientConfig : AbstractConfig("client", ModConfig.Type.CLIENT) { .comment("For those who want it.") .define("REDSTONE_CONTROLS_ITEM_ICONS", false) + var CHARTS_IN_TOOLTIPS: Boolean by builder + .comment("Draw charts in storage tooltips instead of list of last 20 values.") + .comment("Disable to get EnderIO-like experience") + .define("CHARTS_IN_TOOLTIPS", true) + init { builder.pop() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt index 0f21fe07a..d5c4d3865 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Formatting.kt @@ -1,9 +1,17 @@ package ru.dbotthepony.mc.otm.core.util +import com.mojang.datafixers.util.Either import it.unimi.dsi.fastutil.chars.CharArrayList +import it.unimi.dsi.fastutil.floats.Float2ObjectArrayMap import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component +import net.minecraft.network.chat.FormattedText import net.minecraft.network.chat.MutableComponent +import net.minecraft.world.inventory.tooltip.TooltipComponent +import ru.dbotthepony.kommons.math.RGBAColor +import ru.dbotthepony.mc.otm.client.render.ChartLevelLabels +import ru.dbotthepony.mc.otm.client.render.ChartTooltipElement +import ru.dbotthepony.mc.otm.config.ClientConfig import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.Decimal @@ -252,8 +260,179 @@ fun formatTickDuration(ticks: Int, longFormat: Boolean = false): String { } } +/** + * Clientside only function, do not call on shared/server realm. + */ fun formatHistory( - result: MutableList, + result: MutableList>, + widget: ProfiledLevelGaugeWidget<*>, + bias: Int = 0, + decimals: Int = 3, + verbose: BooleanSupplier = never, + suffix: Any = "", +) { + if (!ClientConfig.GUI.CHARTS_IN_TOOLTIPS) { + formatHistoryLines(result, widget, bias, decimals, verbose, suffix) + } else { + formatHistoryChart(result, widget, bias, decimals, verbose, suffix) + } +} + +private fun formatHistoryChart( + result: MutableList>, + widget: ProfiledLevelGaugeWidget<*>, + bias: Int = 0, + decimals: Int = 3, + verbose: BooleanSupplier = never, + suffix: Any = "", +) { + val diff = Array(widget.received.width) { widget.received[it] - widget.transferred[it] } + val normalizedDiff: FloatArray + val received: FloatArray + val transferred: FloatArray + val labels: ChartLevelLabels + + val hasPositiveInfinity = diff.any { it.isInfinite && it.isPositive } + val hasNegativeInfinity = diff.any { it.isInfinite && it.isNegative } + + if (hasPositiveInfinity && hasNegativeInfinity) { + normalizedDiff = FloatArray(diff.size) { + if (widget.received[it].isInfinite && widget.transferred[it].isInfinite) + 0.5f + else if (diff[it].isInfinite && diff[it].isNegative) + 0.1f + else if (diff[it].isInfinite && diff[it].isPositive) + 0.9f + else + 0.5f + } + + received = FloatArray(diff.size) { + if (widget.received[it].isInfinite) 0.9f else 0.5f + } + + transferred = FloatArray(diff.size) { + if (widget.transferred[it].isInfinite) 0.1f else 0.5f + } + + labels = ChartLevelLabels( + labels = mapOf( + 0.5f to Decimal.ZERO.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias), + 0.1f to TextComponent("-∞"), + 0.9f to TextComponent("∞"), + ) + ) + } else if (hasPositiveInfinity) { + normalizedDiff = FloatArray(diff.size) { + if (diff[it].isInfinite) + 0.9f + else + 0.5f + } + + received = FloatArray(diff.size) { + if (widget.received[it].isInfinite) 0.9f else 0.5f + } + + transferred = FloatArray(diff.size) + transferred.fill(0.5f) + + labels = ChartLevelLabels( + labels = mapOf( + 0.5f to Decimal.ZERO.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias), + 0.9f to TextComponent("∞"), + ) + ) + } else if (hasNegativeInfinity) { + normalizedDiff = FloatArray(diff.size) { + if (diff[it].isInfinite) + 0.1f + else + 0.5f + } + + received = FloatArray(diff.size) + received.fill(0.5f) + + transferred = FloatArray(diff.size) { + if (widget.transferred[it].isInfinite) 0.1f else 0.5f + } + + labels = ChartLevelLabels( + labels = mapOf( + 0.5f to Decimal.ZERO.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias), + 0.9f to TextComponent("-∞"), + ) + ) + } else { + val max = maxOf(widget.received.max(), widget.transferred.max()) + val labelNames = Float2ObjectArrayMap() + + labelNames[0.5f] = Decimal.ZERO.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias) + + if (max.isZero) { + normalizedDiff = FloatArray(diff.size) + normalizedDiff.fill(0.5f) + + received = FloatArray(diff.size) + received.fill(0.5f) + + transferred = FloatArray(diff.size) + transferred.fill(0.5f) + + labelNames[0.1f] = TextComponent("-∞") + labelNames[0.9f] = TextComponent("∞") + } else { + normalizedDiff = FloatArray(diff.size) { + (diff[it] / max).toFloat() * 0.4f + 0.5f + } + + received = FloatArray(diff.size) { + (widget.received[it] / max).toFloat() * 0.4f + 0.5f + } + + transferred = FloatArray(diff.size) { + (widget.transferred[it] / max).toFloat() * -0.4f + 0.5f + } + + labelNames[0.1f] = (-max).formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias) + if (verbose.asBoolean) labelNames[0.3f] = (-max * Decimal.ONE_HALF).formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias) + labelNames[0.9f] = max.formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias) + if (verbose.asBoolean) labelNames[0.7f] = (max * Decimal.ONE_HALF).formatSiComponent(suffix, decimals, formatAsReadable = verbose, bias = bias) + } + + labels = ChartLevelLabels(labels = labelNames) + } + + val charts: List> + val receivedActivity = widget.received.any { it.isNotZero } + val transferredActivity = widget.received.any { it.isNotZero } + + if (!receivedActivity && transferredActivity) { + charts = listOf( + received to RGBAColor.YELLOW, + normalizedDiff to RGBAColor.WHITE, + transferred to RGBAColor.RED, + ) + } else if (!transferredActivity && receivedActivity) { + charts = listOf( + transferred to RGBAColor.RED, + normalizedDiff to RGBAColor.WHITE, + received to RGBAColor.YELLOW, + ) + } else { + charts = listOf( + received to RGBAColor.YELLOW, + transferred to RGBAColor.RED, + normalizedDiff to RGBAColor.WHITE, + ) + } + + result.add(Either.right(ChartTooltipElement(charts, if (verbose.asBoolean) 200f else 100f, if (verbose.asBoolean) 120f else 60f, levelLabels = labels))) +} + +private fun formatHistoryLines( + result: MutableList>, widget: ProfiledLevelGaugeWidget<*>, bias: Int = 0, decimals: Int = 3, @@ -321,13 +500,13 @@ fun formatHistory( ) } - result.add(TextComponent("")) - result.add(lines.removeFirst().format()) + result.add(Either.left(TextComponent(""))) + result.add(Either.left(lines.removeFirst().format())) if (verbose.asBoolean) { - result.add(TextComponent("---")) - result.add(lines.removeFirst().format()) - result.add(TextComponent("---")) - lines.forEach { result.add(it.format()) } + result.add(Either.left(TextComponent("---"))) + result.add(Either.left(lines.removeFirst().format())) + result.add(Either.left(TextComponent("---"))) + lines.forEach { result.add(Either.left(it.format())) } } }