Skip to content

Commit dfeb103

Browse files
authored
Textfield number input fixes. (#131)
1 parent 5e814d9 commit dfeb103

10 files changed

Lines changed: 443 additions & 109 deletions

File tree

src/main/java/com/cleanroommc/modularui/test/ItemEditorGui.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public ModularPanel buildUI(GuiData data, PanelSyncManager syncManager, UISettin
8484
if (!syncManager.isClient())
8585
getStack().setItemDamage(val);
8686
}))
87-
.setNumbers(0, Short.MAX_VALUE - 1))
87+
.numbersInt(0, Short.MAX_VALUE - 1))
8888
.child(IKey.str(" Amount: ").asWidget())
8989
.child(new TextFieldWidget()
9090
.size(30, 16)
@@ -95,7 +95,7 @@ public ModularPanel buildUI(GuiData data, PanelSyncManager syncManager, UISettin
9595
if (!syncManager.isClient())
9696
getStack().stackSize = value;
9797
}))
98-
.setNumbers(1, 127)))
98+
.numbersInt(1, 127)))
9999
.child(new TextFieldWidget()
100100
.height(20)
101101
.widthRel(1f)

src/main/java/com/cleanroommc/modularui/test/TestGuis.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,30 @@ public static ModularPanel buildContextMenu() {
737737
.name("side_options"));
738738
}
739739

740+
public static @NotNull ModularPanel buildTextFieldUI() {
741+
return new ModularPanel("text_fields")
742+
.coverChildrenHeight()
743+
.width(120)
744+
.padding(7)
745+
.child(Flow.col()
746+
.coverChildrenHeight()
747+
.childPadding(2)
748+
.crossAxisAlignment(Alignment.CrossAxis.START)
749+
.fullWidth()
750+
.child(IKey.str("Any").asWidget())
751+
.child(new TextFieldWidget().fullWidth())
752+
.child(IKey.str("Decimal numbers").asWidget())
753+
.child(new TextFieldWidget()
754+
.fullWidth()
755+
.numbersDouble(-1000, 1000)
756+
.usingScrollStep())
757+
.child(IKey.str("Whole numbers").asWidget())
758+
.child(new TextFieldWidget()
759+
.fullWidth()
760+
.numbersLong(-100_000_000_000_000L, 100_000_000_000_000L)
761+
.usingScrollStep()));
762+
}
763+
740764
private static Rectangle rndRect(IntList colors, Random random) {
741765
int i = random.nextInt(colors.size());
742766
int c = colors.removeInt(i);

src/main/java/com/cleanroommc/modularui/utils/DAM.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,21 +408,29 @@ public static double[] flatten(double[]... src) {
408408

409409
public interface UnaryDoubleOperator {
410410

411+
UnaryDoubleOperator IDENTITY = v -> v;
412+
411413
double apply(double v);
412414
}
413415

414416
public interface BinaryDoubleOperator {
415417

418+
BinaryDoubleOperator IDENTITY = (v, op) -> v;
419+
416420
double apply(double v, double op);
417421
}
418422

419423
public interface TernaryDoubleOperator {
420424

425+
TernaryDoubleOperator IDENTITY = (v, op1, op2) -> v;
426+
421427
double apply(double v, double op1, double op2);
422428
}
423429

424430
public interface NDoubleOperator {
425431

432+
NDoubleOperator IDENTITY = (v, op) -> v;
433+
426434
double apply(double v, double[] op);
427435
}
428436
}

src/main/java/com/cleanroommc/modularui/utils/MathUtils.java

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package com.cleanroommc.modularui.utils;
22

3+
import com.cleanroommc.modularui.utils.math.CustomDataAccessor;
34
import com.cleanroommc.modularui.utils.math.PostfixPercentOperator;
45

6+
import com.cleanroommc.modularui.widgets.textfield.INumberParser;
7+
8+
import com.google.common.math.LongMath;
9+
510
import net.minecraft.util.MathHelper;
611

712
import com.ezylang.evalex.BaseException;
@@ -11,6 +16,7 @@
1116
import org.apache.commons.lang3.tuple.Pair;
1217

1318
import java.math.BigDecimal;
19+
import java.util.function.LongSupplier;
1420

1521
public class MathUtils {
1622

@@ -23,30 +29,50 @@ public class MathUtils {
2329
.arraysAllowed(false)
2430
.structuresAllowed(false)
2531
.stripTrailingZeros(true)
32+
.allowOverwriteConstants(true)
33+
.dataAccessorSupplier(() -> new CustomDataAccessor(false))
2634
.build()
2735
.withAdditionalOperators(Pair.of("%", new PostfixPercentOperator()));
2836

29-
public static ParseResult parseExpression(String expression) {
30-
return parseExpression(expression, Double.NaN, false);
31-
}
37+
public static final ExpressionConfiguration MATH_CFG_CASE_SENSITIVE = MATH_CFG.toBuilder()
38+
.dataAccessorSupplier(() -> new CustomDataAccessor(true))
39+
.build();
3240

33-
public static ParseResult parseExpression(String expression, boolean useSiPrefixes) {
34-
return parseExpression(expression, Double.NaN, useSiPrefixes);
35-
}
41+
public static final INumberParser PARSER_WITH_SI = MathUtils::parseExpression;
42+
public static final INumberParser PARSER_WHOLE_NUMBER = MathUtils::parseExpressionWholeNumber;
3643

3744
public static ParseResult parseExpression(String expression, double defaultValue) {
38-
return parseExpression(expression, defaultValue, true);
45+
return parseExpression(expression, defaultValue, true, false);
3946
}
4047

41-
public static ParseResult parseExpression(String expression, double defaultValue, boolean useSiPrefixes) {
48+
public static ParseResult parseExpression(String expression, double defaultValue, boolean useSiPrefixes, boolean biggerThanOne) {
4249
if (expression == null || expression.isEmpty()) {
4350
return ParseResult.success(EvaluationValue.numberValue(new BigDecimal(defaultValue)));
4451
}
4552

46-
Expression e = new Expression(expression, MATH_CFG);
53+
Expression e = new Expression(expression, MATH_CFG_CASE_SENSITIVE);
4754
if (useSiPrefixes) {
48-
SIPrefix.addAllToExpression(e);
55+
SIPrefix.addAllToExpression(e, biggerThanOne);
56+
}
57+
try {
58+
return ParseResult.success(e.evaluate());
59+
} catch (BaseException exception) {
60+
return ParseResult.failure(exception);
4961
}
62+
}
63+
64+
public static ParseResult parseExpressionWholeNumber(String expression, double defaultValue) {
65+
if (expression == null || expression.isEmpty()) {
66+
return ParseResult.success(EvaluationValue.numberValue(new BigDecimal(defaultValue)));
67+
}
68+
69+
Expression e = new Expression(expression, MATH_CFG);
70+
SIPrefix.Kilo.addToExpression(e);
71+
SIPrefix.Mega.addToExpression(e);
72+
SIPrefix.Giga.addToExpression(e, "b");
73+
SIPrefix.Tera.addToExpression(e);
74+
e.with("i", 144); // ingot
75+
e.with("s", 64); // stack
5076
try {
5177
return ParseResult.success(e.evaluate());
5278
} catch (BaseException exception) {
@@ -220,4 +246,46 @@ public static int intPlaces(double x) {
220246
if (Math.pow(10, d - 1) > x) d--;
221247
return Math.max(d, 1);
222248
}
249+
250+
public static boolean areBothSmallerOrBiggerThanOne(double a, double b) {
251+
return a > 1 ? b > 1 : b <= 1;
252+
}
253+
254+
public static long percentOrSelf(double value, long maxValue) {
255+
long rounded = Math.round(value);
256+
if (value > 1 || Math.abs(value - rounded) < 0.0000001) return rounded;
257+
return Math.round(value * maxValue);
258+
}
259+
260+
public static int castToIntSaturated(long l) {
261+
if (l >= Integer.MAX_VALUE) return Integer.MAX_VALUE;
262+
if (l <= Integer.MIN_VALUE) return Integer.MIN_VALUE;
263+
return (int) l;
264+
}
265+
266+
public static short castToShortSaturated(long l) {
267+
if (l >= Short.MAX_VALUE) return Short.MAX_VALUE;
268+
if (l <= Short.MIN_VALUE) return Short.MIN_VALUE;
269+
return (short) l;
270+
}
271+
272+
public static byte castToByteSaturated(long l) {
273+
if (l >= Byte.MAX_VALUE) return Byte.MAX_VALUE;
274+
if (l <= Byte.MIN_VALUE) return Byte.MIN_VALUE;
275+
return (byte) l;
276+
}
277+
278+
public interface UnaryLongOperator {
279+
280+
UnaryLongOperator IDENTITY = v -> v;
281+
282+
long apply(long l);
283+
}
284+
285+
public interface UnaryIntOperator {
286+
287+
UnaryIntOperator IDENTITY = v -> v;
288+
289+
int apply(int l);
290+
}
223291
}

src/main/java/com/cleanroommc/modularui/utils/SIPrefix.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ public void addToExpression(Expression e) {
7070
e.with(String.valueOf(this.symbol), this.factor);
7171
}
7272

73+
public void addToExpression(Expression e, String alternativeSymbol) {
74+
addToExpression(e);
75+
e.with(alternativeSymbol, this.factor);
76+
}
77+
7378
public static final SIPrefix[] VALUES = values();
7479
public static final SIPrefix[] HIGH = new SIPrefix[values().length / 2];
7580
public static final SIPrefix[] LOW = new SIPrefix[values().length / 2];
@@ -82,8 +87,9 @@ public void addToExpression(Expression e) {
8287
}
8388
}
8489

85-
public static void addAllToExpression(Expression e) {
90+
public static void addAllToExpression(Expression e, boolean biggerThanOne) {
8691
for (SIPrefix siPrefix : VALUES) {
92+
if (siPrefix == One || siPrefix.infiniteLike || (biggerThanOne && siPrefix.factor < 1)) continue;
8793
siPrefix.addToExpression(e);
8894
}
8995
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.cleanroommc.modularui.utils.math;
2+
3+
import com.ezylang.evalex.data.DataAccessorIfc;
4+
import com.ezylang.evalex.data.EvaluationValue;
5+
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
6+
7+
import java.util.Locale;
8+
import java.util.Map;
9+
10+
public class CustomDataAccessor implements DataAccessorIfc {
11+
12+
private final Map<String, EvaluationValue> map = new Object2ObjectOpenHashMap<>();
13+
private final boolean caseSensitive;
14+
15+
public CustomDataAccessor(boolean caseSensitive) {
16+
this.caseSensitive = caseSensitive;
17+
}
18+
19+
public boolean isCaseSensitive() {
20+
return caseSensitive;
21+
}
22+
23+
@Override
24+
public EvaluationValue getData(String variable) {
25+
if (this.caseSensitive) {
26+
return this.map.get(variable);
27+
}
28+
return this.map.get(variable.toLowerCase(Locale.ROOT));
29+
}
30+
31+
@Override
32+
public void setData(String variable, EvaluationValue value) {
33+
if (this.caseSensitive) {
34+
this.map.put(variable, value);
35+
} else {
36+
this.map.put(variable, value);
37+
String lower = variable.toLowerCase(Locale.ROOT);
38+
if (!lower.equals(variable)) {
39+
this.map.put(lower, value);
40+
}
41+
String upper = variable.toUpperCase(Locale.ROOT);
42+
if (!upper.equals(variable)) {
43+
this.map.put(upper, value);
44+
}
45+
}
46+
}
47+
}

src/main/java/com/cleanroommc/modularui/widgets/textfield/BaseTextFieldWidget.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,19 @@ public void onMouseDrag(int mouseButton, long timeSinceClick) {
258258
this.handler.moveCursorDown(Interactable.hasControlDown(), Interactable.hasShiftDown());
259259
return Result.SUCCESS;
260260
}
261+
case Keyboard.KEY_HOME: {
262+
this.handler.moveCursorStart(Interactable.hasControlDown(), Interactable.hasShiftDown());
263+
return Result.SUCCESS;
264+
}
265+
case Keyboard.KEY_END: {
266+
this.handler.moveCursorEnd(Interactable.hasControlDown(), Interactable.hasShiftDown());
267+
return Result.SUCCESS;
268+
}
261269
case Keyboard.KEY_DELETE:
262-
this.handler.delete(true);
270+
this.handler.delete(true, Interactable.hasControlDown(), Interactable.hasShiftDown());
263271
return Result.SUCCESS;
264272
case Keyboard.KEY_BACK:
265-
this.handler.delete();
273+
this.handler.delete(Interactable.hasControlDown(), Interactable.hasShiftDown());
266274
return Result.SUCCESS;
267275
}
268276

@@ -275,16 +283,14 @@ public void onMouseDrag(int mouseButton, long timeSinceClick) {
275283
GuiScreen.setClipboardString(this.handler.getSelectedText());
276284
return Result.SUCCESS;
277285
} else if (Interactable.isKeyComboCtrlV(keyCode)) {
278-
if (this.handler.hasTextMarked()) {
279-
this.handler.delete();
280-
}
286+
this.handler.deleteMarked();
281287
// paste copied text in marked text
282288
this.handler.insert(GuiScreen.getClipboardString().replace("§", ""), canScrollHorizontally());
283289
return Result.SUCCESS;
284290
} else if (Interactable.isKeyComboCtrlX(keyCode) && this.handler.hasTextMarked()) {
285291
// copy and delete copied text
286292
GuiScreen.setClipboardString(this.handler.getSelectedText());
287-
this.handler.delete();
293+
this.handler.deleteMarked();
288294
return Result.SUCCESS;
289295
} else if (Interactable.isKeyComboCtrlA(keyCode)) {
290296
// mark whole text
@@ -295,9 +301,7 @@ public void onMouseDrag(int mouseButton, long timeSinceClick) {
295301
if (ModularUI.Mods.LWJGL3IFY.isLoaded()) {
296302
return Result.SUCCESS;
297303
}
298-
if (this.handler.hasTextMarked()) {
299-
this.handler.delete();
300-
}
304+
this.handler.deleteMarked();
301305
// insert typed char
302306
this.handler.insert(String.valueOf(character), canScrollHorizontally());
303307
return Result.SUCCESS;
@@ -320,9 +324,7 @@ public boolean onTextInput(InputEvents.TextEvent event) {
320324
}
321325
String t = event.text.replaceAll("§", "");
322326
if (!t.isEmpty() && handler.test(t)) {
323-
if (this.handler.hasTextMarked()) {
324-
this.handler.delete();
325-
}
327+
this.handler.deleteMarked();
326328
// insert typed char
327329
this.handler.insert(t, canScrollHorizontally());
328330
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.cleanroommc.modularui.widgets.textfield;
2+
3+
import com.cleanroommc.modularui.utils.ParseResult;
4+
5+
public interface INumberParser {
6+
7+
ParseResult parse(String expr, double defaultValue);
8+
}

0 commit comments

Comments
 (0)