diff --git a/build.gradle.kts b/build.gradle.kts index a33eb91..fb10396 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "dev.dediamondpro" -version = "1.0-SNAPSHOT62" +version = "1.0-SNAPSHOT70" repositories { mavenCentral() diff --git a/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/LayoutConfigImpl.kt b/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/LayoutConfigImpl.kt index 93e4d0f..2abecaa 100644 --- a/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/LayoutConfigImpl.kt +++ b/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/LayoutConfigImpl.kt @@ -20,7 +20,7 @@ class LayoutConfigImpl( strikethrough: Boolean = false, partOfLink: Boolean = false, preFormatted: Boolean = false, - spacingConfig: SpacingConfig = SpacingConfig(4f, 4f, 4f, 16f), + spacingConfig: SpacingConfig = SpacingConfig(2f, 6f, 16f), headingConfig: HeadingConfig = HeadingConfig(2f, 1.66f, 1.33f, 1f, 1.2f, 1f), imageProvider: ImageProvider = DefaultImageProvider.INSTANCE, browserProvider: BrowserProvider = ElementaBrowserProvider diff --git a/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/MineMarkComponent.kt b/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/MineMarkComponent.kt index 9bb447b..dcb3b6b 100644 --- a/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/MineMarkComponent.kt +++ b/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/MineMarkComponent.kt @@ -80,6 +80,7 @@ class MineMarkComponent( .addElement(Elements.IMAGE, ::MarkdownImageComponent) .addElement(Elements.HORIZONTAL_LINE, ::MarkdownHorizontalLineComponent) .addElement(Elements.LIST_ELEMENT, ::MarkdownListElementComponent) + .addElement(Elements.BLOCKQUOTE, ::MarkdownBlockquoteComponent) } } } \ No newline at end of file diff --git a/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/elements/MarkdownBlockquoteComponent.kt b/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/elements/MarkdownBlockquoteComponent.kt new file mode 100644 index 0000000..3b10b2a --- /dev/null +++ b/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/elements/MarkdownBlockquoteComponent.kt @@ -0,0 +1,29 @@ +package dev.dediamondpro.minemark.elementa.elements + +import dev.dediamondpro.minemark.LayoutData +import dev.dediamondpro.minemark.elementa.LayoutConfigImpl +import dev.dediamondpro.minemark.elementa.RenderData +import dev.dediamondpro.minemark.elements.Element +import dev.dediamondpro.minemark.elements.impl.BlockQuoteElement +import gg.essential.elementa.components.UIBlock +import org.xml.sax.Attributes +import java.awt.Color + +class MarkdownBlockquoteComponent( + layoutConfig: LayoutConfigImpl, + parent: Element?, + qName: String, attributes: Attributes? +) : BlockQuoteElement(layoutConfig, parent, qName, attributes) { + override fun drawBlock(x: Float, y: Float, height: Float, renderData: RenderData) { + UIBlock.drawBlockSized( + renderData.matrixStack, + Color.WHITE, + (x + 4f).toDouble(), y.toDouble(), + 2.0, height.toDouble() + ) + } + + override fun getBlockWidth(layoutData: LayoutData?): Float { + return 4f + 2f + 10f + } +} \ No newline at end of file diff --git a/src/main/java/dev/dediamondpro/minemark/LayoutConfig.java b/src/main/java/dev/dediamondpro/minemark/LayoutConfig.java index f630203..b5855a6 100644 --- a/src/main/java/dev/dediamondpro/minemark/LayoutConfig.java +++ b/src/main/java/dev/dediamondpro/minemark/LayoutConfig.java @@ -147,20 +147,26 @@ public enum Alignment { } public static class SpacingConfig { - private final float textSpacing; + private final float textPadding; private final float paragraphPadding; private final float listPadding; private final float listIndentSpacing; + private final float blockQuotePadding; - public SpacingConfig(float textSpacing, float paragraphPadding, float listPadding, float listIndentSpacing) { - this.textSpacing = textSpacing; + public SpacingConfig(float textPadding, float paragraphPadding, float listIndentSpacing, float listPadding, float blockQuotePadding) { + this.textPadding = textPadding; this.paragraphPadding = paragraphPadding; - this.listPadding = listPadding; this.listIndentSpacing = listIndentSpacing; + this.listPadding = listPadding; + this.blockQuotePadding = blockQuotePadding; + } + + public SpacingConfig(float textPadding, float paragraphPadding, float listIndentSpacing) { + this(textPadding, paragraphPadding, listIndentSpacing, paragraphPadding, paragraphPadding); } - public float getTextSpacing() { - return textSpacing; + public float getTextPadding() { + return textPadding; } public float getParagraphPadding() { @@ -174,6 +180,10 @@ public float getListPadding() { public float getListIndentSpacing() { return listIndentSpacing; } + + public float getBlockQuotePadding() { + return blockQuotePadding; + } } public static class HeadingConfig { diff --git a/src/main/java/dev/dediamondpro/minemark/LayoutData.java b/src/main/java/dev/dediamondpro/minemark/LayoutData.java index 598d5af..843d232 100644 --- a/src/main/java/dev/dediamondpro/minemark/LayoutData.java +++ b/src/main/java/dev/dediamondpro/minemark/LayoutData.java @@ -7,6 +7,8 @@ public class LayoutData { private final ArrayList> elementListeners = new ArrayList<>(); private MarkDownLine currentLine = new MarkDownLine(0f); private final float maxWidth; + private boolean topSpacingLocked = false; + private boolean bottomSpacingLocked = false; public LayoutData(float maxWidth) { this.maxWidth = maxWidth; @@ -16,8 +18,14 @@ public boolean isLineEmpty() { return currentLine.width == 0f; } + public boolean isLineOccupied() { + return currentLine.width != 0f; + } + public void nextLine() { currentLine = new MarkDownLine(currentLine.getBottomY()); + topSpacingLocked = false; + bottomSpacingLocked = false; } public MarkDownElementPosition addElement(LayoutConfig.Alignment alignment, float width, float height) { @@ -79,6 +87,39 @@ public MarkDownLine getCurrentLine() { return currentLine; } + public void updateTopSpacing(float spacing) { + if (topSpacingLocked) return; + currentLine.topSpacing = Math.max(currentLine.topSpacing, spacing); + } + + public void updateBottomSpacing(float spacing) { + if (bottomSpacingLocked) return; + currentLine.bottomSpacing = Math.max(currentLine.bottomSpacing, spacing); + } + + public void updatePadding(float padding) { + updateTopSpacing(padding); + updateBottomSpacing(padding); + } + + public void setTopSpacing(float spacing) { + if (topSpacingLocked) return; + currentLine.topSpacing = spacing; + } + + public void setBottomSpacing(float spacing) { + if (bottomSpacingLocked) return; + currentLine.bottomSpacing = spacing; + } + + public void lockTopSpacing() { + topSpacingLocked = true; + } + + public void lockBottomSpacing() { + bottomSpacingLocked = true; + } + public static class MarkDownElementPosition { private final MarkDownLine line; private final float x; @@ -121,7 +162,7 @@ public float getY() { } public float getBottomY() { - return line.getBottomY(); + return line.getBottomY() - line.getBottomSpacing(); } public float getHeight() { @@ -132,10 +173,6 @@ public float getWidth() { return width; } - public float getLineHeight() { - return line.getHeight(); - } - public boolean isInside(float x, float y) { return x >= getX() && x <= getRightX() && y >= getY() && y <= getBottomY(); @@ -146,6 +183,8 @@ public static class MarkDownLine { private final float y; private float width = 0f; private float height = 0f; + private float topSpacing = 0f; + private float bottomSpacing = 0f; public MarkDownLine(float y) { this.y = y; @@ -160,11 +199,23 @@ public float getWidth() { } public float getHeight() { + return topSpacing + height + bottomSpacing; + } + + public float getRawHeight() { return height; } public float getBottomY() { - return y + height; + return y + getHeight(); + } + + public float getBottomSpacing() { + return bottomSpacing; + } + + public float getTopSpacing() { + return topSpacing; } } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/BasicElement.java b/src/main/java/dev/dediamondpro/minemark/elements/BasicElement.java index cfc759f..7d4acaa 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/BasicElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/BasicElement.java @@ -24,11 +24,11 @@ protected void draw(float xOffset, float yOffset, float mouseX, float mouseY, R protected void generateLayout(LayoutData layoutData) { width = getWidth(layoutData); height = getHeight(layoutData); - if ((!(this instanceof Inline) && !layoutData.isLineEmpty()) || layoutData.getX() + width > layoutData.getMaxWidth()) { + if ((!(this instanceof Inline) && layoutData.isLineOccupied()) || layoutData.getX() + width > layoutData.getMaxWidth()) { layoutData.nextLine(); } position = layoutData.addElement(layoutConfig.getAlignment(), width, height); - if (!(this instanceof Inline) && !layoutData.isLineEmpty()) { + if (!(this instanceof Inline) && layoutData.isLineOccupied()) { layoutData.nextLine(); } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/ChildBasedElement.java b/src/main/java/dev/dediamondpro/minemark/elements/ChildBasedElement.java index 16942f3..6530fa1 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/ChildBasedElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/ChildBasedElement.java @@ -20,22 +20,16 @@ protected void draw(float xOffset, float yOffset, float mouseX, float mouseY, R @Override protected void generateLayout(LayoutData layoutData) { - if (!(this instanceof Inline) && !layoutData.isLineEmpty()) { + if (!(this instanceof Inline) && layoutData.isLineOccupied()) { layoutData.nextLine(); } float padding = getPadding(layoutData); - if (padding != 0 && !(parent instanceof NoPadding)) { - layoutData.setLineHeight(padding); - layoutData.nextLine(); - } + layoutData.updateTopSpacing(padding); for (Element child : children) { child.generateLayout(layoutData); } - if (!(this instanceof Inline) && !layoutData.isLineEmpty()) { - layoutData.nextLine(); - } - if (padding != 0 && !(parent instanceof NoPadding)) { - layoutData.setLineHeight(padding); + layoutData.updateBottomSpacing(padding); + if(!(this instanceof Inline)) { layoutData.nextLine(); } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/Element.java b/src/main/java/dev/dediamondpro/minemark/elements/Element.java index 9ed0a40..9cb77e4 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/Element.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/Element.java @@ -83,6 +83,10 @@ protected void onMouseClicked(MouseButton button, float mouseX, float mouseY) { } } + public int getChildIndex(Element element) { + return children.indexOf(element); + } + /** * Build a tree of elements for debugging purposes */ diff --git a/src/main/java/dev/dediamondpro/minemark/elements/Elements.java b/src/main/java/dev/dediamondpro/minemark/elements/Elements.java index e4276af..3db32d6 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/Elements.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/Elements.java @@ -13,7 +13,8 @@ public enum Elements { IMAGE(listOf("img")), LIST_PARENT(listOf("ol", "ul")), LIST_ELEMENT(listOf("li")), - HORIZONTAL_LINE(listOf("hr")) + HORIZONTAL_LINE(listOf("hr")), + BLOCKQUOTE(listOf("blockquote")) ; public final List tags; diff --git a/src/main/java/dev/dediamondpro/minemark/elements/NoPadding.java b/src/main/java/dev/dediamondpro/minemark/elements/NoPadding.java deleted file mode 100644 index ebedc10..0000000 --- a/src/main/java/dev/dediamondpro/minemark/elements/NoPadding.java +++ /dev/null @@ -1,9 +0,0 @@ -package dev.dediamondpro.minemark.elements; - - -/** - * Interface to tell elements like {@link dev.dediamondpro.minemark.elements.impl.ParagraphElement} to not add any padding. - * Useful for elements like {@link dev.dediamondpro.minemark.elements.impl.list.ListElement} - */ -public interface NoPadding { -} diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/BlockQuoteElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/BlockQuoteElement.java new file mode 100644 index 0000000..423d7f1 --- /dev/null +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/BlockQuoteElement.java @@ -0,0 +1,42 @@ +package dev.dediamondpro.minemark.elements.impl; + +import dev.dediamondpro.minemark.LayoutConfig; +import dev.dediamondpro.minemark.LayoutData; +import dev.dediamondpro.minemark.elements.ChildBasedElement; +import dev.dediamondpro.minemark.elements.Element; +import dev.dediamondpro.minemark.elements.Inline; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.xml.sax.Attributes; + +public abstract class BlockQuoteElement extends ChildBasedElement implements Inline { + protected LayoutData.MarkDownElementPosition position; + protected float blockWidth; + + public BlockQuoteElement(@NotNull L layoutConfig, @Nullable Element parent, @NotNull String qName, @Nullable Attributes attributes) { + super(layoutConfig, parent, qName, attributes); + } + + @Override + protected void draw(float xOffset, float yOffset, float mouseX, float mouseY, R renderData) { + drawBlock(xOffset + position.getX(), yOffset + position.getY(), position.getHeight(), renderData); + super.draw(xOffset + position.getX() + blockWidth, yOffset + position.getY(), mouseX, mouseY, renderData); + } + + @Override + protected void generateLayout(LayoutData layoutData) { + blockWidth = getBlockWidth(layoutData); + if (layoutData.isLineOccupied()) { + layoutData.nextLine(); + } + layoutData.updatePadding(layoutConfig.getSpacingConfig().getBlockQuotePadding()); + LayoutData newLayoutData = new LayoutData(layoutData.getMaxWidth() - blockWidth); + super.generateLayout(newLayoutData); + position = layoutData.addElement(LayoutConfig.Alignment.LEFT, layoutData.getMaxWidth(), newLayoutData.getY() + newLayoutData.getLineHeight()); + layoutData.nextLine(); + } + + public abstract void drawBlock(float x, float y, float height, R renderData); + + public abstract float getBlockWidth(LayoutData layoutData); +} diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/ParagraphElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/ParagraphElement.java index 37b52a8..63c55f5 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/ParagraphElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/ParagraphElement.java @@ -4,7 +4,6 @@ import dev.dediamondpro.minemark.LayoutData; import dev.dediamondpro.minemark.elements.ChildBasedElement; import dev.dediamondpro.minemark.elements.Element; -import dev.dediamondpro.minemark.elements.NoPadding; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.xml.sax.Attributes; diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/AlignmentElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/AlignmentElement.java index dd13b81..4977f73 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/AlignmentElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/AlignmentElement.java @@ -32,7 +32,7 @@ public AlignmentElement(@NotNull L layoutConfig, @Nullable Element parent, @Override protected void generateLayout(LayoutData layoutData) { - if (!layoutData.isLineEmpty()) layoutData.nextLine(); + if (layoutData.isLineOccupied()) layoutData.nextLine(); super.generateLayout(layoutData); } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/list/ListElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/list/ListElement.java index c5ac6b5..bc44414 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/list/ListElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/list/ListElement.java @@ -5,12 +5,11 @@ import dev.dediamondpro.minemark.elements.ChildBasedElement; import dev.dediamondpro.minemark.elements.Element; import dev.dediamondpro.minemark.elements.Inline; -import dev.dediamondpro.minemark.elements.NoPadding; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.xml.sax.Attributes; -public abstract class ListElement extends ChildBasedElement implements Inline, NoPadding { +public abstract class ListElement extends ChildBasedElement implements Inline { protected final ListHolderElement.ListType listType; protected final int elementIndex; protected LayoutData.MarkDownElementPosition markerPosition; @@ -25,7 +24,7 @@ public ListElement(@NotNull L layoutConfig, @Nullable Element parent, @Not } ListHolderElement holder = (ListHolderElement) parent; listType = holder.getListType(); - elementIndex = holder.getElementPosition(this); + elementIndex = holder.getChildIndex(this); } @Override @@ -34,16 +33,26 @@ protected void generateLayout(LayoutData layoutData) { markerWidth = getMarkerWidth(); markerHeight = getMarkerHeight(); indentX = Math.max(markerWidth, layoutConfig.getSpacingConfig().getListIndentSpacing()); + layoutData.updatePadding(layoutConfig.getSpacingConfig().getTextPadding()); markerPosition = layoutData.addElement(LayoutConfig.Alignment.LEFT, indentX, markerHeight); + LayoutData newLayoutData = new LayoutData(layoutData.getMaxWidth() - indentX); + newLayoutData.setTopSpacing(layoutData.getCurrentLine().getTopSpacing()); + newLayoutData.lockTopSpacing(); newLayoutData.updateLineHeight(layoutData.getLineHeight()); + newLayoutData.setBottomSpacing(layoutData.getCurrentLine().getBottomSpacing()); LayoutData.MarkDownLine firstLine = newLayoutData.getCurrentLine(); + super.generateLayout(newLayoutData); - layoutData.updateLineHeight(firstLine.getHeight()); - layoutData.addX(firstLine.getWidth()); + + newLayoutData.setBottomSpacing(layoutData.getCurrentLine().getBottomSpacing()); + layoutData.updateTopSpacing(firstLine.getTopSpacing()); + layoutData.updateLineHeight(firstLine.getRawHeight()); + layoutData.updateBottomSpacing(firstLine.getBottomSpacing()); layoutData.nextLine(); + if (newLayoutData.getCurrentLine() != firstLine) { - layoutData.setLineHeight(newLayoutData.getY() + newLayoutData.getLineHeight() - firstLine.getHeight()); + layoutData.setLineHeight(newLayoutData.getCurrentLine().getBottomY() - firstLine.getHeight()); layoutData.nextLine(); } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/list/ListHolderElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/list/ListHolderElement.java index c9d7f8a..90c80ff 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/list/ListHolderElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/list/ListHolderElement.java @@ -4,7 +4,6 @@ import dev.dediamondpro.minemark.LayoutData; import dev.dediamondpro.minemark.elements.ChildBasedElement; import dev.dediamondpro.minemark.elements.Element; -import dev.dediamondpro.minemark.elements.NoPadding; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.xml.sax.Attributes; @@ -29,10 +28,6 @@ protected float getPadding(LayoutData layoutData) { return layoutConfig.getSpacingConfig().getListPadding(); } - public int getElementPosition(Element element) { - return children.indexOf(element); - } - public ListType getListType() { return listType; } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/text/TextElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/text/TextElement.java index b3af357..9f56fb7 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/text/TextElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/text/TextElement.java @@ -32,10 +32,8 @@ public void generateLayout(LayoutData layoutData) { } for (int i = 0; i < allLines.size(); i++) { String line = allLines.get(i); - lines.put(layoutData.addElement( - layoutConfig.getAlignment(), getTextWidth(line), - getTextHeight(line) + layoutConfig.getSpacingConfig().getTextSpacing() * layoutConfig.getFontSize()), - line); + layoutData.updatePadding(layoutConfig.getSpacingConfig().getTextPadding() * layoutConfig.getFontSize()); + lines.put(layoutData.addElement(layoutConfig.getAlignment(), getTextWidth(line), getTextHeight(line)), line); if (i != allLines.size() - 1) { layoutData.nextLine(); } diff --git a/src/test/java/BasicTest.java b/src/test/java/BasicTest.java index e829c2d..82ae529 100644 --- a/src/test/java/BasicTest.java +++ b/src/test/java/BasicTest.java @@ -18,11 +18,11 @@ public class BasicTest { .addElement(Elements.TEXT, DummyTextElement::new) .build(); - private final LayoutConfig config = new LayoutConfig(5, new LayoutConfig.SpacingConfig(1f, 2f, 2f, 5f), new LayoutConfig.HeadingConfig(6, 5, 4, 3, 2, 1)); + private final LayoutConfig config = new LayoutConfig(5, new LayoutConfig.SpacingConfig(1f, 2f, 5f), new LayoutConfig.HeadingConfig(6, 5, 4, 3, 2, 1)); @Test public void test() throws IOException, SAXException { - MineMarkElement element = core.parse(config, "```\ntest\n```\nHello
World"); + MineMarkElement element = core.parse(config, "> Test"); //element.beforeDraw(0f, 0f, 25f, 0f, 0f, new Object()); System.out.println(element.getTree()); } diff --git a/src/test/resources/test.md b/src/test/resources/test.md index 85e38f0..1c684df 100644 --- a/src/test/resources/test.md +++ b/src/test/resources/test.md @@ -2,7 +2,7 @@ Oh, so **test**
test that's an issue? -
+
> hello > @@ -15,4 +15,5 @@ that's an issue?
-taco \ No newline at end of file +hello +
hello

hello

\ No newline at end of file