Skip to content

Commit 25aa23e

Browse files
committed
added formatting setting groups
1 parent e5cc50c commit 25aa23e

File tree

3 files changed

+204
-21
lines changed

3 files changed

+204
-21
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.config.groups
19+
20+
import com.lambda.util.Describable
21+
import com.lambda.util.NamedEnum
22+
import java.time.format.DateTimeFormatter
23+
import java.util.Locale
24+
25+
interface FormatterConfig {
26+
val locale: Locale
27+
val separator: String
28+
val prefix: String
29+
val postfix: String
30+
val precision: Int
31+
val format: DateTimeFormatter
32+
33+
enum class Locales(
34+
override val displayName: String,
35+
override val description: String,
36+
val locale: Locale,
37+
) : NamedEnum, Describable {
38+
France("France", "Numbers are formatted using a space as the thousands separator and a comma as the decimal separator", Locale.FRANCE),
39+
Germany("Germany", "Numbers are formatted using a dot as the thousands separator and a comma as the decimal separator", Locale.GERMANY),
40+
Italy("Italy", "Numbers are formatted using a comma as the thousands separator and a comma as the decimal separator", Locale.ITALY),
41+
Japan("Japan", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.JAPAN),
42+
Korea("Korea", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.KOREA),
43+
UK("United Kingdom", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.UK),
44+
US("United States", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.US),
45+
Canada("Canada", "Numbers are formatted using a comma as the thousands separator and a dot as the decimal separator", Locale.CANADA),
46+
Quebec("Québec", "Numbers are formatted using a space as the thousands separator and a comma as the decimal separator", Locale.CANADA_FRENCH); // this the best one :3
47+
}
48+
49+
enum class Time(
50+
override val displayName: String,
51+
override val description: String,
52+
val format: DateTimeFormatter,
53+
) : NamedEnum, Describable {
54+
IsoLocalDate("ISO-8601 Extended", "The ISO date formatter that formats or parses a date without an offset, such as '2011-12-03'", DateTimeFormatter.ISO_LOCAL_DATE),
55+
IsoOffsetDate("ISO-8601 Offset", "The ISO date formatter that formats or parses a date with an offset, such as '2011-12-03+01:00'", DateTimeFormatter.ISO_OFFSET_DATE),
56+
IsoDate("ISO-8601 Date", "The ISO date formatter that formats or parses a date with the offset if available, such as '2011-12-03' or '2011-12-03+01:00'", DateTimeFormatter.ISO_DATE),
57+
IsoLocalTime("ISO-8601 Local Time", "The ISO time formatter that formats or parses a time without an offset, such as '10:15' or '10:15:30'", DateTimeFormatter.ISO_LOCAL_TIME),
58+
IsoOffsetTime("ISO-8601 Offset Time", "The ISO time formatter that formats or parses a time with an offset, such as '10:15+01:00' or '10:15:30+01:00'", DateTimeFormatter.ISO_OFFSET_TIME),
59+
IsoTime("ISO-8601 Time", "The ISO time formatter that formats or parses a time, with the offset if available, such as '10:15', '10:15:30' or '10:15:30+01:00'", DateTimeFormatter.ISO_TIME),
60+
IsoLocalDateTime("ISO-8601 Local Date Time", "The ISO date-time formatter that formats or parses a date-time without an offset, such as '2011-12-03T10:15:30'", DateTimeFormatter.ISO_LOCAL_DATE_TIME),
61+
IsoOffsetDateTime("ISO-8601 Offset Date Time", "The ISO date-time formatter that formats or parses a date-time with an offset, such as '2011-12-03T10:15:30+01:00'", DateTimeFormatter.ISO_OFFSET_DATE_TIME),
62+
IsoZonedDateTime("ISO-8601 Zoned Date Time", "The ISO-like date-time formatter that formats or parses a date-time with offset and zone, such as '2011-12-03T10:15:30+01:00[Europe/Paris]'", DateTimeFormatter.ISO_ZONED_DATE_TIME),
63+
IsoDateTime("ISO-8601 Date Time", "The ISO-like date-time formatter that formats or parses a date-time with the offset and zone if available, such as '2011-12-03T10:15:30', '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'", DateTimeFormatter.ISO_DATE_TIME),
64+
IsoOrdinalDate("ISO-8601 Ordinal Date", "The ISO date formatter that formats or parses the ordinal date without an offset, such as '2012-337'", DateTimeFormatter.ISO_ORDINAL_DATE),
65+
IsoWeekDate("ISO-8601 Week Date", "The ISO date formatter that formats or parses the week-based date without an offset, such as '2012-W48-6'", DateTimeFormatter.ISO_WEEK_DATE),
66+
IsoInstant("ISO-8601 Instant", "The ISO instant formatter that formats or parses an instant in UTC, such as '2011-12-03T10:15:30Z'", DateTimeFormatter.ISO_INSTANT),
67+
BasicIsoDate("ISO 8601", "The ISO date formatter that formats or parses a date without an offset, such as '20111203'", DateTimeFormatter.BASIC_ISO_DATE),
68+
Rfc1123("RFC 1123", "The RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'", DateTimeFormatter.RFC_1123_DATE_TIME);
69+
}
70+
71+
// For context, a tuple is an ordered list of identical value types such as a vec3d which is a tuple of doubles
72+
enum class TupleSeparator(
73+
override val displayName: String,
74+
val separator: String,
75+
) : NamedEnum {
76+
Comma("Comma", ", "),
77+
Dot("Dot", ". "),
78+
Semicolon("Semicolon", "; "),
79+
VerticalBar("Vertical Bar", "| "),
80+
Space("Space", " "),
81+
Custom("Custom", ":3c");
82+
}
83+
84+
enum class TupleGrouping(
85+
override val displayName: String,
86+
val prefix: String,
87+
val postfix: String,
88+
) : NamedEnum {
89+
Parentheses("Parenthesis", "(", ")"),
90+
SquareBrackets("Square Brackets", "[", "]"),
91+
CurlyBrackets("Curly Brackets", "{", "}"),
92+
VerticalBar("Vertical Bar", "|", "|");
93+
}
94+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.config.groups
19+
20+
import com.lambda.config.Configurable
21+
import com.lambda.util.NamedEnum
22+
import com.lambda.util.math.Vec2d
23+
import net.minecraft.util.math.Vec2f
24+
import net.minecraft.util.math.Vec3d
25+
import net.minecraft.util.math.Vec3i
26+
import org.joml.Vector3f
27+
import org.joml.Vector4f
28+
import java.time.LocalDate
29+
import java.time.LocalDateTime
30+
import java.time.ZonedDateTime
31+
32+
class FormatterSettings(
33+
owner: Configurable,
34+
vararg baseGroup: NamedEnum,
35+
vis: () -> Boolean = { true }
36+
) : FormatterConfig, SettingGroup(owner) {
37+
val localeEnum by owner.setting("Locale", FormatterConfig.Locales.US, "The regional formatting used for numbers", vis).group(*baseGroup)
38+
override val locale get() = localeEnum.locale
39+
40+
val sep by owner.setting("Separator", FormatterConfig.TupleSeparator.Comma, "Separator for string serialization of tuple data structures", vis).group(*baseGroup)
41+
val customSep by owner.setting("Custom Separator", "") { vis() && sep == FormatterConfig.TupleSeparator.Custom }.group(*baseGroup)
42+
override val separator get() = if (sep == FormatterConfig.TupleSeparator.Custom) customSep else sep.separator
43+
44+
val group by owner.setting("Tuple Prefix", FormatterConfig.TupleGrouping.Parentheses) { vis() }.group(*baseGroup)
45+
override val prefix get() = group.prefix
46+
override val postfix get() = group.postfix
47+
48+
val floatingPrecision by owner.setting("Floating Precision", 3, 0..6, 1, "Precision for floating point numbers") { vis() }.group(*baseGroup)
49+
override val precision get() = floatingPrecision
50+
51+
val timeFormat by owner.setting("Time Format", FormatterConfig.Time.IsoDateTime) { vis() }.group(*baseGroup)
52+
override val format get() = timeFormat.format
53+
54+
infix fun format(value: Short) = "%d".format(locale, value)
55+
infix fun format(value: Int) = "%d".format(locale, value)
56+
infix fun format(value: Long) = "%d".format(locale, value)
57+
infix fun format(value: Float) = "%,.${precision}f".format(locale, value)
58+
infix fun format(value: Double) = "%,.${precision}f".format(locale, value)
59+
60+
infix fun format(tuple: Vec2f) = "$prefix${format(tuple.x)}$separator${format(tuple.y)}$postfix"
61+
infix fun format(tuple: Vec2d) = "$prefix${format(tuple.x)}$separator${format(tuple.y)}$postfix"
62+
infix fun format(tuple: Vec3i) = "$prefix${format(tuple.x)}$separator${format(tuple.y)}$separator${format(tuple.z)}$postfix"
63+
infix fun format(tuple: Vec3d) = "$prefix${format(tuple.x)}$separator${format(tuple.y)}$separator${format(tuple.z)}$postfix"
64+
infix fun format(tuple: Vector3f) = "$prefix${format(tuple.x)}$separator${format(tuple.y)}$separator${format(tuple.z)}$postfix"
65+
infix fun format(tuple: Vector4f) = "$prefix${format(tuple.x)}$separator${format(tuple.y)}$separator${format(tuple.z)}$separator${format(tuple.w)}$postfix"
66+
67+
infix fun format(tuple: ShortArray) = tuple.joinToString(separator, prefix, postfix) { format(it) }
68+
infix fun format(tuple: IntArray) = tuple.joinToString(separator, prefix, postfix) { format(it) }
69+
infix fun format(tuple: LongArray) = tuple.joinToString(separator, prefix, postfix) { format(it) }
70+
infix fun format(tuple: FloatArray) = tuple.joinToString(separator, prefix, postfix) { format(it) }
71+
infix fun format(tuple: DoubleArray) = tuple.joinToString(separator, prefix, postfix) { format(it) }
72+
73+
@JvmName("formatVec2fList") infix fun format(tuple: List<Vec2f>) = tuple.joinToString(separator, prefix, postfix) { format(it) }
74+
@JvmName("formatVec2dList") infix fun format(tuple: List<Vec2d>) = tuple.joinToString(separator, prefix, postfix) { format(it) }
75+
@JvmName("formatVec3iList") infix fun format(tuple: List<Vec3i>) = tuple.joinToString(separator, prefix, postfix) { format(it) }
76+
@JvmName("formatVec3dList") infix fun format(tuple: List<Vec3d>) = tuple.joinToString(separator, prefix, postfix) { format(it) }
77+
@JvmName("formatVector3fList") infix fun format(tuple: List<Vector3f>) = tuple.joinToString(separator, prefix, postfix) { format(it) }
78+
@JvmName("formatVector4fList") infix fun format(tuple: List<Vector4f>) = tuple.joinToString(separator, prefix, postfix) { format(it) }
79+
80+
infix fun format(time: LocalDate): String = time.format(format)
81+
infix fun format(time: LocalDateTime): String = time.format(format)
82+
infix fun format(time: ZonedDateTime): String = time.format(format)
83+
}

src/main/kotlin/com/lambda/module/hud/Coordinates.kt

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,18 @@
1717

1818
package com.lambda.module.hud
1919

20+
import com.lambda.config.groups.FormatterConfig
21+
import com.lambda.config.groups.FormatterSettings
2022
import com.lambda.gui.dsl.ImGuiBuilder
2123
import com.lambda.module.HudModule
2224
import com.lambda.module.tag.ModuleTag
2325
import com.lambda.threading.runSafe
2426
import com.lambda.util.Formatting.asString
27+
import com.lambda.util.NamedEnum
2528
import com.lambda.util.extension.dimensionName
2629
import com.lambda.util.extension.isNether
30+
import com.lambda.util.extension.isOverworld
31+
import com.lambda.util.math.Vec2d
2732
import com.lambda.util.math.netherCoord
2833
import com.lambda.util.math.overworldCoord
2934
import java.util.Locale
@@ -33,33 +38,34 @@ object Coordinates : HudModule(
3338
description = "Show your coordinates",
3439
tag = ModuleTag.HUD,
3540
) {
41+
private val page by setting("Page", Page.CurrentDimension)
3642
private val showDimension by setting("Show Dimension", true)
37-
private val decimals by setting("Decimals", 2, 0..4, 1)
38-
private val groupingStyle by setting("Grouping", Grouping.Comma)
39-
private val coordinateSeparator by setting("Coordinate Separator", " | ")
43+
44+
private val formatter = FormatterSettings(this, Page.CurrentDimension).apply { ::timeFormat.edit { hide() } }
45+
private val otherFormatter = FormatterSettings(this, Page.OtherDimension).apply {
46+
::timeFormat.edit { hide() }
47+
::group.edit { defaultValue(FormatterConfig.TupleGrouping.SquareBrackets) }
48+
}
4049

4150
override fun ImGuiBuilder.buildLayout() {
4251
runSafe {
43-
// TODO: Properly localize based on user settings. Waiting on you emy_fops
44-
val locale = when (groupingStyle) {
45-
Grouping.Comma, Grouping.None -> Locale.US
46-
Grouping.Dot -> Locale.GERMANY
47-
}
48-
val numberGrouping = groupingStyle != Grouping.None
49-
val pos = "${player.pos.x.asString(decimals, locale, numberGrouping)}$coordinateSeparator${player.pos.y.asString(decimals, locale, numberGrouping)}$coordinateSeparator${player.pos.z.asString(decimals, locale, numberGrouping)}"
50-
val coord = if (world.isNether) {
51-
"$pos [${player.overworldCoord.x.asString(decimals, locale, numberGrouping)}$coordinateSeparator${player.overworldCoord.z.asString(decimals, locale, numberGrouping)}]"
52-
} else {
53-
"$pos [${player.netherCoord.x.asString(decimals, locale, numberGrouping)}$coordinateSeparator${player.netherCoord.z.asString(decimals, locale, numberGrouping)}]"
54-
}
55-
val dimension = if (showDimension) " ${world.dimensionName}" else ""
56-
textCopyable("$coord$dimension")
52+
val position = formatter.format(player.pos)
53+
val otherDimensionPos =
54+
if (world.isNether) otherFormatter.format(player.overworldCoord.let { Vec2d(it.x, it.z) })
55+
else otherFormatter.format(player.netherCoord.let { Vec2d(it.x, it.z) })
56+
57+
val text = "$position $otherDimensionPos"
58+
59+
val withDimension =
60+
if (showDimension) "$text ${world.dimensionName}"
61+
else text
62+
63+
textCopyable(withDimension)
5764
}
5865
}
5966

60-
enum class Grouping {
61-
Comma,
62-
Dot,
63-
None
67+
enum class Page(override val displayName: String) : NamedEnum {
68+
CurrentDimension("Current Dimension"),
69+
OtherDimension("Other Dimension"),
6470
}
6571
}

0 commit comments

Comments
 (0)