From 90d286005527d71cb7ddbd2362214cd068b23430 Mon Sep 17 00:00:00 2001 From: DeDiamondPro <67508414+DeDiamondPro@users.noreply.github.com> Date: Sun, 30 Jun 2024 20:17:19 +0200 Subject: [PATCH] seperate normal and formatting elements, remove SingleTagMultiElement --- build.gradle.kts | 2 +- .../elements/MarkdownHeadingComponent.kt | 2 +- minecraft/gradle.properties | 2 +- .../elements/MarkdownCodeBlockElement.java | 1 - .../elements/MarkdownHeadingElement.java | 2 +- .../platform/MarkdownDynamicImage.java | 1 - .../utils/MinecraftImageProvider.java | 14 ++-- .../dediamondpro/minemark/MineMarkCore.java | 28 +++---- .../minemark/MineMarkCoreBuilder.java | 73 +++++++++++++++---- .../minemark/MineMarkHtmlParser.java | 52 +++++++------ .../minemark/elements/BasicElement.java | 8 +- .../minemark/elements/ChildBasedElement.java | 11 +-- .../minemark/elements/ChildMovingElement.java | 3 +- .../minemark/elements/Element.java | 25 ++++++- .../minemark/elements/Elements.java | 2 +- .../minemark/elements/EmptyElement.java | 4 +- .../minemark/elements/MineMarkElement.java | 2 +- .../elements/SingleTagMultiElement.java | 68 ----------------- .../formatting/FormattingElement.java | 68 +++++++++++++++++ .../formatting/TagBasedFormattingElement.java | 52 +++++++++++++ .../formatting/impl/AlignmentElement.java | 57 +++++++++++++++ .../impl}/CssStyleElement.java | 65 ++++++++--------- .../impl/TextFormattingElement.java} | 32 ++++---- .../elements/impl/CodeBlockElement.java | 8 +- .../impl/{formatting => }/HeadingElement.java | 2 +- .../impl/formatting/AlignmentElement.java | 67 ----------------- .../elements/impl/table/TableRowElement.java | 6 +- 27 files changed, 374 insertions(+), 283 deletions(-) delete mode 100644 src/main/java/dev/dediamondpro/minemark/elements/SingleTagMultiElement.java create mode 100644 src/main/java/dev/dediamondpro/minemark/elements/formatting/FormattingElement.java create mode 100644 src/main/java/dev/dediamondpro/minemark/elements/formatting/TagBasedFormattingElement.java create mode 100644 src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/AlignmentElement.java rename src/main/java/dev/dediamondpro/minemark/elements/{impl/formatting => formatting/impl}/CssStyleElement.java (58%) rename src/main/java/dev/dediamondpro/minemark/elements/{impl/formatting/FormattingElement.java => formatting/impl/TextFormattingElement.java} (59%) rename src/main/java/dev/dediamondpro/minemark/elements/impl/{formatting => }/HeadingElement.java (98%) delete mode 100644 src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/AlignmentElement.java diff --git a/build.gradle.kts b/build.gradle.kts index 50b6165..2c5d7d7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,7 @@ plugins { } group = "dev.dediamondpro" -version = "1.1.0" +version = "1.2.0" repositories { mavenCentral() diff --git a/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/elements/MarkdownHeadingComponent.kt b/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/elements/MarkdownHeadingComponent.kt index 5f35050..118f41f 100644 --- a/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/elements/MarkdownHeadingComponent.kt +++ b/elementa/src/main/kotlin/dev/dediamondpro/minemark/elementa/elements/MarkdownHeadingComponent.kt @@ -20,7 +20,7 @@ package dev.dediamondpro.minemark.elementa.elements import dev.dediamondpro.minemark.LayoutStyle import dev.dediamondpro.minemark.elementa.style.MarkdownStyle import dev.dediamondpro.minemark.elements.Element -import dev.dediamondpro.minemark.elements.impl.formatting.HeadingElement +import dev.dediamondpro.minemark.elements.impl.HeadingElement import gg.essential.elementa.components.UIBlock import gg.essential.universal.UMatrixStack import org.xml.sax.Attributes diff --git a/minecraft/gradle.properties b/minecraft/gradle.properties index 0baec6f..a53d054 100644 --- a/minecraft/gradle.properties +++ b/minecraft/gradle.properties @@ -1,6 +1,6 @@ # Mod Configuration mod_name=MineMark mod_id=minemark -mod_version=1.1.0 +mod_version=1.2.0 mod_description=Markdown rendering library mod_license=LGPL \ No newline at end of file diff --git a/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/elements/MarkdownCodeBlockElement.java b/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/elements/MarkdownCodeBlockElement.java index 1bd9f6c..c255e72 100644 --- a/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/elements/MarkdownCodeBlockElement.java +++ b/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/elements/MarkdownCodeBlockElement.java @@ -20,7 +20,6 @@ import dev.dediamondpro.minemark.LayoutStyle; import dev.dediamondpro.minemark.elements.Element; import dev.dediamondpro.minemark.elements.impl.CodeBlockElement; -import dev.dediamondpro.minemark.elements.impl.formatting.HeadingElement; import dev.dediamondpro.minemark.minecraft.platform.MarkdownRenderer; import dev.dediamondpro.minemark.minecraft.style.MarkdownStyle; import org.jetbrains.annotations.NotNull; diff --git a/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/elements/MarkdownHeadingElement.java b/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/elements/MarkdownHeadingElement.java index 0b1db57..f35702b 100644 --- a/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/elements/MarkdownHeadingElement.java +++ b/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/elements/MarkdownHeadingElement.java @@ -19,7 +19,7 @@ import dev.dediamondpro.minemark.LayoutStyle; import dev.dediamondpro.minemark.elements.Element; -import dev.dediamondpro.minemark.elements.impl.formatting.HeadingElement; +import dev.dediamondpro.minemark.elements.impl.HeadingElement; import dev.dediamondpro.minemark.minecraft.platform.MarkdownRenderer; import dev.dediamondpro.minemark.minecraft.style.MarkdownStyle; import org.jetbrains.annotations.NotNull; diff --git a/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/platform/MarkdownDynamicImage.java b/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/platform/MarkdownDynamicImage.java index 2fbdba0..332ed38 100644 --- a/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/platform/MarkdownDynamicImage.java +++ b/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/platform/MarkdownDynamicImage.java @@ -44,7 +44,6 @@ public void close() { public static MarkdownDynamicImage of(NativeImage image) throws IOException { NativeImageBackedTexture texture = new NativeImageBackedTexture(image); Identifier identifier = MinecraftClient.getInstance().getTextureManager().registerDynamicTexture("minemark", texture); - System.out.println("Created dynamic image " + identifier); return new MarkdownDynamicImage(identifier); } } diff --git a/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/utils/MinecraftImageProvider.java b/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/utils/MinecraftImageProvider.java index 0d0f419..0809931 100644 --- a/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/utils/MinecraftImageProvider.java +++ b/minecraft/src/main/java/dev/dediamondpro/minemark/minecraft/utils/MinecraftImageProvider.java @@ -24,6 +24,8 @@ import javax.imageio.ImageIO; import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -43,14 +45,10 @@ public void getImage(String src, Consumer dimensionCallback, Consumer BufferedImage bufferedImage = ImageIO.read(getInputStream(src)); dimensionCallback.accept(new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight())); - NativeImage image = new NativeImage(bufferedImage.getWidth(), bufferedImage.getHeight(), true); - for (int y = 0; y < bufferedImage.getHeight(); y++) { - for (int x = 0; x < bufferedImage.getWidth(); x++) { - image.setColor(x, y, bufferedImage.getRGB(x, y)); - } - } - - imageCallback.accept(MarkdownDynamicImage.of(image)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ImageIO.write(bufferedImage, "png", out); + NativeImage nativeImage = NativeImage.read(new ByteArrayInputStream(out.toByteArray())); + imageCallback.accept(MarkdownDynamicImage.of(nativeImage)); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/dev/dediamondpro/minemark/MineMarkCore.java b/src/main/java/dev/dediamondpro/minemark/MineMarkCore.java index 4bb5060..c565512 100644 --- a/src/main/java/dev/dediamondpro/minemark/MineMarkCore.java +++ b/src/main/java/dev/dediamondpro/minemark/MineMarkCore.java @@ -20,6 +20,7 @@ import dev.dediamondpro.minemark.elements.MineMarkElement; import dev.dediamondpro.minemark.elements.creators.ElementCreator; import dev.dediamondpro.minemark.elements.creators.TextElementCreator; +import dev.dediamondpro.minemark.elements.formatting.FormattingElement; import dev.dediamondpro.minemark.style.Style; import org.commonmark.Extension; import org.commonmark.node.Node; @@ -51,19 +52,20 @@ public class MineMarkCore { private final ReentrantLock parsingLock = new ReentrantLock(); /** - * @param textElement The text element for this core - * @param elements Elements supported to create a layout and render - * @param extensions Markdown extensions that should be used when parsing - * @param urlSanitizer An optional urlSanitizer + * @param textElement The text element for this core + * @param elements Elements supported to create a layout and render + * @param formattingElements Elements that apply a formatting style + * @param extensions Markdown extensions that should be used when parsing + * @param urlSanitizer An optional urlSanitizer */ - protected MineMarkCore(TextElementCreator textElement, List> elements, Iterable extensions, @Nullable UrlSanitizer urlSanitizer) { + protected MineMarkCore(TextElementCreator textElement, List> elements, List> formattingElements, Iterable extensions, @Nullable UrlSanitizer urlSanitizer) { this.markdownParser = Parser.builder().extensions(extensions).build(); HtmlRenderer.Builder htmlRendererBuilder = HtmlRenderer.builder().extensions(extensions); if (urlSanitizer != null) { htmlRendererBuilder.urlSanitizer(urlSanitizer).sanitizeUrls(true); } this.htmlRenderer = htmlRendererBuilder.build(); - this.htmlParser = new MineMarkHtmlParser<>(textElement, elements); + this.htmlParser = new MineMarkHtmlParser<>(textElement, elements, formattingElements); xmlParser = new org.ccil.cowan.tagsoup.Parser(); xmlParser.setContentHandler(htmlParser); } @@ -71,14 +73,14 @@ protected MineMarkCore(TextElementCreator textElement, List parse(@NotNull S style, @NotNull String markdown, Charset charSet) throws SAXException, IOException { + public MineMarkElement parse(@NotNull S style, @NotNull String markdown, @NotNull Charset charSet) throws SAXException, IOException { Node document = markdownParser.parse(markdown); return parseDocument(style, document, charSet); } @@ -86,7 +88,7 @@ public MineMarkElement parse(@NotNull S style, @NotNull String markdown, C /** * Parse markdown to an element used to render it * - * @param markdown The markdown text to parse + * @param markdown The Markdown text to parse * @param style The style passed to all elements * @return The parsed markdown element * @throws SAXException An exception during SAX parsing @@ -99,14 +101,14 @@ public MineMarkElement parse(@NotNull S style, @NotNull String markdown) t /** * Parse markdown to an element used to render it * - * @param markdown The markdown text to parse + * @param markdown The Markdown text to parse * @param style The style passed to all elements * @param charSet The charset to use when parsing the markdown * @return The parsed markdown element * @throws SAXException An exception during SAX parsing * @throws IOException An IOException during parsing */ - public MineMarkElement parse(@NotNull S style, @NotNull Reader markdown, Charset charSet) throws SAXException, IOException { + public MineMarkElement parse(@NotNull S style, @NotNull Reader markdown, @NotNull Charset charSet) throws SAXException, IOException { Node document = markdownParser.parseReader(markdown); return parseDocument(style, document, charSet); } @@ -114,7 +116,7 @@ public MineMarkElement parse(@NotNull S style, @NotNull Reader markdown, C /** * Parse markdown to an element used to render it * - * @param markdown The markdown text to parse + * @param markdown The Markdown text to parse * @param style The style passed to all elements * @return The parsed markdown element * @throws SAXException An exception during SAX parsing @@ -124,7 +126,7 @@ public MineMarkElement parse(@NotNull S style, @NotNull Reader markdown) t return parse(style, markdown, StandardCharsets.UTF_8); } - private MineMarkElement parseDocument(@NotNull S style, Node document, Charset charSet) throws SAXException, IOException { + private MineMarkElement parseDocument(@NotNull S style, Node document, @NotNull Charset charSet) throws SAXException, IOException { String html = "\n" + htmlRenderer.render(document) + ""; // Acquire the lock to make sure this thread is the only one using the parser parsingLock.lock(); diff --git a/src/main/java/dev/dediamondpro/minemark/MineMarkCoreBuilder.java b/src/main/java/dev/dediamondpro/minemark/MineMarkCoreBuilder.java index e09327a..8c528d4 100644 --- a/src/main/java/dev/dediamondpro/minemark/MineMarkCoreBuilder.java +++ b/src/main/java/dev/dediamondpro/minemark/MineMarkCoreBuilder.java @@ -18,11 +18,12 @@ package dev.dediamondpro.minemark; import dev.dediamondpro.minemark.elements.Elements; +import dev.dediamondpro.minemark.elements.formatting.FormattingElement; import dev.dediamondpro.minemark.elements.impl.LinkElement; import dev.dediamondpro.minemark.elements.impl.ParagraphElement; -import dev.dediamondpro.minemark.elements.impl.formatting.AlignmentElement; -import dev.dediamondpro.minemark.elements.impl.formatting.CssStyleElement; -import dev.dediamondpro.minemark.elements.impl.formatting.FormattingElement; +import dev.dediamondpro.minemark.elements.formatting.impl.AlignmentElement; +import dev.dediamondpro.minemark.elements.formatting.impl.CssStyleElement; +import dev.dediamondpro.minemark.elements.formatting.impl.TextFormattingElement; import dev.dediamondpro.minemark.elements.impl.list.ListHolderElement; import dev.dediamondpro.minemark.elements.impl.table.TableHolderElement; import dev.dediamondpro.minemark.elements.impl.table.TableRowElement; @@ -40,8 +41,10 @@ public class MineMarkCoreBuilder { protected MineMarkCoreBuilder() { } + private final ArrayList> formattingElements = new ArrayList<>(); private final ArrayList> elements = new ArrayList<>(); private final ArrayList extensions = new ArrayList<>(); + private boolean withDefaultFormattingElements = true; private TextElementCreator textElement = null; private boolean withDefaultElements = true; private UrlSanitizer urlSanitizer = null; @@ -143,7 +146,7 @@ public MineMarkCoreBuilder addElement(int position, @NotNull Elements elem /** * Add supported elements to be used * - * @param elements A Map with all elements that should be added + * @param elements A List with all elements that should be added */ public MineMarkCoreBuilder addElements(@NotNull List> elements) { for (ElementCreator element : elements) { @@ -152,6 +155,39 @@ public MineMarkCoreBuilder addElements(@NotNull List> return this; } + /** + * Add a formatting element to be used + * + * @param element The formatting element + */ + public MineMarkCoreBuilder addFormatingElement(@NotNull FormattingElement element) { + this.formattingElements.add(element); + return this; + } + + /** + * Add a formatting element to be used + * + * @param position The position the element should be added at + * @param element The formatting element + */ + public MineMarkCoreBuilder addFormatingElement(int position, @NotNull FormattingElement element) { + this.formattingElements.add(position, element); + return this; + } + + /** + * Add formatting elements to be used + * + * @param elements A List of formatting elements that should be added + */ + public MineMarkCoreBuilder addFormatingElements(@NotNull List> elements) { + for (FormattingElement element : elements) { + addFormatingElement(element); + } + return this; + } + /** * Add a commonmark extension to the Markdown parser * @@ -170,6 +206,14 @@ public MineMarkCoreBuilder withoutDefaultElements() { return this; } + /** + * Disable default formatting elements + */ + public MineMarkCoreBuilder withoutDefaultFormattingElements() { + withDefaultFormattingElements = false; + return this; + } + /** * Make the core use an url sanitizer and enable url sanitization * @@ -188,16 +232,17 @@ public MineMarkCore build() { throw new IllegalArgumentException("A text element has to be provided by using \"setTextElement(textElement\""); } if (withDefaultElements) { - // Add default (formatting) elements, these are added first so they take priority and their formatting applies properly - addElement(0, Elements.PARAGRAPH, ParagraphElement::new); - addElement(0, Elements.FORMATTING, FormattingElement::new); - addElement(0, Elements.LINK, LinkElement::new); - addElement(0, Elements.LIST_PARENT, ListHolderElement::new); - addElement(0, Elements.TABLE, TableHolderElement::new); - addElement(0, Elements.TABLE_ROW, TableRowElement::new); - addElement(0, new AlignmentElement.AlignmentElementCreator<>()); - addElement(0, new CssStyleElement.CssStyleElementCreator<>()); + addElement(Elements.PARAGRAPH, ParagraphElement::new); + addElement(Elements.LINK, LinkElement::new); + addElement(Elements.LIST_PARENT, ListHolderElement::new); + addElement(Elements.TABLE, TableHolderElement::new); + addElement(Elements.TABLE_ROW, TableRowElement::new); + } + if (withDefaultFormattingElements) { + addFormatingElement(new AlignmentElement<>()); + addFormatingElement(new CssStyleElement<>()); + addFormatingElement(new TextFormattingElement<>()); } - return new MineMarkCore<>(textElement, elements, extensions, urlSanitizer); + return new MineMarkCore<>(textElement, elements, formattingElements, extensions, urlSanitizer); } } diff --git a/src/main/java/dev/dediamondpro/minemark/MineMarkHtmlParser.java b/src/main/java/dev/dediamondpro/minemark/MineMarkHtmlParser.java index ef64c18..4069397 100644 --- a/src/main/java/dev/dediamondpro/minemark/MineMarkHtmlParser.java +++ b/src/main/java/dev/dediamondpro/minemark/MineMarkHtmlParser.java @@ -20,9 +20,9 @@ import dev.dediamondpro.minemark.elements.Element; import dev.dediamondpro.minemark.elements.EmptyElement; import dev.dediamondpro.minemark.elements.MineMarkElement; -import dev.dediamondpro.minemark.elements.SingleTagMultiElement; import dev.dediamondpro.minemark.elements.creators.ElementCreator; import dev.dediamondpro.minemark.elements.creators.TextElementCreator; +import dev.dediamondpro.minemark.elements.formatting.FormattingElement; import dev.dediamondpro.minemark.style.Style; import org.jetbrains.annotations.NotNull; import org.xml.sax.Attributes; @@ -32,6 +32,7 @@ public class MineMarkHtmlParser extends DefaultHandler { private final List> elements; + private final List> formattingElements; private final TextElementCreator textElementCreator; private MineMarkElement markDown; private Element currentElement; @@ -40,9 +41,10 @@ public class MineMarkHtmlParser extends DefaultHandler { private StringBuilder textBuilder = new StringBuilder(); private boolean isPreFormatted = false; - protected MineMarkHtmlParser(TextElementCreator textElementCreator, List> elements) { + protected MineMarkHtmlParser(TextElementCreator textElementCreator, List> elements, List> formattingElements) { this.textElementCreator = textElementCreator; this.elements = elements; + this.formattingElements = formattingElements; } @Override @@ -59,8 +61,29 @@ public void startElement(String uri, String localName, String qName, Attributes break; } addText(); - Element newElement = createElement(style, currentElement.getLayoutStyle(), currentElement, qName, attributes); - currentElement = newElement != null ? newElement : new EmptyElement<>(style, currentElement.getLayoutStyle(), currentElement, qName, attributes); + + LayoutStyle originalLayoutStyle = currentElement.getLayoutStyle(); + LayoutStyle layoutStyle = originalLayoutStyle; + boolean canBeInline = true; + for (FormattingElement element : formattingElements) { + if (!element.appliesTo(style, layoutStyle, currentElement, qName, attributes)) { + continue; + } + // If a formatting element applies, clone the layout style. This should only be done once + if (layoutStyle == originalLayoutStyle) { + layoutStyle = layoutStyle.clone(); + } + + element.applyStyle(style, layoutStyle, currentElement, qName, attributes); + + canBeInline = canBeInline && element.canBeInline(style, layoutStyle, currentElement, qName, attributes); + } + + Element newElement = createElement(style, layoutStyle, currentElement, qName, attributes); + currentElement = newElement != null ? newElement : new EmptyElement<>(style, layoutStyle, currentElement, qName, attributes); + if (!canBeInline) { + currentElement.setInline(false); + } } @Override @@ -121,31 +144,16 @@ private void addText() { * @param parent The parent element, null if top level element * @param qName The name of the HTML tag * @param attributes The attributes of the HTML tag, null for text - * @return If only one element applies to the given parameters, return that element, - * otherwise return a TagMultiElement with all elements that apply. If no element applies, return null. + * @return The first element that applies to the parameters, if none apply returns null */ private Element createElement(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { - ElementCreator elementCreator = null; - SingleTagMultiElement multipleElement = null; - for (ElementCreator element : elements) { if (!element.appliesTo(style, layoutStyle, parent, qName, attributes)) { continue; } - - if (elementCreator == null) { - elementCreator = element; - continue; - } - - if (multipleElement == null) { - multipleElement = new SingleTagMultiElement<>(style, layoutStyle, parent, qName, attributes); - multipleElement.addElement(elementCreator); - } - multipleElement.addElement(element); - + return element.createElement(style, layoutStyle, parent, qName, attributes); } - return multipleElement != null ? multipleElement : elementCreator != null ? elementCreator.createElement(style, layoutStyle, parent, qName, attributes) : null; + return null; } protected void setStyle(S style, LayoutStyle layoutStyle) { diff --git a/src/main/java/dev/dediamondpro/minemark/elements/BasicElement.java b/src/main/java/dev/dediamondpro/minemark/elements/BasicElement.java index 7a5330c..af880fe 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/BasicElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/BasicElement.java @@ -20,7 +20,6 @@ import dev.dediamondpro.minemark.LayoutData; import dev.dediamondpro.minemark.LayoutStyle; import dev.dediamondpro.minemark.style.Style; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.xml.sax.Attributes; @@ -41,20 +40,15 @@ public void drawInternal(float xOffset, float yOffset, float mouseX, float mouse } @Override - @ApiStatus.Internal public void generateLayout(LayoutData layoutData, R renderData) { float width = getWidth(layoutData, renderData); float height = getHeight(layoutData, renderData); float padding = getPadding(layoutData, renderData); - boolean inline = this instanceof Inline && (((Inline) this).isInline()); - if ((!inline && layoutData.isLineOccupied()) || layoutData.getX() + width > layoutData.getMaxWidth()) { + if (layoutData.getX() + width > layoutData.getMaxWidth()) { layoutData.nextLine(); } layoutData.updatePadding(padding); position = layoutData.addElement(layoutStyle.getAlignment(), width, height); - if (!inline && layoutData.isLineOccupied()) { - layoutData.nextLine(); - } } protected abstract void drawElement(float x, float y, float width, float height, R renderData); diff --git a/src/main/java/dev/dediamondpro/minemark/elements/ChildBasedElement.java b/src/main/java/dev/dediamondpro/minemark/elements/ChildBasedElement.java index 6b23db2..fc3f6d2 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/ChildBasedElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/ChildBasedElement.java @@ -20,7 +20,6 @@ import dev.dediamondpro.minemark.LayoutData; import dev.dediamondpro.minemark.LayoutStyle; import dev.dediamondpro.minemark.style.Style; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.xml.sax.Attributes; @@ -31,21 +30,13 @@ public ChildBasedElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nu } @Override - @ApiStatus.Internal public void generateLayout(LayoutData layoutData, R renderData) { - boolean inline = this instanceof Inline && (((Inline) this).isInline()); - if (!inline && layoutData.isLineOccupied()) { - layoutData.nextLine(); - } float padding = getPadding(layoutData, renderData); layoutData.updateTopSpacing(padding); for (Element child : children) { - child.generateLayout(layoutData, renderData); + child.generateLayoutInternal(layoutData, renderData); } layoutData.updateBottomSpacing(padding); - if (!inline) { - layoutData.nextLine(); - } } protected float getPadding(LayoutData layoutData, R renderData) { diff --git a/src/main/java/dev/dediamondpro/minemark/elements/ChildMovingElement.java b/src/main/java/dev/dediamondpro/minemark/elements/ChildMovingElement.java index 4e490d4..35cb898 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/ChildMovingElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/ChildMovingElement.java @@ -41,7 +41,6 @@ public ChildMovingElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @N } @Override - @ApiStatus.Internal public void generateLayout(LayoutData layoutData, R renderData) { if (layoutData.isLineOccupied()) { layoutData.nextLine(); @@ -91,7 +90,7 @@ public void generateLayout(LayoutData layoutData, R renderData) { protected void generateNewLayout(LayoutData layoutData, R renderData) { for (Element child : children) { - child.generateLayout(layoutData, renderData); + child.generateLayoutInternal(layoutData, renderData); } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/Element.java b/src/main/java/dev/dediamondpro/minemark/elements/Element.java index 7536ac0..a4e87e4 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/Element.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/Element.java @@ -31,6 +31,9 @@ import java.io.Closeable; import java.util.ArrayList; +/** + * Base class for an element that should render content, only one can apply per HTML tag. + */ public abstract class Element implements Closeable { protected final @Nullable Element parent; protected final ArrayList> children = new ArrayList<>(); @@ -38,6 +41,7 @@ public abstract class Element implements Closeable { protected final Attributes attributes; protected final S style; protected LayoutStyle layoutStyle; + protected boolean isInline = (this instanceof Inline) && ((Inline) this).isInline(); /** * Base Element Constructor used by {@link ElementCreator} @@ -87,10 +91,23 @@ public void onMouseClickedInternal(MouseButton button, float mouseX, float mouse } /** - * Internal method for generating the layout of this element, should never be used directly. + * Internal method for doing layout generation and handling if this element is inline or not. */ @ApiStatus.Internal - public abstract void generateLayout(LayoutData layoutData, R renderData); + public void generateLayoutInternal(LayoutData layoutData, R renderData) { + if (!isInline && layoutData.isLineOccupied()) { + layoutData.nextLine(); + } + generateLayout(layoutData, renderData); + if (!isInline && layoutData.isLineOccupied()) { + layoutData.nextLine(); + } + } + + /** + * Method for generating the layout of this element, should never be used directly. + */ + protected abstract void generateLayout(LayoutData layoutData, R renderData); /** * Call this method to regenerate the layout of all associated elements @@ -138,4 +155,8 @@ public String buildTree(int depth) { public LayoutStyle getLayoutStyle() { return layoutStyle; } + + public void setInline(boolean inline) { + this.isInline = inline; + } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/Elements.java b/src/main/java/dev/dediamondpro/minemark/elements/Elements.java index 352dfb0..00ba7a4 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/Elements.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/Elements.java @@ -22,7 +22,7 @@ public enum Elements { PARAGRAPH(listOf("p")), - FORMATTING(listOf("strong", "b", "em", "i", "ins", "u", "del", "s", "pre")), + TEXT_FORMATTING(listOf("strong", "b", "em", "i", "ins", "u", "del", "s", "pre")), HEADING(listOf("h1", "h2", "h3", "h4", "h5", "h6")), LINK(listOf("a")), IMAGE(listOf("img")), diff --git a/src/main/java/dev/dediamondpro/minemark/elements/EmptyElement.java b/src/main/java/dev/dediamondpro/minemark/elements/EmptyElement.java index 4323e70..0147e0b 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/EmptyElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/EmptyElement.java @@ -27,7 +27,7 @@ /** * An element that is used when no element is found for an HTML tag */ -public class EmptyElement extends Element { +public class EmptyElement extends Element implements Inline { public EmptyElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @Nullable Attributes attributes) { super(style, layoutStyle, parent, qName, attributes); } @@ -35,7 +35,7 @@ public EmptyElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullabl @Override public void generateLayout(LayoutData layoutData, R renderData) { for (Element child : children) { - child.generateLayout(layoutData, renderData); + child.generateLayoutInternal(layoutData, renderData); } } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/MineMarkElement.java b/src/main/java/dev/dediamondpro/minemark/elements/MineMarkElement.java index 6f3293e..0346780 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/MineMarkElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/MineMarkElement.java @@ -74,7 +74,7 @@ public void beforeDraw(float x, float y, float width, float mouseX, float mouseY throw new IllegalArgumentException("Width cannot be zero or negative!"); } if (width != lastWidth) { - generateLayout(new LayoutData(width), renderData); + generateLayoutInternal(new LayoutData(width), renderData); lastWidth = width; } this.beforeDrawInternal(x, y, mouseX - x, mouseY - y, renderData); diff --git a/src/main/java/dev/dediamondpro/minemark/elements/SingleTagMultiElement.java b/src/main/java/dev/dediamondpro/minemark/elements/SingleTagMultiElement.java deleted file mode 100644 index 2893bfc..0000000 --- a/src/main/java/dev/dediamondpro/minemark/elements/SingleTagMultiElement.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of MineMark - * Copyright (C) 2024 DeDiamondPro - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License Version 3 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package dev.dediamondpro.minemark.elements; - - -import dev.dediamondpro.minemark.LayoutData; -import dev.dediamondpro.minemark.LayoutStyle; -import dev.dediamondpro.minemark.elements.creators.ElementCreator; -import dev.dediamondpro.minemark.style.Style; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.xml.sax.Attributes; - -import java.util.ArrayList; - -/** - * An element that is used to apply multiple elements to the same HTML tag. - */ -public class SingleTagMultiElement extends Element { - private Element deepestChildElement = this; - - public SingleTagMultiElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @Nullable Attributes attributes) { - super(style, layoutStyle, parent, qName, attributes); - } - - @Override - public void generateLayout(LayoutData layoutData, R renderData) { - for (Element child : children) { - child.generateLayout(layoutData, renderData); - } - } - - @Override - public @NotNull ArrayList> getChildren() { - // We return the children of the deepest child so all new elements are added to the deepest child, - if (deepestChildElement == this) return children; - return deepestChildElement.getChildren(); - } - - @Override - public LayoutStyle getLayoutStyle() { - if (deepestChildElement == this) return layoutStyle; - return deepestChildElement.getLayoutStyle(); - } - - public void addElement(@NotNull ElementCreator elementCreator) { - assert parent != null; - Element newElement = elementCreator.createElement(style, getLayoutStyle(), parent, qName, attributes); - parent.getChildren().remove(newElement); - deepestChildElement.getChildren().add(newElement); - deepestChildElement = newElement; - } -} diff --git a/src/main/java/dev/dediamondpro/minemark/elements/formatting/FormattingElement.java b/src/main/java/dev/dediamondpro/minemark/elements/formatting/FormattingElement.java new file mode 100644 index 0000000..3c2dd88 --- /dev/null +++ b/src/main/java/dev/dediamondpro/minemark/elements/formatting/FormattingElement.java @@ -0,0 +1,68 @@ +/* + * This file is part of MineMark + * Copyright (C) 2024 DeDiamondPro + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License Version 3 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package dev.dediamondpro.minemark.elements.formatting; + +import dev.dediamondpro.minemark.LayoutStyle; +import dev.dediamondpro.minemark.elements.Element; +import dev.dediamondpro.minemark.style.Style; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.xml.sax.Attributes; + +/** + * An element that applies a specific format, multiple formatting elements can be applied to a single HTML tag + */ +public interface FormattingElement { + + /** + * Apply the style of this formatting element to the current layoutStyle. + * + * @param style The style of the element + * @param layoutStyle The layout style of the element + * @param parent The parent element + * @param qName The name of the HTML tag + * @param attributes The attributes of the HTML tag + */ + void applyStyle(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @NotNull Attributes attributes); + + /** + * Check if the element applies to the given parameters and can be created with them + * + * @param style The style of the element + * @param layoutStyle The layout style of the element + * @param parent The parent element + * @param qName The name of the HTML tag + * @param attributes The attributes of the HTML tag + * @return True if the element applies to the given parameters + */ + boolean appliesTo(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes); + + /** + * Check if the element can be inline, if not the element associated with the HTML tag can never be inline + * + * @param style The style of the element + * @param layoutStyle The layout style of the element + * @param parent The parent element + * @param qName The name of the HTML tag + * @param attributes The attributes of the HTML tag + * @return True if the element applies to the given parameters + */ + default boolean canBeInline(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { + return true; + } +} diff --git a/src/main/java/dev/dediamondpro/minemark/elements/formatting/TagBasedFormattingElement.java b/src/main/java/dev/dediamondpro/minemark/elements/formatting/TagBasedFormattingElement.java new file mode 100644 index 0000000..87235ec --- /dev/null +++ b/src/main/java/dev/dediamondpro/minemark/elements/formatting/TagBasedFormattingElement.java @@ -0,0 +1,52 @@ +/* + * This file is part of MineMark + * Copyright (C) 2024 DeDiamondPro + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License Version 3 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package dev.dediamondpro.minemark.elements.formatting; + +import dev.dediamondpro.minemark.LayoutStyle; +import dev.dediamondpro.minemark.elements.Element; +import dev.dediamondpro.minemark.elements.Elements; +import dev.dediamondpro.minemark.style.Style; +import org.jetbrains.annotations.NotNull; +import org.xml.sax.Attributes; + +import java.util.Collections; +import java.util.List; + +/** + * Utility class for formatting elements that apply based on solely the HTML tag + */ +public abstract class TagBasedFormattingElement implements FormattingElement { + protected final List tags; + + public TagBasedFormattingElement(List tags) { + this.tags = tags; + } + + public TagBasedFormattingElement(Elements tag) { + this(tag.tags); + } + + public TagBasedFormattingElement(String tag) { + this(Collections.singletonList(tag)); + } + + @Override + public boolean appliesTo(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { + return tags.contains(qName); + } +} diff --git a/src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/AlignmentElement.java b/src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/AlignmentElement.java new file mode 100644 index 0000000..69fff65 --- /dev/null +++ b/src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/AlignmentElement.java @@ -0,0 +1,57 @@ +/* + * This file is part of MineMark + * Copyright (C) 2024 DeDiamondPro + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License Version 3 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package dev.dediamondpro.minemark.elements.formatting.impl; + +import dev.dediamondpro.minemark.LayoutStyle; +import dev.dediamondpro.minemark.elements.Element; +import dev.dediamondpro.minemark.elements.formatting.FormattingElement; +import dev.dediamondpro.minemark.style.Style; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.xml.sax.Attributes; + +public class AlignmentElement implements FormattingElement { + protected String alignment; + + @Override + public void applyStyle(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @NotNull Attributes attributes) { + alignment = qName.equals("div") ? attributes.getValue("align") : qName; + if (alignment == null) return; + switch (alignment) { + case "left": + layoutStyle.setAlignment(LayoutStyle.Alignment.LEFT); + break; + case "center": + layoutStyle.setAlignment(LayoutStyle.Alignment.CENTER); + break; + case "right": + layoutStyle.setAlignment(LayoutStyle.Alignment.RIGHT); + break; + } + } + + @Override + public boolean canBeInline(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { + return false; + } + + @Override + public boolean appliesTo(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { + return qName.equals("center") || (qName.equals("div") && attributes.getValue("align") != null); + } +} diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/CssStyleElement.java b/src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/CssStyleElement.java similarity index 58% rename from src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/CssStyleElement.java rename to src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/CssStyleElement.java index c47a131..be13e98 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/CssStyleElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/CssStyleElement.java @@ -15,28 +15,32 @@ * along with this program. If not, see . */ -package dev.dediamondpro.minemark.elements.impl.formatting; +package dev.dediamondpro.minemark.elements.formatting.impl; import dev.dediamondpro.minemark.LayoutStyle; -import dev.dediamondpro.minemark.elements.ChildBasedElement; import dev.dediamondpro.minemark.elements.Element; -import dev.dediamondpro.minemark.elements.Inline; -import dev.dediamondpro.minemark.elements.creators.ElementCreator; +import dev.dediamondpro.minemark.elements.formatting.FormattingElement; import dev.dediamondpro.minemark.style.Style; import dev.dediamondpro.minemark.utils.ColorFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.xml.sax.Attributes; -public class CssStyleElement extends ChildBasedElement implements Inline { - private boolean isInline = true; +import java.util.ArrayList; +import java.util.List; - public CssStyleElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @Nullable Attributes attributes) { - super(style, layoutStyle, parent, qName, attributes); - assert attributes != null; +public class CssStyleElement implements FormattingElement { + protected final List supportedProperties = new ArrayList() {{ + add("color"); + add("text-align"); + add("text-decoration"); + add("font-size"); + }}; + + @Override + public void applyStyle(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @NotNull Attributes attributes) { String inlineCss = attributes.getValue("style"); if (inlineCss == null) return; - this.layoutStyle = this.layoutStyle.clone(); String[] parts = inlineCss.split(";"); for (String part : parts) { String[] propertyValue = part.split(":"); @@ -45,21 +49,18 @@ public CssStyleElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Null String value = propertyValue[1].trim(); switch (property) { case "color": - this.layoutStyle.setTextColor(ColorFactory.web(value)); + layoutStyle.setTextColor(ColorFactory.web(value)); break; case "text-align": switch (value.toLowerCase()) { case "left": - this.layoutStyle.setAlignment(LayoutStyle.Alignment.LEFT); - isInline = false; + layoutStyle.setAlignment(LayoutStyle.Alignment.LEFT); break; case "center": - this.layoutStyle.setAlignment(LayoutStyle.Alignment.CENTER); - isInline = false; + layoutStyle.setAlignment(LayoutStyle.Alignment.CENTER); break; case "right": - this.layoutStyle.setAlignment(LayoutStyle.Alignment.RIGHT); - isInline = false; + layoutStyle.setAlignment(LayoutStyle.Alignment.RIGHT); break; } break; @@ -67,10 +68,10 @@ public CssStyleElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Null for (String decoration : value.split(" ")) { switch (decoration) { case "underline": - this.layoutStyle.setUnderlined(true); + layoutStyle.setUnderlined(true); break; case "line-through": - this.layoutStyle.setStrikethrough(true); + layoutStyle.setStrikethrough(true); break; } } @@ -83,7 +84,7 @@ public CssStyleElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Null fontSize = layoutStyle.getFontSize() * (Float.parseFloat(value.substring(0, value.length() - 1)) / 100); } if (fontSize != null) { - this.layoutStyle.setFontSize(fontSize); + layoutStyle.setFontSize(fontSize); } break; } @@ -91,25 +92,17 @@ public CssStyleElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Null } @Override - public boolean isInline() { - return isInline; + public boolean canBeInline(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { + return !attributes.getValue("style").contains("text-align"); } @Override - public String toString() { - return "CssStyleElement {" + attributes.getValue("style") + "}"; - } - - public static class CssStyleElementCreator implements ElementCreator { - - @Override - public Element createElement(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { - return new CssStyleElement<>(style, layoutStyle, parent, qName, attributes); - } - - @Override - public boolean appliesTo(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { - return attributes.getValue("style") != null; + public boolean appliesTo(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { + String styleCss = attributes.getValue("style"); + if (styleCss == null) return false; + for (String property : supportedProperties) { + if (styleCss.contains(property)) return true; } + return false; } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/FormattingElement.java b/src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/TextFormattingElement.java similarity index 59% rename from src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/FormattingElement.java rename to src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/TextFormattingElement.java index 4473b16..778215f 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/FormattingElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/formatting/impl/TextFormattingElement.java @@ -15,46 +15,44 @@ * along with this program. If not, see . */ -package dev.dediamondpro.minemark.elements.impl.formatting; +package dev.dediamondpro.minemark.elements.formatting.impl; import dev.dediamondpro.minemark.LayoutStyle; -import dev.dediamondpro.minemark.elements.ChildBasedElement; import dev.dediamondpro.minemark.elements.Element; -import dev.dediamondpro.minemark.elements.Inline; +import dev.dediamondpro.minemark.elements.Elements; +import dev.dediamondpro.minemark.elements.formatting.TagBasedFormattingElement; import dev.dediamondpro.minemark.style.Style; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.xml.sax.Attributes; -public class FormattingElement extends ChildBasedElement implements Inline { - public FormattingElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @Nullable Attributes attributes) { - super(style, layoutStyle, parent, qName, attributes); - this.layoutStyle = this.layoutStyle.clone(); +public class TextFormattingElement extends TagBasedFormattingElement { + public TextFormattingElement() { + super(Elements.TEXT_FORMATTING); + } + + @Override + public void applyStyle(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @NotNull Attributes attributes) { switch (qName) { case "strong": case "b": - this.layoutStyle.setBold(true); + layoutStyle.setBold(true); break; case "em": case "i": - this.layoutStyle.setItalic(true); + layoutStyle.setItalic(true); break; case "ins": case "u": - this.layoutStyle.setUnderlined(true); + layoutStyle.setUnderlined(true); break; case "del": case "s": - this.layoutStyle.setStrikethrough(true); + layoutStyle.setStrikethrough(true); break; case "pre": - this.layoutStyle.setPreFormatted(true); + layoutStyle.setPreFormatted(true); break; } } - - @Override - public String toString() { - return "FormattingElement {" + qName + "}"; - } } diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/CodeBlockElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/CodeBlockElement.java index bc43d93..c133964 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/CodeBlockElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/CodeBlockElement.java @@ -21,6 +21,7 @@ import dev.dediamondpro.minemark.LayoutStyle; import dev.dediamondpro.minemark.elements.ChildMovingElement; import dev.dediamondpro.minemark.elements.Element; +import dev.dediamondpro.minemark.elements.Inline; import dev.dediamondpro.minemark.style.Style; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -29,7 +30,7 @@ import java.awt.*; -public abstract class CodeBlockElement extends ChildMovingElement { +public abstract class CodeBlockElement extends ChildMovingElement implements Inline { protected final CodeBlockType codeBlockType; public CodeBlockElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @Nullable Attributes attributes) { @@ -79,6 +80,11 @@ protected MarkerType getMarkerType() { return MarkerType.BLOCK; } + @Override + public boolean isInline() { + return codeBlockType == CodeBlockType.INLINE; + } + public enum CodeBlockType { INLINE, BLOCK diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/HeadingElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/HeadingElement.java similarity index 98% rename from src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/HeadingElement.java rename to src/main/java/dev/dediamondpro/minemark/elements/impl/HeadingElement.java index f108fe2..298e68b 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/HeadingElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/HeadingElement.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package dev.dediamondpro.minemark.elements.impl.formatting; +package dev.dediamondpro.minemark.elements.impl; import dev.dediamondpro.minemark.LayoutData; import dev.dediamondpro.minemark.LayoutStyle; 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 deleted file mode 100644 index 4a9f4aa..0000000 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/formatting/AlignmentElement.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of MineMark - * Copyright (C) 2024 DeDiamondPro - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License Version 3 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package dev.dediamondpro.minemark.elements.impl.formatting; - -import dev.dediamondpro.minemark.LayoutStyle; -import dev.dediamondpro.minemark.elements.ChildBasedElement; -import dev.dediamondpro.minemark.elements.Element; -import dev.dediamondpro.minemark.elements.creators.ElementCreator; -import dev.dediamondpro.minemark.style.Style; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.xml.sax.Attributes; - -public class AlignmentElement extends ChildBasedElement { - protected String alignment; - - public AlignmentElement(@NotNull S style, @NotNull LayoutStyle layoutStyle, @Nullable Element parent, @NotNull String qName, @Nullable Attributes attributes) { - super(style, layoutStyle, parent, qName, attributes); - this.layoutStyle = this.layoutStyle.clone(); - alignment = qName.equals("div") ? (attributes != null ? attributes.getValue("align") : null) : qName; - if (alignment == null) return; - switch (alignment) { - case "left": - this.layoutStyle.setAlignment(LayoutStyle.Alignment.LEFT); - break; - case "center": - this.layoutStyle.setAlignment(LayoutStyle.Alignment.CENTER); - break; - case "right": - this.layoutStyle.setAlignment(LayoutStyle.Alignment.RIGHT); - break; - } - } - - @Override - public String toString() { - return "AlignmentElement {" + qName + "}"; - } - - public static class AlignmentElementCreator implements ElementCreator { - - @Override - public Element createElement(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { - return new AlignmentElement<>(style, layoutStyle, parent, qName, attributes); - } - - @Override - public boolean appliesTo(S style, LayoutStyle layoutStyle, @NotNull Element parent, @NotNull String qName, @NotNull Attributes attributes) { - return qName.equals("center") || (qName.equals("div") && attributes.getValue("align") != null); - } - } -} diff --git a/src/main/java/dev/dediamondpro/minemark/elements/impl/table/TableRowElement.java b/src/main/java/dev/dediamondpro/minemark/elements/impl/table/TableRowElement.java index ecf1f19..f309189 100644 --- a/src/main/java/dev/dediamondpro/minemark/elements/impl/table/TableRowElement.java +++ b/src/main/java/dev/dediamondpro/minemark/elements/impl/table/TableRowElement.java @@ -71,18 +71,14 @@ public void onMouseClickedInternal(MouseButton button, float mouseX, float mouse @Override public void generateLayout(LayoutData layoutData, R renderData) { if (children.isEmpty()) return; - if (layoutData.isLineOccupied()) { - layoutData.nextLine(); - } cellWidth = layoutData.getMaxWidth() / (children.isEmpty() ? 1 : children.size()); cellHeight = 0; for (Element child : children) { LayoutData newLayoutData = new LayoutData(cellWidth); - child.generateLayout(newLayoutData, renderData); + child.generateLayoutInternal(newLayoutData, renderData); cellHeight = Math.max(cellHeight, newLayoutData.getY() + newLayoutData.getCurrentLine().getHeight()); } position = layoutData.addElement(LayoutStyle.Alignment.LEFT, layoutData.getMaxWidth(), cellHeight); - layoutData.nextLine(); } }