Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ private record CropSpec(int x, int y, int width, int height) {}

private record ScaleSpec(double scaleX, double scaleY) {}

private record DisplaySpec(int width, int height) {

private boolean isSpecified() {
return width > 0 || height > 0;
}
}

@Override
public Set<String> getTagNames() {
return Collections.singleton(TAG_NAME);
Expand All @@ -52,9 +59,17 @@ protected void compile(PageCompiler compiler, LytFlowParent parent, MdxJsxElemen
var align = el.getAttributeString("align", "left");
var title = el.getAttributeString("title", null);
var alt = el.getAttributeString("alt", null);
CropSpec crop = parseCropSpec(compiler, parent, el);
DisplaySpec display = parseDisplaySpec(compiler, parent, el);
CropSpec crop = parseCropSpec(compiler, parent, el, display != null && display.isSpecified());
ScaleSpec scale = parseScaleSpec(compiler, parent, el);
if (crop == null || scale == null) {
if (crop == null || display == null || scale == null) {
return;
}
if (display.isSpecified() && hasScaleAttributes(el)) {
parent.appendError(
compiler,
"FloatingImage displayWidth/displayHeight cannot be used with scaleX/scaleY.",
el);
return;
}

Expand All @@ -75,6 +90,8 @@ protected void compile(PageCompiler compiler, LytFlowParent parent, MdxJsxElemen
block.setCropHeight(crop.height());
block.setScaleX(scale.scaleX());
block.setScaleY(scale.scaleY());
block.setDisplayWidth(display.width());
block.setDisplayHeight(display.height());

// Resolve the image src to a string identifier for later script use without
// loading the actual asset at compile time.
Expand Down Expand Up @@ -243,7 +260,8 @@ public static int parseIntAttr(MdxJsxElementFields el, String name, int def) {
}

@Nullable
private static CropSpec parseCropSpec(PageCompiler compiler, LytFlowParent parent, MdxJsxElementFields el) {
private static CropSpec parseCropSpec(PageCompiler compiler, LytFlowParent parent, MdxJsxElementFields el,
boolean allowWholeImage) {
String widthValue = el.getAttributeString("width", null);
String widthAlias = el.getAttributeString("w", null);
String heightValue = el.getAttributeString("height", null);
Expand All @@ -256,6 +274,13 @@ private static CropSpec parseCropSpec(PageCompiler compiler, LytFlowParent paren
parent.appendError(compiler, "FloatingImage cannot use both height and h.", el);
return null;
}
if (!hasCropAttributes(el)) {
if (allowWholeImage) {
return new CropSpec(0, 0, -1, -1);
}
parent.appendError(compiler, "FloatingImage requires x, y, width or w, and height or h.", el);
return null;
}
Integer x = parseRequiredIntAttr(compiler, parent, el, "x");
Integer y = parseRequiredIntAttr(compiler, parent, el, "y");
Integer width = parseRequiredAliasedIntAttr(compiler, parent, el, "width", "w");
Expand All @@ -273,6 +298,14 @@ private static CropSpec parseCropSpec(PageCompiler compiler, LytFlowParent paren
return new CropSpec(x, y, width, height);
}

private static boolean hasCropAttributes(MdxJsxElementFields el) {
return el.getAttributeString("x", null) != null || el.getAttributeString("y", null) != null
|| el.getAttributeString("width", null) != null
|| el.getAttributeString("w", null) != null
|| el.getAttributeString("height", null) != null
|| el.getAttributeString("h", null) != null;
}

@Nullable
private static ScaleSpec parseScaleSpec(PageCompiler compiler, LytFlowParent parent, MdxJsxElementFields el) {
Double scaleX = parseDoubleAttr(compiler, parent, el, "scaleX", 1.0d);
Expand All @@ -287,6 +320,21 @@ private static ScaleSpec parseScaleSpec(PageCompiler compiler, LytFlowParent par
return new ScaleSpec(scaleX, scaleY);
}

@Nullable
private static DisplaySpec parseDisplaySpec(PageCompiler compiler, LytFlowParent parent, MdxJsxElementFields el) {
Integer width = parseOptionalPositiveIntAttr(compiler, parent, el, "displayWidth");
Integer height = parseOptionalPositiveIntAttr(compiler, parent, el, "displayHeight");
if ((width == null && el.getAttributeString("displayWidth", null) != null)
|| (height == null && el.getAttributeString("displayHeight", null) != null)) {
return null;
}
return new DisplaySpec(width != null ? width : -1, height != null ? height : -1);
}

private static boolean hasScaleAttributes(MdxJsxElementFields el) {
return el.getAttributeString("scaleX", null) != null || el.getAttributeString("scaleY", null) != null;
}

@Nullable
private static Integer parseRequiredAliasedIntAttr(PageCompiler compiler, LytFlowParent parent,
MdxJsxElementFields el, String primaryName, String aliasName) {
Expand Down Expand Up @@ -328,6 +376,24 @@ private static Integer parseRequiredIntAttr(PageCompiler compiler, LytFlowParent
}
}

@Nullable
private static Integer parseOptionalPositiveIntAttr(PageCompiler compiler, LytFlowParent parent,
MdxJsxElementFields el, String name) {
String value = el.getAttributeString(name, null);
if (value == null || value.trim()
.isEmpty()) {
return null;
}
try {
int parsed = Integer.parseInt(value.trim());
if (parsed > 0) {
return parsed;
}
} catch (NumberFormatException ignored) {}
parent.appendError(compiler, "FloatingImage " + name + " must be a positive integer.", el);
return null;
}

@Nullable
private static Double parseDoubleAttr(PageCompiler compiler, LytFlowParent parent, MdxJsxElementFields el,
String name, double defaultValue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public class LytImage extends LytBlock implements InteractiveElement {
private int cropHeight = -1;
private double scaleX = 1.0d;
private double scaleY = 1.0d;
private int displayWidth = -1;
private int displayHeight = -1;

@Getter
private final List<ImageRegionAnnotation> annotations = new ArrayList<>();
Expand Down Expand Up @@ -86,6 +88,11 @@ public void setScale(double scaleX, double scaleY) {
this.scaleY = scaleY > 0.0d ? scaleY : 1.0d;
}

public void setDisplaySize(int displayWidth, int displayHeight) {
this.displayWidth = displayWidth > 0 ? displayWidth : -1;
this.displayHeight = displayHeight > 0 ? displayHeight : -1;
}

@Override
protected LytRect computeLayout(LayoutContext context, int x, int y, int availableWidth) {
if (texture == null) {
Expand All @@ -97,7 +104,12 @@ protected LytRect computeLayout(LayoutContext context, int x, int y, int availab
int sourceHeight = Math.max(1, cropHeight > 0 ? cropHeight : size.height());
int width;
int height;
if (explicitWidth > 0 || explicitHeight > 0) {
if (displayWidth > 0 || displayHeight > 0) {
width = displayWidth > 0 ? displayWidth
: Math.max(1, (int) Math.round(displayHeight * sourceWidth / (double) sourceHeight));
height = displayHeight > 0 ? displayHeight
: Math.max(1, (int) Math.round(displayWidth * sourceHeight / (double) sourceWidth));
} else if (explicitWidth > 0 || explicitHeight > 0) {
width = explicitWidth > 0 ? explicitWidth : Math.max(1, (int) Math.round(sourceWidth * scaleX));
height = explicitHeight > 0 ? explicitHeight : Math.max(1, (int) Math.round(sourceHeight * scaleY));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public class LytImageBlock extends LytParagraph {
private double scaleX = 1.0d;
@Getter
private double scaleY = 1.0d;
@Getter
private int displayWidth = -1;
@Getter
private int displayHeight = -1;
@Nullable
private String align;
@Getter
Expand Down Expand Up @@ -99,6 +103,14 @@ public void setScaleY(double scaleY) {
this.scaleY = scaleY > 0.0d ? scaleY : 1.0d;
}

public void setDisplayWidth(int displayWidth) {
this.displayWidth = displayWidth > 0 ? displayWidth : -1;
}

public void setDisplayHeight(int displayHeight) {
this.displayHeight = displayHeight > 0 ? displayHeight : -1;
}

@Nullable
public String getAlign() {
return align;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public static void initialize() {
new AttributeSpec("h", AttrType.INT),
new AttributeSpec("scaleX", AttrType.FLOAT),
new AttributeSpec("scaleY", AttrType.FLOAT),
new AttributeSpec("displayWidth", AttrType.INT),
new AttributeSpec("displayHeight", AttrType.INT),
new AttributeSpec("sound", AttrType.STRING),
new AttributeSpec("soundSrc", AttrType.FILE_PATH),
new AttributeSpec("trigger", AttrType.STRING));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,7 @@ private static Result applyFloatingImage(String source, int start, int end) {
String selected = start < end ? sanitizeAttributeValue(source.substring(start, end)) : "";
String imagePath = selected.isEmpty() ? "test1.png" : selected;
String replacement = "<FloatingImage src=\"" + imagePath
+ "\" x=\"0\" y=\"0\" width=\"128\" height=\"128\" scaleX=\"1.0\" scaleY=\"1.0\" wrap=\"inline\" title=\"Example\" />";
+ "\" x=\"0\" y=\"0\" width=\"128\" height=\"128\" displayWidth=\"128\" displayHeight=\"128\" wrap=\"inline\" title=\"Example\" />";
int caretStart = start + replacement.indexOf(imagePath);
return new Result(
source.substring(0, start) + replacement + source.substring(end),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.hfstudio.guidenh.guide.internal.host.LytScript;
import com.hfstudio.guidenh.guide.internal.host.ScriptContext;
import com.hfstudio.guidenh.guide.internal.host.ScriptType;
import com.hfstudio.guidenh.guide.render.GuidePageTexture;

public class FloatingImageScript implements LytScript {

Expand Down Expand Up @@ -53,19 +54,20 @@ public void onEvent(Object node, LytEvent event, ScriptContext ctx) {
return;
}

byte[] imageData = ctx.loadAsset(imageId);
LytImage image = new LytImage();
image.setImage(imageId, imageData); // null imageData → GuidePageTexture.missing()
image.setTexture(imageId, GuidePageTexture.loadCached(imageId, () -> ctx.loadAsset(imageId)));

String alt = placeholder.getAlt();
if (alt != null && !alt.isEmpty()) image.setAlt(alt);
String title = placeholder.getTitle();
if (title != null && !title.isEmpty()) {
image.setTitle(title);
} else if (imageData == null) {
image.setTitle("Missing image: " + src);
}
if (imageData != null) {
} else if (image.getTexture()
.isMissing()) {
image.setTitle("Missing image: " + src);
}
if (!image.getTexture()
.isMissing()) {
var size = image.getTexture()
.getSize();
int cropRight = placeholder.getCropX() + placeholder.getCropWidth();
Expand All @@ -81,6 +83,7 @@ public void onEvent(Object node, LytEvent event, ScriptContext ctx) {
placeholder.getCropWidth(),
placeholder.getCropHeight());
image.setScale(placeholder.getScaleX(), placeholder.getScaleY());
image.setDisplaySize(placeholder.getDisplayWidth(), placeholder.getDisplayHeight());
image.setMarginTop(placeholder.getMarginTop());
image.setMarginLeft(placeholder.getMarginLeft());
image.setMarginRight(placeholder.getMarginRight());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.hfstudio.guidenh.guide.internal.host.LytScript;
import com.hfstudio.guidenh.guide.internal.host.ScriptContext;
import com.hfstudio.guidenh.guide.internal.host.ScriptType;
import com.hfstudio.guidenh.guide.render.GuidePageTexture;

public class ImageScript implements LytScript {

Expand Down Expand Up @@ -52,9 +53,8 @@ public void onEvent(Object node, LytEvent event, ScriptContext ctx) {
return;
}

byte[] imageData = ctx.loadAsset(imageId);
LytImage image = new LytImage();
image.setImage(imageId, imageData); // null imageData → GuidePageTexture.missing()
image.setTexture(imageId, GuidePageTexture.loadCached(imageId, () -> ctx.loadAsset(imageId)));

String alt = placeholder.getAlt();
if (alt != null && !alt.isEmpty()) image.setAlt(alt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Supplier;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
Expand Down Expand Up @@ -66,6 +67,11 @@ public static GuidePageTexture missing() {
return MISSING;
}

@Nullable
public static synchronized GuidePageTexture getCached(ResourceLocation id) {
return CACHE.get(id);
}

public static GuidePageTexture of(ResourceLocation texture) {
return new GuidePageTexture(texture, 256, 256);
}
Expand All @@ -88,6 +94,11 @@ public static synchronized GuidePageTexture load(ResourceLocation id, byte[] ima
}
}

public static GuidePageTexture loadCached(ResourceLocation id, Supplier<byte[]> assetLoader) {
GuidePageTexture cached = getCached(id);
return cached != null ? cached : load(id, assetLoader.get());
}

public static synchronized void clear() {
TextureManager textureManager = Minecraft.getMinecraft()
.getTextureManager();
Expand Down
Loading