mirror of
https://github.com/aNNiMON/HotaruFX.git
synced 2024-09-19 14:14:21 +03:00
Update to run on Java 11 with OpenJFX
Removed lombok
This commit is contained in:
parent
eb6bf422cc
commit
93e7a87c03
@ -1,26 +1,33 @@
|
||||
plugins {
|
||||
id 'com.github.johnrengelman.shadow' version '2.0.1'
|
||||
id 'java'
|
||||
id 'application'
|
||||
id "com.github.johnrengelman.shadow" version "5.1.0"
|
||||
id 'org.openjfx.javafxplugin' version '0.0.8'
|
||||
}
|
||||
|
||||
group 'HotaruFX'
|
||||
version '0.9.1'
|
||||
version '1.0.0'
|
||||
mainClassName = 'com.annimon.hotarufx.Main'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
sourceCompatibility = 11
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
javafx {
|
||||
version = "11"
|
||||
modules = ['javafx.controls', 'javafx.fxml', "javafx.swing"]
|
||||
}
|
||||
|
||||
ext.junit5Version = '5.5.2'
|
||||
|
||||
dependencies {
|
||||
implementation 'org.fxmisc.richtext:richtextfx:0.6.10'
|
||||
compileOnly 'org.projectlombok:lombok:1.16.18'
|
||||
testCompileOnly 'org.projectlombok:lombok:1.16.18'
|
||||
testRuntime 'org.junit.platform:junit-platform-launcher:1.0.0'
|
||||
testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.0.0'
|
||||
testRuntime 'org.junit.vintage:junit-vintage-engine:4.12.0'
|
||||
testRuntime 'org.junit.jupiter:junit-jupiter-params:5.0.0'
|
||||
implementation 'org.fxmisc.richtext:richtextfx:0.10.2'
|
||||
testRuntime 'org.junit.platform:junit-platform-launcher:1.5.2'
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junit5Version"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params:$junit5Version"
|
||||
testRuntime "org.junit.jupiter:junit-jupiter-engine:$junit5Version"
|
||||
testRuntime "org.junit.vintage:junit-vintage-engine:$junit5Version"
|
||||
testImplementation 'org.hamcrest:hamcrest-library:1.3'
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.stage.Stage;
|
||||
import lombok.val;
|
||||
|
||||
public class Main extends Application {
|
||||
|
||||
@ -20,8 +19,8 @@ public class Main extends Application {
|
||||
ClickableHyperLink.setHostServices(getHostServices());
|
||||
primaryStage.setTitle("HotaruFX");
|
||||
try {
|
||||
val loader = new FXMLLoader(getClass().getResource("/fxml/Editor.fxml"));
|
||||
val scene = new Scene(loader.load());
|
||||
final var loader = new FXMLLoader(getClass().getResource("/fxml/Editor.fxml"));
|
||||
final var scene = new Scene(loader.load());
|
||||
scene.getStylesheets().addAll(
|
||||
getClass().getResource("/styles/theme-dark.css").toExternalForm(),
|
||||
getClass().getResource("/styles/codearea.css").toExternalForm(),
|
||||
@ -33,7 +32,7 @@ public class Main extends Application {
|
||||
primaryStage.setOnCloseRequest(controller::onCloseRequest);
|
||||
primaryStage.setScene(scene);
|
||||
} catch (IOException ex) {
|
||||
val text = new TextArea(Exceptions.stackTraceToString(ex));
|
||||
final var text = new TextArea(Exceptions.stackTraceToString(ex));
|
||||
text.setEditable(false);
|
||||
primaryStage.setScene(new Scene(text));
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package com.annimon.hotarufx.bundles;
|
||||
|
||||
import com.annimon.hotarufx.lib.Context;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import lombok.val;
|
||||
|
||||
public final class BundleLoader {
|
||||
|
||||
@ -26,7 +26,7 @@ public final class BundleLoader {
|
||||
}
|
||||
|
||||
public static Map<String, FunctionType> functions() {
|
||||
val functions = new HashMap<String, FunctionType>();
|
||||
final var functions = new HashMap<String, FunctionType>();
|
||||
apply(runtimeBundles(), functions, ((bundle, map) -> map.putAll(bundle.functions())));
|
||||
return functions;
|
||||
}
|
||||
@ -43,9 +43,11 @@ public final class BundleLoader {
|
||||
|
||||
for (Class<? extends Bundle> clazz : bundles) {
|
||||
try {
|
||||
val bundle = clazz.newInstance();
|
||||
final var ctor = clazz.getDeclaredConstructor();
|
||||
final var bundle = ctor.newInstance();
|
||||
action.accept(bundle, obj);
|
||||
} catch (IllegalAccessException | InstantiationException ignore) {}
|
||||
} catch (IllegalAccessException | InstantiationException
|
||||
| NoSuchMethodException | InvocationTargetException ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javafx.scene.paint.Paint;
|
||||
import lombok.val;
|
||||
import static com.annimon.hotarufx.bundles.FunctionInfo.of;
|
||||
import static com.annimon.hotarufx.bundles.FunctionType.COMMON;
|
||||
|
||||
@ -57,11 +56,11 @@ public class CompositionBundle implements Bundle {
|
||||
width = args[0].asInt();
|
||||
height = args[1].asInt();
|
||||
frameRate = args[2].asDouble();
|
||||
val background = PropertyType.PAINT.<Paint>getFromHFX().apply(args[3]);
|
||||
final var background = PropertyType.PAINT.<Paint>getFromHFX().apply(args[3]);
|
||||
composition = new Composition(width, height, frameRate, background);
|
||||
break;
|
||||
}
|
||||
val scene = composition.getScene();
|
||||
final var scene = composition.getScene();
|
||||
context.composition(composition);
|
||||
context.variables().put("Width", NumberValue.of(scene.getVirtualWidth()));
|
||||
context.variables().put("Height", NumberValue.of(scene.getVirtualHeight()));
|
||||
@ -73,8 +72,8 @@ public class CompositionBundle implements Bundle {
|
||||
|
||||
private static Function render(Context context) {
|
||||
return args -> {
|
||||
val renderVisitor = new RenderVisitor(context.composition().getTimeline());
|
||||
val scene = context.composition().getScene();
|
||||
final var renderVisitor = new RenderVisitor(context.composition().getTimeline());
|
||||
final var scene = context.composition().getScene();
|
||||
Arrays.stream(args)
|
||||
.filter(v -> v.type() == Types.NODE)
|
||||
.map(v -> ((NodeValue) v).getNode())
|
||||
|
@ -9,7 +9,6 @@ import com.annimon.hotarufx.lib.Validator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javafx.scene.text.Font;
|
||||
import lombok.val;
|
||||
import static com.annimon.hotarufx.bundles.FunctionInfo.of;
|
||||
import static com.annimon.hotarufx.bundles.FunctionType.COMMON;
|
||||
|
||||
@ -28,7 +27,7 @@ public class FontBundle implements Bundle {
|
||||
|
||||
private static Function newFont(Context context) {
|
||||
return args -> {
|
||||
val validator = Validator.with(args);
|
||||
final var validator = Validator.with(args);
|
||||
validator.check(1);
|
||||
if (args[0].type() == Types.MAP) {
|
||||
return new FontValue(FontValue.toFont((MapValue) args[0]));
|
||||
|
@ -2,11 +2,7 @@ package com.annimon.hotarufx.bundles;
|
||||
|
||||
import com.annimon.hotarufx.lib.Context;
|
||||
import com.annimon.hotarufx.lib.Function;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class FunctionInfo {
|
||||
|
||||
public static FunctionInfo of(FunctionType type, Function function) {
|
||||
@ -17,10 +13,18 @@ public class FunctionInfo {
|
||||
return new FunctionInfo(type, extractor);
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final FunctionType type;
|
||||
private final java.util.function.Function<Context, Function> functionExtractor;
|
||||
|
||||
private FunctionInfo(FunctionType type, java.util.function.Function<Context, Function> functionExtractor) {
|
||||
this.type = type;
|
||||
this.functionExtractor = functionExtractor;
|
||||
}
|
||||
|
||||
public FunctionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Function extract(Context context) {
|
||||
return functionExtractor.apply(context);
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.scene.shape.Shape;
|
||||
import lombok.val;
|
||||
import static com.annimon.hotarufx.bundles.FunctionInfo.of;
|
||||
import static com.annimon.hotarufx.bundles.FunctionType.COMMON;
|
||||
|
||||
@ -32,15 +31,15 @@ public class NodeUtilsBundle implements Bundle {
|
||||
|
||||
private static Function strokePattern(Context context) {
|
||||
return args -> {
|
||||
val validator = Validator.with(args);
|
||||
final var validator = Validator.with(args);
|
||||
validator.checkOrOr(1, 2);
|
||||
if (args[0].type() != Types.NODE || !(args[0].raw() instanceof ShapeNode)) {
|
||||
throw new TypeException("Shape required at first argument");
|
||||
}
|
||||
val shape = (Shape) ((ShapeNode) args[0].raw()).getFxNode();
|
||||
final var shape = (Shape) ((ShapeNode) args[0].raw()).getFxNode();
|
||||
if (args.length == 2) {
|
||||
val array = validator.requireArrayAt(1);
|
||||
val dashList = array.stream()
|
||||
final var array = validator.requireArrayAt(1);
|
||||
final var dashList = array.stream()
|
||||
.map(Value::asDouble)
|
||||
.collect(Collectors.toList());
|
||||
shape.getStrokeDashArray().setAll(dashList);
|
||||
|
@ -12,7 +12,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.val;
|
||||
import static com.annimon.hotarufx.bundles.FunctionInfo.of;
|
||||
import static com.annimon.hotarufx.bundles.FunctionType.NODE;
|
||||
|
||||
@ -41,8 +40,8 @@ public class NodesBundle implements Bundle {
|
||||
|
||||
private static Function node(Supplier<? extends ObjectNode> supplier) {
|
||||
return args -> {
|
||||
val map = Validator.with(args).requireMapAt(0);
|
||||
val node = new NodeValue(supplier.get());
|
||||
final var map = Validator.with(args).requireMapAt(0);
|
||||
final var node = new NodeValue(supplier.get());
|
||||
node.fill(map);
|
||||
return node;
|
||||
};
|
||||
@ -50,12 +49,12 @@ public class NodesBundle implements Bundle {
|
||||
|
||||
private static Function poly(java.util.function.Function<List<Double>, ObjectNode> ctor) {
|
||||
return args -> {
|
||||
val validator = Validator.with(args);
|
||||
val map = validator.requireMapAt(1);
|
||||
val points = validator.requireArrayAt(0).stream()
|
||||
final var validator = Validator.with(args);
|
||||
final var map = validator.requireMapAt(1);
|
||||
final var points = validator.requireArrayAt(0).stream()
|
||||
.map(Value::asDouble)
|
||||
.collect(Collectors.toList());
|
||||
val node = new NodeValue(ctor.apply(points));
|
||||
final var node = new NodeValue(ctor.apply(points));
|
||||
node.fill(map);
|
||||
return node;
|
||||
};
|
||||
@ -63,10 +62,10 @@ public class NodesBundle implements Bundle {
|
||||
|
||||
private static Function image() {
|
||||
return args -> {
|
||||
val validator = Validator.with(args);
|
||||
val map = validator.requireMapAt(1);
|
||||
val url = args[0].asString();
|
||||
val node = new NodeValue(new ImageNode(url));
|
||||
final var validator = Validator.with(args);
|
||||
final var map = validator.requireMapAt(1);
|
||||
final var url = args[0].asString();
|
||||
final var node = new NodeValue(new ImageNode(url));
|
||||
node.fill(map);
|
||||
return node;
|
||||
};
|
||||
@ -74,7 +73,7 @@ public class NodesBundle implements Bundle {
|
||||
|
||||
private static Function group() {
|
||||
return args -> {
|
||||
val nodes = Arrays.stream(args)
|
||||
final var nodes = Arrays.stream(args)
|
||||
.filter(v -> v.type() == Types.NODE)
|
||||
.map(v -> ((NodeValue) v).getNode())
|
||||
.collect(Collectors.toList());
|
||||
|
@ -2,7 +2,6 @@ package com.annimon.hotarufx.exceptions;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import lombok.val;
|
||||
|
||||
public final class Exceptions {
|
||||
|
||||
@ -11,7 +10,7 @@ public final class Exceptions {
|
||||
}
|
||||
|
||||
public static String stackTraceToString(Throwable throwable) {
|
||||
val sw = new StringWriter();
|
||||
final var sw = new StringWriter();
|
||||
throwable.printStackTrace(new PrintWriter(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import lombok.val;
|
||||
|
||||
public class FileManager implements DocumentManager {
|
||||
|
||||
@ -55,7 +54,7 @@ public class FileManager implements DocumentManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
val content = readFile(currentFile);
|
||||
final var content = readFile(currentFile);
|
||||
if (content.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@ -80,7 +79,7 @@ public class FileManager implements DocumentManager {
|
||||
} else {
|
||||
fileChooser.setInitialFileName("animation.hfx");
|
||||
}
|
||||
val newFile = fileChooser.showSaveDialog(stage);
|
||||
final var newFile = fileChooser.showSaveDialog(stage);
|
||||
if (newFile == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3,18 +3,18 @@ package com.annimon.hotarufx.io;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import lombok.val;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class IOStream {
|
||||
|
||||
public static String readContent(InputStream is) throws IOException {
|
||||
val baos = new ByteArrayOutputStream();
|
||||
val bufferSize = 4096;
|
||||
val buffer = new byte[bufferSize];
|
||||
final var baos = new ByteArrayOutputStream();
|
||||
final var bufferSize = 4096;
|
||||
final var buffer = new byte[bufferSize];
|
||||
int read;
|
||||
while ((read = is.read(buffer, 0, bufferSize)) != -1) {
|
||||
baos.write(buffer, 0, read);
|
||||
}
|
||||
return baos.toString("UTF-8");
|
||||
return baos.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,11 @@ package com.annimon.hotarufx.lexer;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.val;
|
||||
|
||||
public class HotaruLexer extends Lexer {
|
||||
|
||||
public static List<Token> tokenize(String input) {
|
||||
val lexer = new HotaruLexer(input);
|
||||
final var lexer = new HotaruLexer(input);
|
||||
lexer.tokenize();
|
||||
return lexer.getTokens();
|
||||
}
|
||||
@ -48,7 +47,7 @@ public class HotaruLexer extends Lexer {
|
||||
}
|
||||
|
||||
public Token nextToken() {
|
||||
val current = peek(0);
|
||||
final var current = peek(0);
|
||||
if (Character.isDigit(current)) return tokenizeNumber();
|
||||
else if (Character.isJavaIdentifierStart(current)) return tokenizeWord();
|
||||
else if (current == '#') return tokenizeComment();
|
||||
@ -99,7 +98,7 @@ public class HotaruLexer extends Lexer {
|
||||
current = next();
|
||||
}
|
||||
|
||||
val word = getBuffer().toString();
|
||||
final var word = getBuffer().toString();
|
||||
return addToken(KEYWORDS.getOrDefault(word, HotaruTokenId.WORD));
|
||||
}
|
||||
|
||||
@ -110,7 +109,7 @@ public class HotaruLexer extends Lexer {
|
||||
char current = peek(0);
|
||||
while (true) {
|
||||
if (current == '\\') {
|
||||
val buffer = getBuffer();
|
||||
final var buffer = getBuffer();
|
||||
current = next();
|
||||
if (current == openChar) {
|
||||
current = next();
|
||||
@ -166,7 +165,7 @@ public class HotaruLexer extends Lexer {
|
||||
char current = peek(0);
|
||||
clearBuffer();
|
||||
while (true) {
|
||||
val text = getBuffer().toString();
|
||||
final var text = getBuffer().toString();
|
||||
if (!text.isEmpty() && !OPERATORS.containsKey(text + current)) {
|
||||
return addToken(OPERATORS.get(text), "", text.length());
|
||||
}
|
||||
|
@ -1,9 +1,5 @@
|
||||
package com.annimon.hotarufx.lexer;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public enum HotaruTokenId {
|
||||
|
||||
NUMBER(Category.NUMBER),
|
||||
@ -41,6 +37,10 @@ public enum HotaruTokenId {
|
||||
|
||||
private final Category category;
|
||||
|
||||
HotaruTokenId(Category category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public String getPrimaryCategory() {
|
||||
return category.name().toLowerCase();
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package com.annimon.hotarufx.lexer;
|
||||
import com.annimon.hotarufx.exceptions.LexerException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.val;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public abstract class Lexer {
|
||||
|
||||
private final String input;
|
||||
@ -88,7 +88,7 @@ public abstract class Lexer {
|
||||
}
|
||||
|
||||
protected Token addToken(HotaruTokenId tokenId, String text, int length) {
|
||||
val token = createToken(tokenId, text, length);
|
||||
final var token = createToken(tokenId, text, length);
|
||||
tokens.add(token);
|
||||
return token;
|
||||
}
|
||||
|
@ -1,14 +1,46 @@
|
||||
package com.annimon.hotarufx.lexer;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Objects;
|
||||
|
||||
@Data
|
||||
public class SourcePosition {
|
||||
|
||||
private final int position;
|
||||
private final int row;
|
||||
private final int column;
|
||||
|
||||
public SourcePosition(int position, int row, int column) {
|
||||
this.position = position;
|
||||
this.row = row;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public int getRow() {
|
||||
return row;
|
||||
}
|
||||
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SourcePosition that = (SourcePosition) o;
|
||||
return position == that.position &&
|
||||
row == that.row &&
|
||||
column == that.column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(position, row, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + row + ", " + column + "]";
|
||||
|
@ -1,8 +1,7 @@
|
||||
package com.annimon.hotarufx.lexer;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Objects;
|
||||
|
||||
@Data
|
||||
public class Token {
|
||||
|
||||
private final HotaruTokenId type;
|
||||
@ -10,6 +9,45 @@ public class Token {
|
||||
private final int length;
|
||||
private final SourcePosition position;
|
||||
|
||||
public Token(HotaruTokenId type, String text, int length, SourcePosition position) {
|
||||
this.type = type;
|
||||
this.text = text;
|
||||
this.length = length;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public HotaruTokenId getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public SourcePosition getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Token token = (Token) o;
|
||||
return length == token.length &&
|
||||
type == token.type &&
|
||||
Objects.equals(text, token.text) &&
|
||||
Objects.equals(position, token.position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, text, length, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.name() + " " + position + " " + text;
|
||||
|
@ -6,7 +6,6 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.Getter;
|
||||
|
||||
public class ArrayValue implements Value, Iterable<Value> {
|
||||
|
||||
@ -17,7 +16,6 @@ public class ArrayValue implements Value, Iterable<Value> {
|
||||
.toArray(Value[]::new));
|
||||
}
|
||||
|
||||
@Getter
|
||||
private final Value[] elements;
|
||||
|
||||
public ArrayValue(int size) {
|
||||
@ -33,6 +31,10 @@ public class ArrayValue implements Value, Iterable<Value> {
|
||||
this(array.elements);
|
||||
}
|
||||
|
||||
public Value[] getElements() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
public Value[] getCopyElements() {
|
||||
final Value[] result = new Value[elements.length];
|
||||
System.arraycopy(elements, 0, result, 0, elements.length);
|
||||
|
@ -4,17 +4,16 @@ import com.annimon.hotarufx.exceptions.TypeException;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontPosture;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import lombok.val;
|
||||
|
||||
public class FontValue extends MapValue {
|
||||
|
||||
public static Font toFont(MapValue mapValue) {
|
||||
val map = mapValue.getMap();
|
||||
val family = map.getOrDefault("family", new StringValue(Font.getDefault().getFamily())).asString();
|
||||
val weight = map.getOrDefault("weight", NumberValue.of(FontWeight.NORMAL.getWeight())).asInt();
|
||||
val isItalic = map.getOrDefault("italic", NumberValue.ZERO).asBoolean();
|
||||
val posture = isItalic ? FontPosture.ITALIC : FontPosture.REGULAR;
|
||||
val size = map.getOrDefault("size", NumberValue.MINUS_ONE).asDouble();
|
||||
final var map = mapValue.getMap();
|
||||
final var family = map.getOrDefault("family", new StringValue(Font.getDefault().getFamily())).asString();
|
||||
final var weight = map.getOrDefault("weight", NumberValue.of(FontWeight.NORMAL.getWeight())).asInt();
|
||||
final var isItalic = map.getOrDefault("italic", NumberValue.ZERO).asBoolean();
|
||||
final var posture = isItalic ? FontPosture.ITALIC : FontPosture.REGULAR;
|
||||
final var size = map.getOrDefault("size", NumberValue.MINUS_ONE).asDouble();
|
||||
return Font.font(family, FontWeight.findByWeight(weight), posture, size);
|
||||
}
|
||||
|
||||
@ -27,10 +26,10 @@ public class FontValue extends MapValue {
|
||||
}
|
||||
|
||||
private void init() {
|
||||
val map = super.getMap();
|
||||
final var map = super.getMap();
|
||||
map.put("family", new StringValue(font.getFamily()));
|
||||
map.put("isItalic", NumberValue.fromBoolean(font.getStyle().toLowerCase().contains("italic")));
|
||||
val weight = FontWeight.findByName(font.getStyle());
|
||||
final var weight = FontWeight.findByName(font.getStyle());
|
||||
map.put("weight", NumberValue.of(weight != null
|
||||
? (weight.getWeight())
|
||||
: FontWeight.NORMAL.getWeight()));
|
||||
|
@ -2,19 +2,21 @@ package com.annimon.hotarufx.lib;
|
||||
|
||||
import com.annimon.hotarufx.exceptions.TypeException;
|
||||
import java.util.Objects;
|
||||
import lombok.Getter;
|
||||
|
||||
public class FunctionValue implements Value {
|
||||
|
||||
public static final FunctionValue EMPTY = new FunctionValue(args -> NumberValue.ZERO);
|
||||
|
||||
@Getter
|
||||
private final Function value;
|
||||
|
||||
public FunctionValue(Function value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Function getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int type() {
|
||||
return Types.FUNCTION;
|
||||
|
@ -2,17 +2,19 @@ package com.annimon.hotarufx.lib;
|
||||
|
||||
import com.annimon.hotarufx.exceptions.TypeException;
|
||||
import javafx.animation.Interpolator;
|
||||
import lombok.Getter;
|
||||
|
||||
public class InterpolatorValue implements Value {
|
||||
|
||||
@Getter
|
||||
private final Interpolator interpolator;
|
||||
|
||||
public InterpolatorValue(Interpolator interpolator) {
|
||||
this.interpolator = interpolator;
|
||||
}
|
||||
|
||||
public Interpolator getInterpolator() {
|
||||
return interpolator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int type() {
|
||||
return Types.INTERPOLATOR;
|
||||
|
@ -9,7 +9,6 @@ import com.annimon.hotarufx.visual.objects.ObjectNode;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.text.Font;
|
||||
import lombok.val;
|
||||
|
||||
public class NodeValue implements Value {
|
||||
|
||||
@ -45,8 +44,8 @@ public class NodeValue implements Value {
|
||||
throw new HotaruRuntimeException("Unable to get property " + key + " from node value");
|
||||
}
|
||||
final Property property = bindings.get(key);
|
||||
val timeline = property.getProperty().get();
|
||||
val type = property.getType();
|
||||
final var timeline = property.getProperty().get();
|
||||
final var type = property.getType();
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
return type.<Boolean>getToHFX().apply(
|
||||
@ -76,8 +75,8 @@ public class NodeValue implements Value {
|
||||
public void set(String key, Value value) {
|
||||
if (!bindings.containsKey(key)) return;
|
||||
final Property property = bindings.get(key);
|
||||
val timeline = property.getProperty().get();
|
||||
val type = property.getType();
|
||||
final var timeline = property.getProperty().get();
|
||||
final var type = property.getType();
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
((PropertyTimeline<Boolean>) timeline).getProperty().setValue(
|
||||
@ -108,7 +107,7 @@ public class NodeValue implements Value {
|
||||
}
|
||||
|
||||
public Value getProperty(String key) {
|
||||
val property = bindings.get(key);
|
||||
final var property = bindings.get(key);
|
||||
if (property == null) {
|
||||
throw new HotaruRuntimeException("Unable to get property " + key + " from node value");
|
||||
}
|
||||
|
@ -11,12 +11,9 @@ import javafx.animation.Interpolator;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.text.Font;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
|
||||
public class PropertyValue implements Value {
|
||||
|
||||
@Getter
|
||||
private final Property property;
|
||||
private final Map<String, Value> fields;
|
||||
|
||||
@ -27,13 +24,17 @@ public class PropertyValue implements Value {
|
||||
fields.put("clear", new FunctionValue(clear()));
|
||||
}
|
||||
|
||||
public Property getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int type() {
|
||||
return Types.PROPERTY;
|
||||
}
|
||||
|
||||
public Value getField(String name) {
|
||||
val field = fields.get(name);
|
||||
final var field = fields.get(name);
|
||||
if (field == null) {
|
||||
throw new HotaruRuntimeException("PropertyValue does not have " + name + " field");
|
||||
}
|
||||
@ -53,7 +54,7 @@ public class PropertyValue implements Value {
|
||||
}
|
||||
interpolator = ((InterpolatorValue) args[2]).getInterpolator();
|
||||
}
|
||||
val type = property.getType();
|
||||
final var type = property.getType();
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
((PropertyTimeline<Boolean>)property.getProperty().get()).add(
|
||||
|
@ -2,14 +2,19 @@ package com.annimon.hotarufx.lib;
|
||||
|
||||
import com.annimon.hotarufx.exceptions.ArgumentsMismatchException;
|
||||
import com.annimon.hotarufx.exceptions.TypeException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
|
||||
@RequiredArgsConstructor(staticName = "with")
|
||||
public class Validator {
|
||||
|
||||
public static Validator with(Value[] args) {
|
||||
return new Validator(args);
|
||||
}
|
||||
|
||||
private final Value[] args;
|
||||
|
||||
private Validator(Value[] args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public Validator check(int expected) {
|
||||
if (args.length != expected) throw new ArgumentsMismatchException(String.format(
|
||||
"%d %s expected, got %d", expected, pluralize(expected), args.length));
|
||||
@ -38,7 +43,7 @@ public class Validator {
|
||||
|
||||
public ArrayValue requireArrayAt(int index) {
|
||||
checkAtLeast(index + 1);
|
||||
val value = args[index];
|
||||
final var value = args[index];
|
||||
if (value.type() != Types.ARRAY) {
|
||||
throw new TypeException(String.format("Array required at %d argument", index));
|
||||
}
|
||||
@ -47,7 +52,7 @@ public class Validator {
|
||||
|
||||
public MapValue requireMapAt(int index) {
|
||||
checkAtLeast(index + 1);
|
||||
val value = args[index];
|
||||
final var value = args[index];
|
||||
if (value.type() != Types.MAP) {
|
||||
throw new TypeException(String.format("Map required at %d argument", index));
|
||||
}
|
||||
|
@ -9,13 +9,12 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.val;
|
||||
|
||||
public class HotaruParser extends Parser {
|
||||
|
||||
public static Node parse(List<Token> tokens) {
|
||||
val parser = new HotaruParser(tokens);
|
||||
val program = parser.parse();
|
||||
final var parser = new HotaruParser(tokens);
|
||||
final var program = parser.parse();
|
||||
if (parser.getParseErrors().hasErrors()) {
|
||||
throw new ParseException(parser.getParseErrors().toString());
|
||||
}
|
||||
@ -27,7 +26,7 @@ public class HotaruParser extends Parser {
|
||||
}
|
||||
|
||||
private Node block() {
|
||||
val block = new BlockNode();
|
||||
final var block = new BlockNode();
|
||||
block.start(getSourcePosition());
|
||||
consume(HotaruTokenId.LBRACE);
|
||||
while (!match(HotaruTokenId.RBRACE)) {
|
||||
@ -55,7 +54,7 @@ public class HotaruParser extends Parser {
|
||||
|
||||
private Node functionChain(Node qualifiedNameExpr) {
|
||||
// f1()()() || f1().f2().f3() || f1().key
|
||||
val expr = function(qualifiedNameExpr);
|
||||
final var expr = function(qualifiedNameExpr);
|
||||
if (lookMatch(0, HotaruTokenId.LPAREN)) {
|
||||
return functionChain(expr);
|
||||
}
|
||||
@ -64,7 +63,7 @@ public class HotaruParser extends Parser {
|
||||
|
||||
private Node objectAccess(Node expr) {
|
||||
if (lookMatch(0, HotaruTokenId.DOT)) {
|
||||
val indices = variableSuffix();
|
||||
final var indices = variableSuffix();
|
||||
if (indices == null || indices.isEmpty())
|
||||
return expr;
|
||||
|
||||
@ -81,7 +80,7 @@ public class HotaruParser extends Parser {
|
||||
private FunctionNode function(Node qualifiedNameExpr) {
|
||||
// function(arg1, arg2, ...)
|
||||
consume(HotaruTokenId.LPAREN);
|
||||
val function = new FunctionNode(qualifiedNameExpr);
|
||||
final var function = new FunctionNode(qualifiedNameExpr);
|
||||
while (!match(HotaruTokenId.RPAREN)) {
|
||||
function.addArgument(expression());
|
||||
match(HotaruTokenId.COMMA);
|
||||
@ -92,7 +91,7 @@ public class HotaruParser extends Parser {
|
||||
private Node array() {
|
||||
// [value1, value2, ...]
|
||||
consume(HotaruTokenId.LBRACKET);
|
||||
val elements = new ArrayList<Node>();
|
||||
final var elements = new ArrayList<Node>();
|
||||
while (!match(HotaruTokenId.RBRACKET)) {
|
||||
elements.add(expression());
|
||||
match(HotaruTokenId.COMMA);
|
||||
@ -105,9 +104,9 @@ public class HotaruParser extends Parser {
|
||||
consume(HotaruTokenId.LBRACE);
|
||||
final Map<String, Node> elements = new HashMap<>();
|
||||
while (!match(HotaruTokenId.RBRACE)) {
|
||||
val key = consume(HotaruTokenId.WORD).getText();
|
||||
final var key = consume(HotaruTokenId.WORD).getText();
|
||||
consume(HotaruTokenId.COLON);
|
||||
val value = expression();
|
||||
final var value = expression();
|
||||
elements.put(key, value);
|
||||
match(HotaruTokenId.COMMA);
|
||||
}
|
||||
@ -120,7 +119,7 @@ public class HotaruParser extends Parser {
|
||||
}
|
||||
|
||||
private Node assignment() {
|
||||
val assignment = assignmentStrict();
|
||||
final var assignment = assignmentStrict();
|
||||
if (assignment != null) {
|
||||
return assignment;
|
||||
}
|
||||
@ -129,8 +128,8 @@ public class HotaruParser extends Parser {
|
||||
|
||||
private Node assignmentStrict() {
|
||||
final int position = pos;
|
||||
val startSourcePosition = getSourcePosition();
|
||||
val targetExpr = qualifiedName();
|
||||
final var startSourcePosition = getSourcePosition();
|
||||
final var targetExpr = qualifiedName();
|
||||
if ((targetExpr == null) || !(targetExpr instanceof Accessible)) {
|
||||
pos = position;
|
||||
return null;
|
||||
@ -157,7 +156,7 @@ public class HotaruParser extends Parser {
|
||||
|
||||
private Node primary() {
|
||||
if (match(HotaruTokenId.LPAREN)) {
|
||||
val result = expression();
|
||||
final var result = expression();
|
||||
match(HotaruTokenId.RPAREN);
|
||||
return result;
|
||||
}
|
||||
@ -189,8 +188,8 @@ public class HotaruParser extends Parser {
|
||||
}
|
||||
// node@prop || map.node@prop
|
||||
if (match(HotaruTokenId.AT)) {
|
||||
val propName = consume(HotaruTokenId.WORD).getText();
|
||||
val expr = new PropertyNode(qualifiedNameExpr, propName);
|
||||
final var propName = consume(HotaruTokenId.WORD).getText();
|
||||
final var expr = new PropertyNode(qualifiedNameExpr, propName);
|
||||
return objectAccess(expr);
|
||||
}
|
||||
return qualifiedNameExpr;
|
||||
@ -221,8 +220,8 @@ public class HotaruParser extends Parser {
|
||||
final List<Node> indices = new ArrayList<>();
|
||||
while (lookMatch(0, HotaruTokenId.DOT)) {
|
||||
if (match(HotaruTokenId.DOT)) {
|
||||
val fieldName = consume(HotaruTokenId.WORD).getText();
|
||||
val key = new ValueNode(fieldName);
|
||||
final var fieldName = consume(HotaruTokenId.WORD).getText();
|
||||
final var key = new ValueNode(fieldName);
|
||||
indices.add(key);
|
||||
}
|
||||
}
|
||||
@ -230,7 +229,7 @@ public class HotaruParser extends Parser {
|
||||
}
|
||||
|
||||
private Node value() {
|
||||
val current = get(0);
|
||||
final var current = get(0);
|
||||
if (match(HotaruTokenId.TRUE)) {
|
||||
return new ValueNode(NumberValue.ONE);
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import com.annimon.hotarufx.lexer.Token;
|
||||
import com.annimon.hotarufx.parser.ast.BlockNode;
|
||||
import com.annimon.hotarufx.parser.ast.Node;
|
||||
import java.util.List;
|
||||
import lombok.val;
|
||||
|
||||
public abstract class Parser {
|
||||
|
||||
@ -38,7 +37,7 @@ public abstract class Parser {
|
||||
|
||||
public Node parse() {
|
||||
parseErrors.clear();
|
||||
val result = new BlockNode();
|
||||
final var result = new BlockNode();
|
||||
result.start(getSourcePosition());
|
||||
while (!match(HotaruTokenId.EOF)) {
|
||||
try {
|
||||
@ -77,7 +76,7 @@ public abstract class Parser {
|
||||
}
|
||||
|
||||
protected Token consume(HotaruTokenId type) {
|
||||
val current = get(0);
|
||||
final var current = get(0);
|
||||
if (type != current.getType()) {
|
||||
throw new ParseException("Token " + current + " doesn't match " + type, current.getPosition());
|
||||
}
|
||||
@ -86,7 +85,7 @@ public abstract class Parser {
|
||||
}
|
||||
|
||||
protected boolean match(HotaruTokenId type) {
|
||||
val current = get(0);
|
||||
final var current = get(0);
|
||||
if (type != current.getType()) return false;
|
||||
pos++;
|
||||
return true;
|
||||
@ -97,7 +96,7 @@ public abstract class Parser {
|
||||
}
|
||||
|
||||
protected Token get(int relativePosition) {
|
||||
val position = pos + relativePosition;
|
||||
final var position = pos + relativePosition;
|
||||
if (position >= size) return EOF;
|
||||
return tokens.get(position);
|
||||
}
|
||||
|
@ -1,18 +1,30 @@
|
||||
package com.annimon.hotarufx.parser.ast;
|
||||
|
||||
import com.annimon.hotarufx.lexer.SourcePosition;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(fluent = true)
|
||||
public abstract class ASTNode implements Node {
|
||||
|
||||
@Getter @Setter
|
||||
private SourcePosition start;
|
||||
@Getter @Setter
|
||||
private SourcePosition end;
|
||||
|
||||
public SourcePosition start() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public SourcePosition end() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public ASTNode start(SourcePosition start) {
|
||||
this.start = start;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ASTNode end(SourcePosition end) {
|
||||
this.end = end;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSourceRange() {
|
||||
return start + " .. " + end;
|
||||
}
|
||||
|
@ -3,20 +3,25 @@ package com.annimon.hotarufx.parser.ast;
|
||||
import com.annimon.hotarufx.lib.Value;
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class AccessNode extends ASTNode implements Accessible {
|
||||
|
||||
@Getter
|
||||
public final Node root;
|
||||
public final List<Node> indices;
|
||||
|
||||
public AccessNode(Node root, List<Node> indices) {
|
||||
this.root = root;
|
||||
this.indices = indices;
|
||||
}
|
||||
|
||||
public AccessNode(String variable, List<Node> indices) {
|
||||
this(new VariableNode(variable), indices);
|
||||
}
|
||||
|
||||
public Node getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
|
@ -2,13 +2,15 @@ package com.annimon.hotarufx.parser.ast;
|
||||
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ArrayNode extends ASTNode {
|
||||
|
||||
public final List<Node> elements;
|
||||
|
||||
public ArrayNode(List<Node> elements) {
|
||||
this.elements = elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
|
@ -1,14 +1,17 @@
|
||||
package com.annimon.hotarufx.parser.ast;
|
||||
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class AssignNode extends ASTNode {
|
||||
|
||||
public final Accessible target;
|
||||
public final Node value;
|
||||
|
||||
public AssignNode(Accessible target, Node value) {
|
||||
this.target = target;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
|
@ -2,13 +2,15 @@ package com.annimon.hotarufx.parser.ast;
|
||||
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class MapNode extends ASTNode {
|
||||
|
||||
public final Map<String, Node> elements;
|
||||
|
||||
public MapNode(Map<String, Node> elements) {
|
||||
this.elements = elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
|
@ -1,14 +1,17 @@
|
||||
package com.annimon.hotarufx.parser.ast;
|
||||
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class PropertyNode extends ASTNode {
|
||||
|
||||
public final Node node;
|
||||
public final String property;
|
||||
|
||||
public PropertyNode(Node node, String property) {
|
||||
this.node = node;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
|
@ -1,9 +1,7 @@
|
||||
package com.annimon.hotarufx.parser.ast;
|
||||
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class UnaryNode extends ASTNode {
|
||||
|
||||
public enum Operator { NEGATE };
|
||||
@ -11,6 +9,11 @@ public class UnaryNode extends ASTNode {
|
||||
public final Operator operator;
|
||||
public final Node node;
|
||||
|
||||
public UnaryNode(Operator operator, Node node) {
|
||||
this.operator = operator;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
|
@ -1,9 +1,7 @@
|
||||
package com.annimon.hotarufx.parser.ast;
|
||||
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class UnitNode extends ASTNode {
|
||||
|
||||
public enum Unit {MILLISECONDS, SECONDS};
|
||||
@ -11,6 +9,11 @@ public class UnitNode extends ASTNode {
|
||||
public final Node value;
|
||||
public final Unit operator;
|
||||
|
||||
public UnitNode(Node value, Unit operator) {
|
||||
this.value = value;
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
|
@ -4,13 +4,15 @@ import com.annimon.hotarufx.lib.NumberValue;
|
||||
import com.annimon.hotarufx.lib.StringValue;
|
||||
import com.annimon.hotarufx.lib.Value;
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ValueNode extends ASTNode {
|
||||
|
||||
public final Value value;
|
||||
|
||||
public ValueNode(Value value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ValueNode(Number value) {
|
||||
this(NumberValue.of(value));
|
||||
}
|
||||
|
@ -2,13 +2,15 @@ package com.annimon.hotarufx.parser.ast;
|
||||
|
||||
import com.annimon.hotarufx.lib.Value;
|
||||
import com.annimon.hotarufx.parser.visitors.ResultVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class VariableNode extends ASTNode implements Accessible {
|
||||
|
||||
public final String name;
|
||||
|
||||
public VariableNode(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T input) {
|
||||
return visitor.visit(this, input);
|
||||
|
@ -10,7 +10,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import lombok.val;
|
||||
|
||||
public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
|
||||
@ -21,7 +20,7 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
|
||||
@Override
|
||||
public Value visit(ArrayNode node, Context context) {
|
||||
val elements = node.elements.stream()
|
||||
final var elements = node.elements.stream()
|
||||
.map(el -> el.accept(this, context))
|
||||
.toArray(Value[]::new);
|
||||
return new ArrayValue(elements);
|
||||
@ -29,7 +28,7 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
|
||||
@Override
|
||||
public Value visit(AssignNode node, Context context) {
|
||||
val value = node.value.accept(this, context);
|
||||
final var value = node.value.accept(this, context);
|
||||
return node.target.set(this, value, context);
|
||||
}
|
||||
|
||||
@ -44,20 +43,20 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
|
||||
@Override
|
||||
public Value visit(FunctionNode node, Context context) {
|
||||
val value = node.functionNode.accept(this, context);
|
||||
final var value = node.functionNode.accept(this, context);
|
||||
final Function function;
|
||||
switch (value.type()) {
|
||||
case Types.FUNCTION:
|
||||
function = ((FunctionValue) value).getValue();
|
||||
break;
|
||||
default:
|
||||
val functionName = value.asString();
|
||||
final var functionName = value.asString();
|
||||
function = context.functions().get(functionName);
|
||||
if (function == null)
|
||||
throw new FunctionNotFoundException(functionName, node.start(), node.end());
|
||||
break;
|
||||
}
|
||||
val args = node.arguments.stream()
|
||||
final var args = node.arguments.stream()
|
||||
.map(n -> n.accept(this, context))
|
||||
.toArray(Value[]::new);
|
||||
return function.execute(args);
|
||||
@ -74,11 +73,11 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
|
||||
@Override
|
||||
public Value visit(PropertyNode node, Context context) {
|
||||
val value = node.node.accept(this, context);
|
||||
final var value = node.node.accept(this, context);
|
||||
if (value.type() != Types.NODE) {
|
||||
throw new TypeException("Node value expected");
|
||||
}
|
||||
val nodeValue = (NodeValue) value;
|
||||
final var nodeValue = (NodeValue) value;
|
||||
return nodeValue.getProperty(node.property);
|
||||
}
|
||||
|
||||
@ -86,7 +85,7 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
public Value visit(UnaryNode node, Context context) {
|
||||
switch (node.operator) {
|
||||
case NEGATE:
|
||||
val value = node.node.accept(this, context);
|
||||
final var value = node.node.accept(this, context);
|
||||
if (value.type() == Types.STRING) {
|
||||
final StringBuilder sb = new StringBuilder(value.asString());
|
||||
return new StringValue(sb.reverse().toString());
|
||||
@ -112,8 +111,8 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
|
||||
@Override
|
||||
public Value visit(UnitNode node, Context context) {
|
||||
val value = node.value.accept(this, context);
|
||||
val frameRate = context.composition().getTimeline().getFrameRate();
|
||||
final var value = node.value.accept(this, context);
|
||||
final var frameRate = context.composition().getTimeline().getFrameRate();
|
||||
final double frame;
|
||||
switch (node.operator) {
|
||||
case SECONDS:
|
||||
@ -155,12 +154,12 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
.orElseThrow(exceptionSupplier);
|
||||
switch (container.type()) {
|
||||
case Types.MAP: {
|
||||
val key = node.indices.get(lastIndex).accept(this, context).asString();
|
||||
final var key = node.indices.get(lastIndex).accept(this, context).asString();
|
||||
((MapValue) container).getMap().put(key, value);
|
||||
} break;
|
||||
|
||||
case Types.NODE: {
|
||||
val key = node.indices.get(lastIndex).accept(this, context).asString();
|
||||
final var key = node.indices.get(lastIndex).accept(this, context).asString();
|
||||
((NodeValue) container).set(key, value);
|
||||
} break;
|
||||
|
||||
@ -174,18 +173,18 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
for (Node index : nodes) {
|
||||
switch (container.type()) {
|
||||
case Types.MAP: {
|
||||
val key = index.accept(this, context).asString();
|
||||
final var key = index.accept(this, context).asString();
|
||||
container = ((MapValue) container).getMap().get(key);
|
||||
} break;
|
||||
|
||||
case Types.NODE: {
|
||||
val key = index.accept(this, context).asString();
|
||||
final var key = index.accept(this, context).asString();
|
||||
container = ((NodeValue) container).get(key);
|
||||
} break;
|
||||
|
||||
case Types.PROPERTY: {
|
||||
val key = index.accept(this, context).asString();
|
||||
val propertyValue = (PropertyValue) container;
|
||||
final var key = index.accept(this, context).asString();
|
||||
final var propertyValue = (PropertyValue) container;
|
||||
container = propertyValue.getField(key);
|
||||
} break;
|
||||
|
||||
@ -198,7 +197,7 @@ public class InterpreterVisitor implements ResultVisitor<Value, Context> {
|
||||
|
||||
@Override
|
||||
public Value get(VariableNode node, Context context) {
|
||||
val result = context.variables().get(node.name);
|
||||
final var result = context.variables().get(node.name);
|
||||
if (result == null)
|
||||
throw new VariableNotFoundException(node.name, node.start(), node.end());
|
||||
return result;
|
||||
|
@ -8,7 +8,6 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.util.Pair;
|
||||
import lombok.Getter;
|
||||
|
||||
public enum FontAwesome {
|
||||
|
||||
@ -28,7 +27,6 @@ public enum FontAwesome {
|
||||
SEARCH_MINUS("\uf010", "search-minus"),
|
||||
UNDO("\uf0e2", "undo");
|
||||
|
||||
@Getter
|
||||
private final String symbol;
|
||||
private final List<String> names;
|
||||
|
||||
@ -41,6 +39,10 @@ public enum FontAwesome {
|
||||
}
|
||||
}
|
||||
|
||||
public String getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public static String getIcon(String name) {
|
||||
return MAPPING.get(name);
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import java.util.function.Function;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import lombok.val;
|
||||
|
||||
public class RenderPreparer {
|
||||
|
||||
@ -71,8 +70,8 @@ public class RenderPreparer {
|
||||
}
|
||||
|
||||
private void evaluate() {
|
||||
val parser = new HotaruParser(HotaruLexer.tokenize(source.input));
|
||||
val program = parser.parse();
|
||||
final var parser = new HotaruParser(HotaruLexer.tokenize(source.input));
|
||||
final var program = parser.parse();
|
||||
if (parser.getParseErrors().hasErrors()) {
|
||||
throw new RendererException(parser.getParseErrors().toString());
|
||||
}
|
||||
@ -91,10 +90,10 @@ public class RenderPreparer {
|
||||
|
||||
public WithStage prepareStage(Stage primaryStage) {
|
||||
checkCompositionExists();
|
||||
val stage = new Stage();
|
||||
final var stage = new Stage();
|
||||
stage.initOwner(primaryStage);
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
val composition = source.context.composition();
|
||||
final var composition = source.context.composition();
|
||||
stage.setScene(sceneProvider().apply(composition));
|
||||
return new WithStage(composition, stage);
|
||||
}
|
||||
|
@ -15,13 +15,10 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.concurrent.Task;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
import org.fxmisc.richtext.StyleSpans;
|
||||
import org.fxmisc.richtext.StyleSpansBuilder;
|
||||
import org.fxmisc.richtext.model.StyleSpans;
|
||||
import org.fxmisc.richtext.model.StyleSpansBuilder;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class SyntaxHighlighter {
|
||||
|
||||
private final CodeArea editor;
|
||||
@ -29,6 +26,11 @@ public class SyntaxHighlighter {
|
||||
private Set<String> nodeFunctions;
|
||||
private Map<HotaruTokenId, String> operatorClasses;
|
||||
|
||||
public SyntaxHighlighter(CodeArea editor, ExecutorService executor) {
|
||||
this.editor = editor;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public void init(BooleanProperty enabledProperty) {
|
||||
operatorClasses = new HashMap<>();
|
||||
operatorClasses.put(HotaruTokenId.AT, "keyframes-extractor");
|
||||
@ -51,13 +53,13 @@ public class SyntaxHighlighter {
|
||||
}
|
||||
|
||||
private Task<StyleSpans<Collection<String>>> computeHighlightingAsync() {
|
||||
val text = editor.getText();
|
||||
val task = new Task<StyleSpans<Collection<String>>>() {
|
||||
final var text = editor.getText();
|
||||
final var task = new Task<StyleSpans<Collection<String>>>() {
|
||||
@Override
|
||||
protected StyleSpans<Collection<String>> call() throws Exception {
|
||||
val spans = new StyleSpansBuilder<Collection<String>>();
|
||||
for (val t : new HotaruLexer(text).tokenize()) {
|
||||
val category = t.getType().getPrimaryCategory();
|
||||
final var spans = new StyleSpansBuilder<Collection<String>>();
|
||||
for (final var t : new HotaruLexer(text).tokenize()) {
|
||||
final var category = t.getType().getPrimaryCategory();
|
||||
switch (category) {
|
||||
case "string":
|
||||
case "keyword":
|
||||
@ -75,7 +77,7 @@ public class SyntaxHighlighter {
|
||||
break;
|
||||
|
||||
case "operator":
|
||||
val className = operatorClasses.get(t.getType());
|
||||
final var className = operatorClasses.get(t.getType());
|
||||
if (className != null) {
|
||||
spans.add(Collections.singleton(className), t.getLength());
|
||||
} else {
|
||||
|
@ -20,7 +20,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.Executors;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
@ -43,13 +42,14 @@ import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import javafx.util.Duration;
|
||||
import lombok.val;
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
import org.fxmisc.richtext.LineNumberFactory;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class EditorController implements Initializable, DocumentListener {
|
||||
|
||||
private static final int DEFAULT_FONT_SIZE = 14;
|
||||
|
||||
@FXML
|
||||
private Menu examplesMenu;
|
||||
|
||||
@ -73,6 +73,7 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
private Stage primaryStage;
|
||||
private SyntaxHighlighter syntaxHighlighter;
|
||||
private DocumentManager documentManager;
|
||||
private int fontSize = DEFAULT_FONT_SIZE;
|
||||
|
||||
@FXML
|
||||
private void handleMenuNew(ActionEvent event) {
|
||||
@ -83,7 +84,7 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
|
||||
@FXML
|
||||
private void handleMenuOpen(ActionEvent event) {
|
||||
val isOpened = documentManager.open(primaryStage, editor::replaceText);
|
||||
final var isOpened = documentManager.open(primaryStage, editor::replaceText);
|
||||
if (isOpened) {
|
||||
updateTitle();
|
||||
}
|
||||
@ -120,13 +121,13 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
}
|
||||
|
||||
private boolean confirmExit() {
|
||||
val alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
final var alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setTitle("Exit");
|
||||
alert.setHeaderText("Are you sure you want to exit?");
|
||||
alert.initOwner(primaryStage);
|
||||
alert.initModality(Modality.APPLICATION_MODAL);
|
||||
alert.getDialogPane().setContent(new Group());
|
||||
val icon = new FontAwesomeIcon(FontAwesome.QUESTION_CIRCLE);
|
||||
final var icon = new FontAwesomeIcon(FontAwesome.QUESTION_CIRCLE);
|
||||
alert.getDialogPane().setGraphic(icon);
|
||||
return alert.showAndWait()
|
||||
.filter(b -> b == ButtonType.OK)
|
||||
@ -144,22 +145,22 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
}
|
||||
|
||||
private void changeFontSize(int delta) {
|
||||
if (editor.getFont() == null) return;
|
||||
val newSize = (int) editor.getFont().getSize() + delta;
|
||||
final int newSize = fontSize + delta;
|
||||
if (8 > newSize || newSize > 40) return;
|
||||
fontSize = newSize;
|
||||
editor.setStyle("-fx-font-size: " + newSize + "px");
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void handleMenuAbout(ActionEvent event) {
|
||||
val stage = new Stage();
|
||||
final var stage = new Stage();
|
||||
stage.setTitle("About");
|
||||
stage.setResizable(false);
|
||||
stage.initOwner(primaryStage);
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
try {
|
||||
val loader = new FXMLLoader(getClass().getResource("/fxml/About.fxml"));
|
||||
val scene = new Scene(loader.load());
|
||||
final var loader = new FXMLLoader(getClass().getResource("/fxml/About.fxml"));
|
||||
final var scene = new Scene(loader.load());
|
||||
scene.getStylesheets().addAll(
|
||||
getClass().getResource("/styles/theme-dark.css").toExternalForm(),
|
||||
getClass().getResource("/styles/about.css").toExternalForm()
|
||||
@ -174,7 +175,7 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
@FXML
|
||||
private void handleMenuPlay(ActionEvent event) {
|
||||
log.setText("");
|
||||
val input = editor.getText();
|
||||
final var input = editor.getText();
|
||||
if (input.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -185,14 +186,14 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
.evaluateWithRuntimeBundle()
|
||||
.prepareStage(primaryStage)
|
||||
.peek((stage, composition) -> {
|
||||
val timeline = composition.getTimeline();
|
||||
final var timeline = composition.getTimeline();
|
||||
timeline.getFxTimeline().currentTimeProperty().addListener((o, oldValue, d) -> {
|
||||
val min = (int) d.toMinutes();
|
||||
val durationSec = d.subtract(Duration.minutes(min));
|
||||
val sec = (int) durationSec.toSeconds();
|
||||
val durationMs = durationSec.subtract(Duration.seconds(sec));
|
||||
val frame = (int) (durationMs.toMillis() * timeline.getFrameRate() / 1000d);
|
||||
val allFrame = (int) (d.toMillis() * timeline.getFrameRate() / 1000d);
|
||||
final var min = (int) d.toMinutes();
|
||||
final var durationSec = d.subtract(Duration.minutes(min));
|
||||
final var sec = (int) durationSec.toSeconds();
|
||||
final var durationMs = durationSec.subtract(Duration.seconds(sec));
|
||||
final var frame = (int) (durationMs.toMillis() * timeline.getFrameRate() / 1000d);
|
||||
final var allFrame = (int) (d.toMillis() * timeline.getFrameRate() / 1000d);
|
||||
stage.setTitle(String.format("%02d:%02d.%02d %d", min, sec, frame, allFrame));
|
||||
});
|
||||
|
||||
@ -209,7 +210,7 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
@FXML
|
||||
private void handleMenuRender(ActionEvent event) {
|
||||
log.setText("");
|
||||
val input = editor.getText();
|
||||
final var input = editor.getText();
|
||||
if (input.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -220,18 +221,18 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
.evaluateForRender()
|
||||
.prepareStage(primaryStage)
|
||||
.peek((stage, composition) -> {
|
||||
val chooser = new DirectoryChooser();
|
||||
final var chooser = new DirectoryChooser();
|
||||
chooser.setTitle("Choose directory for rendering frames");
|
||||
val directory = chooser.showDialog(primaryStage);
|
||||
final var directory = chooser.showDialog(primaryStage);
|
||||
if (directory == null || !directory.exists() || !directory.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
val fxTimeline = composition.getTimeline().getFxTimeline();
|
||||
final var fxTimeline = composition.getTimeline().getFxTimeline();
|
||||
stage.setOnShown(e -> {
|
||||
fxTimeline.playFromStart();
|
||||
fxTimeline.pause();
|
||||
val task = new RenderTask(directory, composition, stage.getScene());
|
||||
final var task = new RenderTask(directory, composition, stage.getScene());
|
||||
task.messageProperty().addListener(ev -> {
|
||||
stage.setTitle(task.getMessage());
|
||||
});
|
||||
@ -257,6 +258,7 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
documentManager = new FileManager();
|
||||
populateExamples();
|
||||
initSyntaxHighlighter();
|
||||
changeFontSize(0);
|
||||
initUndoRedo();
|
||||
initCopyCutPaste();
|
||||
openExample();
|
||||
@ -266,7 +268,7 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
}
|
||||
|
||||
private void populateExamples() {
|
||||
val map = new LinkedHashMap<String, String>();
|
||||
final var map = new LinkedHashMap<String, String>();
|
||||
map.put("HotaruFX Logo", "hotarufx-logo.hfx");
|
||||
map.put("Font Awesome Icons", "font-awesome.hfx");
|
||||
map.put("HSV Color", "hsv.hfx");
|
||||
@ -280,19 +282,19 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
map.put("Blend Modes", "blend-modes.hfx");
|
||||
map.put("Stroke Ants", "stroke-ants.hfx");
|
||||
examplesMenu.getItems().clear();
|
||||
for (val entry : map.entrySet()) {
|
||||
val item = new MenuItem(entry.getKey());
|
||||
for (final var entry : map.entrySet()) {
|
||||
final var item = new MenuItem(entry.getKey());
|
||||
item.setOnAction(e -> openExample("/examples/" + entry.getValue()));
|
||||
examplesMenu.getItems().add(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void initSyntaxHighlighter() {
|
||||
val highlightProperty = syntaxHighlightingItem.selectedProperty();
|
||||
final var highlightProperty = syntaxHighlightingItem.selectedProperty();
|
||||
highlightProperty.addListener((observable, oldValue, highlightEnabled) -> {
|
||||
if (highlightEnabled) {
|
||||
// create event to reinit highlighter
|
||||
val pos = editor.getCaretPosition();
|
||||
final var pos = editor.getCaretPosition();
|
||||
editor.insertText(pos, " ");
|
||||
editor.replaceText(pos, pos + 1, "");
|
||||
} else {
|
||||
@ -304,16 +306,14 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
}
|
||||
|
||||
private void initUndoRedo() {
|
||||
undoButton.disableProperty().bind(
|
||||
Bindings.not(editor.undoAvailableProperty()));
|
||||
redoButton.disableProperty().bind(
|
||||
Bindings.not(editor.redoAvailableProperty()));
|
||||
undoButton.disableProperty().bind(editor.undoAvailableProperty().map(x -> !x));
|
||||
redoButton.disableProperty().bind(editor.redoAvailableProperty().map(x -> !x));
|
||||
undoButton.setOnAction(editorAction(editor::undo));
|
||||
redoButton.setOnAction(editorAction(editor::redo));
|
||||
}
|
||||
|
||||
private void initCopyCutPaste() {
|
||||
val selectionEmpty = new BooleanBinding() {
|
||||
final var selectionEmpty = new BooleanBinding() {
|
||||
{ bind(editor.selectionProperty()); }
|
||||
@Override
|
||||
protected boolean computeValue() {
|
||||
@ -367,7 +367,7 @@ public class EditorController implements Initializable, DocumentListener {
|
||||
}
|
||||
|
||||
private void openExample(String path) {
|
||||
val content = (path != null) ? readProgram(path) : fallbackProgram();
|
||||
final var content = (path != null) ? readProgram(path) : fallbackProgram();
|
||||
editor.replaceText(content);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import javafx.scene.Scene;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.util.Duration;
|
||||
import javax.imageio.ImageIO;
|
||||
import lombok.val;
|
||||
|
||||
public class RenderTask extends Task<Boolean> {
|
||||
|
||||
@ -31,25 +30,25 @@ public class RenderTask extends Task<Boolean> {
|
||||
|
||||
@Override
|
||||
protected Boolean call() throws Exception {
|
||||
val fxTimeline = timeLine.getFxTimeline();
|
||||
final var fxTimeline = timeLine.getFxTimeline();
|
||||
|
||||
val totalFrames = toFrame(fxTimeline.getTotalDuration());
|
||||
final var totalFrames = toFrame(fxTimeline.getTotalDuration());
|
||||
int frame = 0;
|
||||
while (frame < totalFrames) {
|
||||
updateProgress(frame, totalFrames);
|
||||
updateMessage(String.format("%d / %d", frame + 1, totalFrames));
|
||||
fxTimeline.jumpTo(toDuration(frame));
|
||||
|
||||
val image = newImage();
|
||||
final var image = newImage();
|
||||
|
||||
val latch = new CountDownLatch(1);
|
||||
final var latch = new CountDownLatch(1);
|
||||
Platform.runLater(() -> {
|
||||
scene.snapshot(image);
|
||||
latch.countDown();
|
||||
});
|
||||
latch.await();
|
||||
|
||||
val file = new File(directory, String.format("frame_%05d.png", frame + 1));
|
||||
final var file = new File(directory, String.format("frame_%05d.png", frame + 1));
|
||||
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);
|
||||
frame++;
|
||||
}
|
||||
|
@ -5,25 +5,18 @@ import javafx.scene.Scene;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
|
||||
public class Composition {
|
||||
|
||||
@Getter
|
||||
private final int
|
||||
virtualWidth, virtualHeight,
|
||||
sceneWidth, sceneHeight;
|
||||
@Getter
|
||||
private final double factor;
|
||||
|
||||
@Getter
|
||||
private final TimeLine timeline;
|
||||
|
||||
@Getter
|
||||
private final VirtualScene scene;
|
||||
|
||||
@Getter
|
||||
private final Paint background;
|
||||
|
||||
public Composition() {
|
||||
@ -53,17 +46,49 @@ public class Composition {
|
||||
scene = newScene();
|
||||
}
|
||||
|
||||
public int getVirtualWidth() {
|
||||
return virtualWidth;
|
||||
}
|
||||
|
||||
public int getVirtualHeight() {
|
||||
return virtualHeight;
|
||||
}
|
||||
|
||||
public int getSceneWidth() {
|
||||
return sceneWidth;
|
||||
}
|
||||
|
||||
public int getSceneHeight() {
|
||||
return sceneHeight;
|
||||
}
|
||||
|
||||
public double getFactor() {
|
||||
return factor;
|
||||
}
|
||||
|
||||
public TimeLine getTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
public VirtualScene getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public Paint getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
private VirtualScene newScene() {
|
||||
val group = new NodesGroup(sceneWidth, sceneHeight);
|
||||
final var group = new NodesGroup(sceneWidth, sceneHeight);
|
||||
group.setScaleX(1d / factor);
|
||||
group.setScaleY(1d / factor);
|
||||
group.setTranslateX(sceneWidth / 2);
|
||||
group.setTranslateY(sceneHeight / 2);
|
||||
group.setTranslateX(sceneWidth / 2f);
|
||||
group.setTranslateY(sceneHeight / 2f);
|
||||
return new VirtualScene(group, virtualWidth, virtualHeight);
|
||||
}
|
||||
|
||||
public Scene producePreviewScene() {
|
||||
val fxScene = new Scene(scene.getGroup(), sceneWidth, sceneHeight, background);
|
||||
final var fxScene = new Scene(scene.getGroup(), sceneWidth, sceneHeight, background);
|
||||
fxScene.setOnKeyPressed(e -> {
|
||||
switch (e.getCode()) {
|
||||
case SPACE:
|
||||
@ -92,8 +117,6 @@ public class Composition {
|
||||
}
|
||||
|
||||
public Scene produceRendererScene() {
|
||||
val fxScene = new Scene(scene.getGroup(), sceneWidth, sceneHeight, background);
|
||||
|
||||
return fxScene;
|
||||
return new Scene(scene.getGroup(), sceneWidth, sceneHeight, background);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,38 @@
|
||||
package com.annimon.hotarufx.visual;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import java.util.Objects;
|
||||
|
||||
@RequiredArgsConstructor(staticName="of")
|
||||
@EqualsAndHashCode
|
||||
public class KeyFrame implements Comparable<KeyFrame> {
|
||||
|
||||
@Getter
|
||||
public static KeyFrame of(int frame) {
|
||||
return new KeyFrame(frame);
|
||||
}
|
||||
|
||||
private KeyFrame(int frame) {
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
private final int frame;
|
||||
|
||||
public int getFrame() {
|
||||
return frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(KeyFrame o) {
|
||||
return Integer.compare(frame, o.frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
KeyFrame keyFrame = (KeyFrame) o;
|
||||
return frame == keyFrame.frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(frame);
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,26 @@
|
||||
package com.annimon.hotarufx.visual;
|
||||
|
||||
import javafx.animation.Interpolator;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class KeyFrameValue<T> {
|
||||
|
||||
private final T value;
|
||||
private final Interpolator interpolator;
|
||||
|
||||
public KeyFrameValue(T value, Interpolator interpolator) {
|
||||
this.value = value;
|
||||
this.interpolator = interpolator;
|
||||
}
|
||||
|
||||
public KeyFrameValue(T value) {
|
||||
this(value, Interpolator.LINEAR);
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Interpolator getInterpolator() {
|
||||
return interpolator;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,22 @@
|
||||
package com.annimon.hotarufx.visual;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class Property {
|
||||
|
||||
@Getter
|
||||
private final PropertyType type;
|
||||
|
||||
@Getter
|
||||
private final Supplier<PropertyTimeline<?>> property;
|
||||
|
||||
public Property(PropertyType type, Supplier<PropertyTimeline<?>> property) {
|
||||
this.type = type;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public PropertyType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Supplier<PropertyTimeline<?>> getProperty() {
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,7 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import javafx.animation.Interpolator;
|
||||
import javafx.beans.value.WritableValue;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class PropertyTimeline<T> {
|
||||
|
||||
private final WritableValue<T> property;
|
||||
@ -17,6 +15,14 @@ public class PropertyTimeline<T> {
|
||||
keyFrames = new TreeMap<>();
|
||||
}
|
||||
|
||||
public WritableValue<T> getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public Map<KeyFrame, KeyFrameValue<T>> getKeyFrames() {
|
||||
return keyFrames;
|
||||
}
|
||||
|
||||
public PropertyTimeline<T> add(KeyFrame keyFrame, T value) {
|
||||
keyFrames.put(keyFrame, new KeyFrameValue<>(value));
|
||||
return this;
|
||||
|
@ -13,11 +13,7 @@ import java.util.function.Function;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Font;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public enum PropertyType {
|
||||
|
||||
BOOLEAN(Value::asBoolean, o -> NumberValue.fromBoolean(Boolean.TRUE.equals(o))),
|
||||
@ -28,6 +24,11 @@ public enum PropertyType {
|
||||
PAINT(v -> Color.valueOf(v.asString()), o -> new StringValue(o.toString())),
|
||||
FONT(toFont(), object -> new FontValue((Font) object));
|
||||
|
||||
PropertyType(Function<Value, Object> fromHFX, Function<Object, Value> toHFX) {
|
||||
this.fromHFX = fromHFX;
|
||||
this.toHFX = toHFX;
|
||||
}
|
||||
|
||||
private final Function<Value, Object> fromHFX;
|
||||
private final Function<Object, Value> toHFX;
|
||||
|
||||
|
@ -3,15 +3,11 @@ package com.annimon.hotarufx.visual;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.util.Duration;
|
||||
import lombok.Getter;
|
||||
import lombok.val;
|
||||
|
||||
public class TimeLine {
|
||||
|
||||
@Getter
|
||||
private final double frameRate;
|
||||
|
||||
@Getter
|
||||
private final Timeline fxTimeline;
|
||||
|
||||
public TimeLine(double frameRate) {
|
||||
@ -19,6 +15,14 @@ public class TimeLine {
|
||||
fxTimeline = new Timeline(frameRate);
|
||||
}
|
||||
|
||||
public double getFrameRate() {
|
||||
return frameRate;
|
||||
}
|
||||
|
||||
public Timeline getFxTimeline() {
|
||||
return fxTimeline;
|
||||
}
|
||||
|
||||
public void addKeyFrame(KeyFrame keyFrame, KeyValue fxKeyValue) {
|
||||
fxTimeline.getKeyFrames().add(new javafx.animation.KeyFrame(
|
||||
duration(keyFrame), fxKeyValue));
|
||||
@ -44,14 +48,14 @@ public class TimeLine {
|
||||
|
||||
public void seekFrame(final int value) {
|
||||
fxTimeline.pause();
|
||||
val offset = Duration.millis(1000d * Math.abs(value) / frameRate);
|
||||
val now = fxTimeline.getCurrentTime();
|
||||
val newDuration = value > 0 ? now.add(offset) : now.subtract(offset);
|
||||
final var offset = Duration.millis(1000d * Math.abs(value) / frameRate);
|
||||
final var now = fxTimeline.getCurrentTime();
|
||||
final var newDuration = value > 0 ? now.add(offset) : now.subtract(offset);
|
||||
fxTimeline.jumpTo(newDuration);
|
||||
}
|
||||
|
||||
public void seek(final int sec) {
|
||||
val now = fxTimeline.getCurrentTime();
|
||||
final var now = fxTimeline.getCurrentTime();
|
||||
fxTimeline.jumpTo(now.add(Duration.seconds(sec)));
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,31 @@ package com.annimon.hotarufx.visual;
|
||||
|
||||
import com.annimon.hotarufx.ui.control.NodesGroup;
|
||||
import javafx.scene.Node;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class VirtualScene {
|
||||
|
||||
@Getter
|
||||
private final NodesGroup group;
|
||||
|
||||
@Getter
|
||||
private final int virtualWidth, virtualHeight;
|
||||
|
||||
public VirtualScene(NodesGroup group, int virtualWidth, int virtualHeight) {
|
||||
this.group = group;
|
||||
this.virtualWidth = virtualWidth;
|
||||
this.virtualHeight = virtualHeight;
|
||||
}
|
||||
|
||||
public NodesGroup getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public int getVirtualWidth() {
|
||||
return virtualWidth;
|
||||
}
|
||||
|
||||
public int getVirtualHeight() {
|
||||
return virtualHeight;
|
||||
}
|
||||
|
||||
public void add(Node node) {
|
||||
group.getChildren().add(node);
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.scene.Group;
|
||||
import lombok.val;
|
||||
import static com.annimon.hotarufx.visual.PropertyType.BOOLEAN;
|
||||
|
||||
public class GroupNode extends ObjectNode {
|
||||
@ -27,7 +26,7 @@ public class GroupNode extends ObjectNode {
|
||||
super(group);
|
||||
this.group = group;
|
||||
this.nodes = new ArrayList<>(nodes);
|
||||
val fxNodes = nodes.stream()
|
||||
final var fxNodes = nodes.stream()
|
||||
.map(ObjectNode::getFxNode)
|
||||
.collect(Collectors.toList());
|
||||
group.getChildren().addAll(fxNodes);
|
||||
|
@ -14,9 +14,6 @@ import javafx.beans.value.WritableValue;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.effect.BlendMode;
|
||||
import javafx.util.StringConverter;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.val;
|
||||
import static com.annimon.hotarufx.visual.PropertyType.*;
|
||||
|
||||
public abstract class ObjectNode {
|
||||
@ -31,7 +28,6 @@ public abstract class ObjectNode {
|
||||
private PropertyTimelineHolder<Number> scaleX, scaleY, scaleZ;
|
||||
private PropertyTimelineHolder<Number> layoutX, layoutY;
|
||||
private PropertyTimelineHolder<String> blendMode;
|
||||
@Getter @Setter
|
||||
private boolean isRenderable;
|
||||
|
||||
public ObjectNode(Node node) {
|
||||
@ -57,6 +53,14 @@ public abstract class ObjectNode {
|
||||
return node;
|
||||
}
|
||||
|
||||
public boolean isRenderable() {
|
||||
return isRenderable;
|
||||
}
|
||||
|
||||
public void setRenderable(boolean renderable) {
|
||||
isRenderable = renderable;
|
||||
}
|
||||
|
||||
public PropertyTimeline<Boolean> visibleProperty() {
|
||||
return visible.setIfEmptyThenGet(node::visibleProperty);
|
||||
}
|
||||
@ -155,7 +159,7 @@ public abstract class ObjectNode {
|
||||
|
||||
protected <T extends Enum<T>> Supplier<WritableValue<String>> enumToString(Class<T> enumClass, ObjectProperty<T> property) {
|
||||
return () -> {
|
||||
val stringProperty = new SimpleStringProperty();
|
||||
final var stringProperty = new SimpleStringProperty();
|
||||
stringProperty.bindBidirectional(property, new StringConverter<T>() {
|
||||
@Override
|
||||
public String toString(T object) {
|
||||
@ -174,7 +178,7 @@ public abstract class ObjectNode {
|
||||
return Enum.valueOf(enumClass, string);
|
||||
} catch (IllegalArgumentException e) {
|
||||
try {
|
||||
val number = (int) Double.parseDouble(string);
|
||||
final var number = (int) Double.parseDouble(string);
|
||||
return enumClass.cast(EnumSet.allOf(enumClass).toArray()[number]);
|
||||
} catch (Exception ex) {
|
||||
throw new HotaruRuntimeException("No constant " + string
|
||||
|
@ -3,13 +3,15 @@ package com.annimon.hotarufx.visual.visitors;
|
||||
import com.annimon.hotarufx.visual.TimeLine;
|
||||
import com.annimon.hotarufx.visual.VirtualScene;
|
||||
import com.annimon.hotarufx.visual.objects.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class RenderVisitor implements NodeVisitor<Void, VirtualScene> {
|
||||
|
||||
private final TimeLine timeline;
|
||||
|
||||
public RenderVisitor(TimeLine timeline) {
|
||||
this.timeline = timeline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ArcNode node, VirtualScene scene) {
|
||||
return render(node, scene);
|
||||
|
@ -16,7 +16,7 @@
|
||||
<LineText />
|
||||
|
||||
<LineText />
|
||||
<LineText styleClass="bold" content="0.9.1" />
|
||||
<LineText styleClass="bold" content="1.0.0" />
|
||||
|
||||
<LineText />
|
||||
<LineText content="Programming language for creating animations" />
|
||||
|
@ -272,7 +272,7 @@
|
||||
})
|
||||
</code>
|
||||
</LibraryItem>
|
||||
<LibraryItem text="SVG Hearth">
|
||||
<LibraryItem text="SVG Heart">
|
||||
<graphic>
|
||||
<SVGPath content="M23.6,0c-3.4,0-6.3,2.7-7.6,5.6C14.7,2.7,11.8,0,8.4,0C3.8,0,0,3.8,0,8.4c0,9.4,9.5,11.9,16,21.2 6.1-9.3,16-12.1,16-21.2C32,3.8,28.2,0,23.6,0z"
|
||||
fill="#c91720"
|
||||
|
@ -6,7 +6,6 @@ import com.annimon.hotarufx.lib.NumberValue;
|
||||
import com.annimon.hotarufx.lib.Validator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import static com.annimon.hotarufx.bundles.FunctionInfo.of;
|
||||
import static com.annimon.hotarufx.bundles.FunctionType.COMMON;
|
||||
@ -30,7 +29,7 @@ public class AssertionsBundle implements Bundle {
|
||||
private static Function assertHasVariable(Context context) {
|
||||
return args -> {
|
||||
Validator.with(args).check(1);
|
||||
val name = args[0].asString();
|
||||
final var name = args[0].asString();
|
||||
Assertions.assertTrue(context.variables().containsKey(name));
|
||||
return NumberValue.ZERO;
|
||||
};
|
||||
@ -39,7 +38,7 @@ public class AssertionsBundle implements Bundle {
|
||||
private static Function assertHasFunction(Context context) {
|
||||
return args -> {
|
||||
Validator.with(args).check(1);
|
||||
val name = args[0].asString();
|
||||
final var name = args[0].asString();
|
||||
Assertions.assertTrue(context.functions().containsKey(name));
|
||||
return NumberValue.ZERO;
|
||||
};
|
||||
@ -56,8 +55,8 @@ public class AssertionsBundle implements Bundle {
|
||||
private static Function assertEquals(Context context) {
|
||||
return args -> {
|
||||
Validator.with(args).check(2);
|
||||
val expectedValue = args[0];
|
||||
val actualValue = args[1];
|
||||
final var expectedValue = args[0];
|
||||
final var actualValue = args[1];
|
||||
Assertions.assertEquals(expectedValue, actualValue);
|
||||
return NumberValue.ZERO;
|
||||
};
|
||||
|
@ -2,7 +2,6 @@ package com.annimon.hotarufx.bundles;
|
||||
|
||||
import com.annimon.hotarufx.lib.Context;
|
||||
import com.annimon.hotarufx.lib.NumberValue;
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
@ -11,7 +10,7 @@ class CompositionBundleTest {
|
||||
|
||||
@Test
|
||||
void testBundle() {
|
||||
val context = new Context();
|
||||
final var context = new Context();
|
||||
BundleLoader.loadSingle(context, CompositionBundle.class);
|
||||
|
||||
assertThat(context.functions(), hasKey("composition"));
|
||||
|
@ -10,7 +10,6 @@ import com.annimon.hotarufx.visual.objects.CircleNode;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import javafx.scene.paint.Color;
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
@ -19,7 +18,7 @@ class NodesBundleTest {
|
||||
|
||||
@Test
|
||||
void testBundle() {
|
||||
val context = new Context();
|
||||
final var context = new Context();
|
||||
BundleLoader.load(context, Arrays.asList(
|
||||
CompositionBundle.class,
|
||||
NodesBundle.class
|
||||
@ -27,20 +26,20 @@ class NodesBundleTest {
|
||||
|
||||
assertThat(context.functions(), hasKey("circle"));
|
||||
|
||||
val map = new HashMap<String, Value>();
|
||||
final var map = new HashMap<String, Value>();
|
||||
map.put("translateZ", NumberValue.of(-40));
|
||||
map.put("cx", NumberValue.of(-10));
|
||||
map.put("radius", NumberValue.of(50));
|
||||
map.put("fill", new StringValue("#00AA00"));
|
||||
val value = context.functions().get("circle").execute(new MapValue(map));
|
||||
final var value = context.functions().get("circle").execute(new MapValue(map));
|
||||
|
||||
assertThat(value, instanceOf(NodeValue.class));
|
||||
|
||||
val nodeValue = (NodeValue) value;
|
||||
final var nodeValue = (NodeValue) value;
|
||||
assertThat(nodeValue.getNode(), notNullValue());
|
||||
assertThat(nodeValue.getNode(), instanceOf(CircleNode.class));
|
||||
|
||||
val circle = (CircleNode) nodeValue.getNode();
|
||||
final var circle = (CircleNode) nodeValue.getNode();
|
||||
assertThat(circle.circle.getCenterX(), closeTo(-10, 0.001));
|
||||
assertThat(circle.circle.getRadius(), closeTo(50, 0.001));
|
||||
assertThat(circle.circle.getFill(), is(Color.web("#00AA00")));
|
||||
|
@ -5,7 +5,6 @@ import com.annimon.hotarufx.lib.Function;
|
||||
import com.annimon.hotarufx.lib.NumberValue;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.val;
|
||||
import static com.annimon.hotarufx.bundles.FunctionInfo.of;
|
||||
import static com.annimon.hotarufx.bundles.FunctionType.COMMON;
|
||||
|
||||
@ -46,13 +45,13 @@ public class PrintBundle implements Bundle {
|
||||
|
||||
private static Function dump(Context context) {
|
||||
return args -> {
|
||||
val maxVariableLength = context.variables()
|
||||
final var maxVariableLength = context.variables()
|
||||
.keySet().stream()
|
||||
.mapToInt(String::length)
|
||||
.max()
|
||||
.orElse(20);
|
||||
System.out.println("\n\tVARIABLES");
|
||||
val format = "%"+maxVariableLength+"s %s%n";
|
||||
final var format = "%"+maxVariableLength+"s %s%n";
|
||||
context.variables().forEach((k, v) -> {
|
||||
System.out.printf(format, k, v);
|
||||
});
|
||||
|
@ -14,7 +14,6 @@ import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
@ -45,8 +44,8 @@ class ProgramTest {
|
||||
@MethodSource("programPathProvider")
|
||||
@ParameterizedTest
|
||||
void testProgram(Path path) {
|
||||
val context = new Context();
|
||||
val bundles = new ArrayList<Class<? extends Bundle>>();
|
||||
final var context = new Context();
|
||||
final var bundles = new ArrayList<Class<? extends Bundle>>();
|
||||
bundles.addAll(BundleLoader.runtimeBundles());
|
||||
bundles.add(AssertionsBundle.class);
|
||||
bundles.add(PrintBundle.class);
|
||||
|
@ -12,7 +12,6 @@ import com.annimon.hotarufx.parser.ast.UnitNode;
|
||||
import com.annimon.hotarufx.parser.ast.ValueNode;
|
||||
import com.annimon.hotarufx.parser.ast.VariableNode;
|
||||
import java.util.Arrays;
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
@ -69,23 +68,23 @@ class HotaruParserTest {
|
||||
Node node = p(input);
|
||||
assertThat(node, instanceOf(BlockNode.class));
|
||||
|
||||
val block = (BlockNode) node;
|
||||
final var block = (BlockNode) node;
|
||||
assertThat(block.statements.size(), is(2));
|
||||
|
||||
val expectedValues = Arrays.asList(
|
||||
final var expectedValues = Arrays.asList(
|
||||
NumberValue.fromBoolean(true),
|
||||
NumberValue.fromBoolean(false)
|
||||
);
|
||||
val it = expectedValues.iterator();
|
||||
final var it = expectedValues.iterator();
|
||||
|
||||
for (Node statement : block.statements) {
|
||||
assertThat(statement, instanceOf(AssignNode.class));
|
||||
|
||||
val assignNode = (AssignNode) statement;
|
||||
final var assignNode = (AssignNode) statement;
|
||||
assertThat(assignNode.target, instanceOf(VariableNode.class));
|
||||
assertThat(assignNode.value, instanceOf(ValueNode.class));
|
||||
|
||||
val value = ((ValueNode) assignNode.value).value;
|
||||
final var value = ((ValueNode) assignNode.value).value;
|
||||
assertThat(value, is(it.next()));
|
||||
}
|
||||
}
|
||||
@ -96,26 +95,26 @@ class HotaruParserTest {
|
||||
Node node = p(input);
|
||||
assertThat(node, instanceOf(BlockNode.class));
|
||||
|
||||
val block = (BlockNode) node;
|
||||
final var block = (BlockNode) node;
|
||||
assertThat(block.statements.size(), is(2));
|
||||
|
||||
val expectedValues = Arrays.asList(
|
||||
final var expectedValues = Arrays.asList(
|
||||
NumberValue.of(500),
|
||||
NumberValue.of(0.5)
|
||||
);
|
||||
val it = expectedValues.iterator();
|
||||
final var it = expectedValues.iterator();
|
||||
|
||||
for (Node statement : block.statements) {
|
||||
assertThat(statement, instanceOf(AssignNode.class));
|
||||
|
||||
val assignNode = (AssignNode) statement;
|
||||
final var assignNode = (AssignNode) statement;
|
||||
assertThat(assignNode.target, instanceOf(VariableNode.class));
|
||||
assertThat(assignNode.value, instanceOf(UnitNode.class));
|
||||
|
||||
val unitNode = (UnitNode) assignNode.value;
|
||||
final var unitNode = (UnitNode) assignNode.value;
|
||||
assertThat(unitNode.value, instanceOf(ValueNode.class));
|
||||
|
||||
val value = ((ValueNode) unitNode.value).value;
|
||||
final var value = ((ValueNode) unitNode.value).value;
|
||||
assertThat(value, is(it.next()));
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import com.annimon.hotarufx.lib.Value;
|
||||
import com.annimon.hotarufx.parser.HotaruParser;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
@ -120,7 +119,7 @@ class InterpreterVisitorTest {
|
||||
|
||||
@Test
|
||||
void testUnits() {
|
||||
val context = new Context();
|
||||
final var context = new Context();
|
||||
BundleLoader.loadSingle(context, CompositionBundle.class);
|
||||
context.functions().put("rate", context.functions().get("composition"));
|
||||
Value value;
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.annimon.hotarufx.visual;
|
||||
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
@ -9,7 +8,7 @@ class TimeLineTest {
|
||||
|
||||
@Test
|
||||
void add() {
|
||||
val timeline = new PropertyTimeline<String>(null);
|
||||
final var timeline = new PropertyTimeline<String>(null);
|
||||
timeline.add(KeyFrame.of(20), null);
|
||||
timeline.add(KeyFrame.of(10), null);
|
||||
timeline.add(KeyFrame.of(0), null);
|
||||
|
@ -10,7 +10,6 @@ import javafx.scene.paint.Color;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.Text;
|
||||
import lombok.val;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
@ -52,36 +51,36 @@ class NodePropertiesTypeTest {
|
||||
@SuppressWarnings("unchecked")
|
||||
void testNode(ObjectNode node, String name, Property property, String nodeName) {
|
||||
try {
|
||||
val value = property.getProperty().get().getProperty();
|
||||
final var value = property.getProperty().get().getProperty();
|
||||
switch (property.getType()) {
|
||||
case BOOLEAN:
|
||||
val booleanValue = (WritableValue<Boolean>) value;
|
||||
final var booleanValue = (WritableValue<Boolean>) value;
|
||||
booleanValue.setValue(true);
|
||||
assertTrue(booleanValue.getValue());
|
||||
break;
|
||||
case NUMBER:
|
||||
val numberValue = (WritableValue<Number>) value;
|
||||
final var numberValue = (WritableValue<Number>) value;
|
||||
numberValue.setValue(2);
|
||||
assertThat(numberValue.getValue().intValue(), is(2));
|
||||
break;
|
||||
case STRING:
|
||||
val stringValue = (WritableValue<String>) value;
|
||||
final var stringValue = (WritableValue<String>) value;
|
||||
stringValue.setValue("0");
|
||||
assertThat(stringValue.getValue(), is("0"));
|
||||
break;
|
||||
case NODE:
|
||||
case CLIP_NODE:
|
||||
val nodeValue = (WritableValue<Node>) value;
|
||||
final var nodeValue = (WritableValue<Node>) value;
|
||||
nodeValue.setValue(new Text("test"));
|
||||
assertThat(((Text) nodeValue.getValue()).getText(), is("test"));
|
||||
break;
|
||||
case PAINT:
|
||||
val paintValue = (WritableValue<Paint>) value;
|
||||
final var paintValue = (WritableValue<Paint>) value;
|
||||
paintValue.setValue(Color.BLUE);
|
||||
assertThat(paintValue.getValue(), is(Color.BLUE));
|
||||
break;
|
||||
case FONT:
|
||||
val fontValue = (WritableValue<Font>) value;
|
||||
final var fontValue = (WritableValue<Font>) value;
|
||||
fontValue.setValue(Font.getDefault());
|
||||
assertThat(fontValue.getValue().getFamily(), is(Font.getDefault().getFamily()));
|
||||
break;
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,5 @@
|
||||
#Mon Aug 21 12:17:04 EEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip
|
||||
|
22
gradlew
vendored
22
gradlew
vendored
@ -1,5 +1,21 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
@ -28,7 +44,7 @@ APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
@ -109,8 +125,8 @@ if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
18
gradlew.bat
vendored
18
gradlew.bat
vendored
@ -1,3 +1,19 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
Loading…
Reference in New Issue
Block a user