Merge ImagePanelComponent with PanelComponent
- Remove ImagePanelComponent - Add LayoutableRenderableEntity that is RenderableEntity with preferred size - Add support to PanelComponent for rendering list of LayoutableRenderableEntity - Add support for aligning PanelComponent horizontally or vertically - Add ImageComponent to be used in PanelComponent - Make other components support new design Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.ui.overlay.components;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Setter
|
||||||
|
public class ImageComponent implements LayoutableRenderableEntity
|
||||||
|
{
|
||||||
|
private BufferedImage image;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension render(Graphics2D graphics)
|
||||||
|
{
|
||||||
|
if (image == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics.drawImage(image, 0, -graphics.getFontMetrics().getHeight(), null);
|
||||||
|
return new Dimension(image.getWidth(), image.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreferredSize(Dimension dimension)
|
||||||
|
{
|
||||||
|
// Just use image dimensions for now
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2017, Devin French <https://github.com/devinfrench>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package net.runelite.client.ui.overlay.components;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.FontMetrics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.Point;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import net.runelite.client.ui.overlay.RenderableEntity;
|
|
||||||
|
|
||||||
public class ImagePanelComponent implements RenderableEntity
|
|
||||||
{
|
|
||||||
private static final int TOP_BORDER = 4;
|
|
||||||
private static final int SIDE_BORDER = 4;
|
|
||||||
private static final int BOTTOM_BORDER = 4;
|
|
||||||
private static final int SEPARATOR = 1;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Nullable
|
|
||||||
private String title;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private Color titleColor = Color.WHITE;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private Color backgroundColor = BackgroundComponent.DEFAULT_BACKGROUND_COLOR;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final List<BufferedImage> images = new ArrayList<>();
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private Point position = new Point();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension render(Graphics2D graphics)
|
|
||||||
{
|
|
||||||
final Dimension dimension = new Dimension();
|
|
||||||
final FontMetrics metrics = graphics.getFontMetrics();
|
|
||||||
|
|
||||||
//Determine max height and width of images
|
|
||||||
int maxImageHeight = 0;
|
|
||||||
int imageWidth = 0;
|
|
||||||
for (final BufferedImage image : images)
|
|
||||||
{
|
|
||||||
if (image.getHeight() > maxImageHeight)
|
|
||||||
{
|
|
||||||
maxImageHeight = image.getHeight();
|
|
||||||
}
|
|
||||||
imageWidth += image.getWidth() + SEPARATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
int height = TOP_BORDER + (Strings.isNullOrEmpty(title) ? 0 : metrics.getHeight() + SEPARATOR)
|
|
||||||
+ maxImageHeight + BOTTOM_BORDER;
|
|
||||||
int width = Math.max(Strings.isNullOrEmpty(title) ? 0 : metrics.stringWidth(title), imageWidth) + SIDE_BORDER * 2;
|
|
||||||
dimension.setSize(width, height);
|
|
||||||
|
|
||||||
if (dimension.height == TOP_BORDER + BOTTOM_BORDER)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int y = position.y + TOP_BORDER;
|
|
||||||
if (!Strings.isNullOrEmpty(title))
|
|
||||||
{
|
|
||||||
// Calculate panel dimensions
|
|
||||||
y += metrics.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render background
|
|
||||||
final BackgroundComponent backgroundComponent = new BackgroundComponent();
|
|
||||||
backgroundComponent.setBackgroundColor(backgroundColor);
|
|
||||||
backgroundComponent.setRectangle(new Rectangle(position.x, position.y, dimension.width, dimension.height));
|
|
||||||
backgroundComponent.render(graphics);
|
|
||||||
|
|
||||||
// Render title
|
|
||||||
if (!Strings.isNullOrEmpty(title))
|
|
||||||
{
|
|
||||||
final TextComponent titleComponent = new TextComponent();
|
|
||||||
titleComponent.setText(title);
|
|
||||||
titleComponent.setColor(titleColor);
|
|
||||||
titleComponent.setPosition(new Point(position.x + (width - metrics.stringWidth(title)) / 2, y));
|
|
||||||
titleComponent.render(graphics);
|
|
||||||
y += SEPARATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render all images
|
|
||||||
int imageOffsetX = ((width - imageWidth) / 2);
|
|
||||||
for (final BufferedImage image : images)
|
|
||||||
{
|
|
||||||
graphics.drawImage(image, imageOffsetX + ((imageWidth / images.size()) - image.getWidth()) / 2, y, null);
|
|
||||||
imageOffsetX += image.getWidth() + SEPARATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dimension;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.ui.overlay.components;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import net.runelite.client.ui.overlay.RenderableEntity;
|
||||||
|
|
||||||
|
public interface LayoutableRenderableEntity extends RenderableEntity
|
||||||
|
{
|
||||||
|
void setPreferredSize(Dimension dimension);
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.client.ui.overlay.components;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Point;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
public class LineComponent implements LayoutableRenderableEntity
|
||||||
|
{
|
||||||
|
private static final int SEPARATOR = 1;
|
||||||
|
|
||||||
|
private String left;
|
||||||
|
private String right;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private Color leftColor = Color.WHITE;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private Color rightColor = Color.WHITE;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private Dimension preferredSize = new Dimension();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension render(Graphics2D graphics)
|
||||||
|
{
|
||||||
|
// Prevent NPEs
|
||||||
|
final String left = MoreObjects.firstNonNull(this.left, "");
|
||||||
|
final String right = MoreObjects.firstNonNull(this.right, "");
|
||||||
|
|
||||||
|
final FontMetrics metrics = graphics.getFontMetrics();
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
final int leftFullWidth = getLineWidth(left, metrics);
|
||||||
|
final int rightFullWidth = getLineWidth(right, metrics);
|
||||||
|
|
||||||
|
if (preferredSize.width < leftFullWidth + rightFullWidth)
|
||||||
|
{
|
||||||
|
int leftSmallWidth = preferredSize.width;
|
||||||
|
int rightSmallWidth = 0;
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(right))
|
||||||
|
{
|
||||||
|
rightSmallWidth = (preferredSize.width / 3);
|
||||||
|
leftSmallWidth -= rightSmallWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String[] leftSplitLines = lineBreakText(left, leftSmallWidth, metrics);
|
||||||
|
final String[] rightSplitLines = lineBreakText(right, rightSmallWidth, metrics);
|
||||||
|
|
||||||
|
int lineCount = Math.max(leftSplitLines.length, rightSplitLines.length);
|
||||||
|
|
||||||
|
for (int i = 0; i < lineCount; i++)
|
||||||
|
{
|
||||||
|
String leftText = "";
|
||||||
|
String rightText = "";
|
||||||
|
|
||||||
|
if (i < leftSplitLines.length)
|
||||||
|
{
|
||||||
|
leftText = leftSplitLines[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < rightSplitLines.length)
|
||||||
|
{
|
||||||
|
rightText = rightSplitLines[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextComponent leftLineComponent = new TextComponent();
|
||||||
|
leftLineComponent.setPosition(new Point(x, y));
|
||||||
|
leftLineComponent.setText(leftText);
|
||||||
|
leftLineComponent.setColor(leftColor);
|
||||||
|
leftLineComponent.render(graphics);
|
||||||
|
|
||||||
|
final TextComponent rightLineComponent = new TextComponent();
|
||||||
|
rightLineComponent.setPosition(new Point(x + leftSmallWidth + rightFullWidth - getLineWidth(rightText, metrics), y));
|
||||||
|
rightLineComponent.setText(rightText);
|
||||||
|
rightLineComponent.setColor(rightColor);
|
||||||
|
rightLineComponent.render(graphics);
|
||||||
|
y += metrics.getHeight() + SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Dimension(preferredSize.width, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextComponent leftLineComponent = new TextComponent();
|
||||||
|
leftLineComponent.setPosition(new Point(x, y));
|
||||||
|
leftLineComponent.setText(left);
|
||||||
|
leftLineComponent.setColor(leftColor);
|
||||||
|
leftLineComponent.render(graphics);
|
||||||
|
|
||||||
|
final TextComponent rightLineComponent = new TextComponent();
|
||||||
|
rightLineComponent.setPosition(new Point(x + preferredSize.width - getLineWidth(right, metrics), y));
|
||||||
|
rightLineComponent.setText(right);
|
||||||
|
rightLineComponent.setColor(rightColor);
|
||||||
|
rightLineComponent.render(graphics);
|
||||||
|
y += metrics.getHeight() + SEPARATOR;
|
||||||
|
|
||||||
|
return new Dimension(preferredSize.width, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getLineWidth(final String line, final FontMetrics metrics)
|
||||||
|
{
|
||||||
|
return metrics.stringWidth(TextComponent.textWithoutColTags(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] lineBreakText(String text, int maxWidth, FontMetrics metrics)
|
||||||
|
{
|
||||||
|
final String[] words = text.split(" ");
|
||||||
|
|
||||||
|
if (words.length == 0)
|
||||||
|
{
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder wrapped = new StringBuilder(words[0]);
|
||||||
|
int spaceLeft = maxWidth - metrics.stringWidth(wrapped.toString());
|
||||||
|
|
||||||
|
for (int i = 1; i < words.length; i++)
|
||||||
|
{
|
||||||
|
final String word = words[i];
|
||||||
|
final int wordLen = metrics.stringWidth(word);
|
||||||
|
final int spaceWidth = metrics.stringWidth(" ");
|
||||||
|
|
||||||
|
if (wordLen + spaceWidth > spaceLeft)
|
||||||
|
{
|
||||||
|
wrapped.append("\n").append(word);
|
||||||
|
spaceLeft = maxWidth - wordLen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wrapped.append(" ").append(word);
|
||||||
|
spaceLeft -= spaceWidth + wordLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapped.toString().split("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -33,78 +33,23 @@ import java.awt.Point;
|
|||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.Objects;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.runelite.client.ui.overlay.RenderableEntity;
|
|
||||||
|
|
||||||
public class PanelComponent implements RenderableEntity
|
public class PanelComponent implements LayoutableRenderableEntity
|
||||||
{
|
{
|
||||||
|
public enum Orientation
|
||||||
|
{
|
||||||
|
HORIZONTAL,
|
||||||
|
VERTICAL;
|
||||||
|
}
|
||||||
|
|
||||||
private static final int TOP_BORDER = 4;
|
private static final int TOP_BORDER = 4;
|
||||||
private static final int LEFT_BORDER = 4;
|
private static final int LEFT_BORDER = 4;
|
||||||
private static final int RIGHT_BORDER = 4;
|
private static final int RIGHT_BORDER = 4;
|
||||||
private static final int BOTTOM_BORDER = 4;
|
private static final int BOTTOM_BORDER = 4;
|
||||||
private static final int SEPARATOR = 1;
|
private static final int SEPARATOR = 1;
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public static class Line
|
|
||||||
{
|
|
||||||
private boolean wrapWords;
|
|
||||||
private String left;
|
|
||||||
private Color leftColor = Color.WHITE;
|
|
||||||
private String right = "";
|
|
||||||
private Color rightColor = Color.WHITE;
|
|
||||||
|
|
||||||
public Line(String left)
|
|
||||||
{
|
|
||||||
this.left = left;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Line(boolean wrapWords, String left)
|
|
||||||
{
|
|
||||||
this.wrapWords = wrapWords;
|
|
||||||
this.left = left;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Line(String left, Color leftColor)
|
|
||||||
{
|
|
||||||
this.left = left;
|
|
||||||
this.leftColor = leftColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Line(boolean wrapWords, String left, Color leftColor)
|
|
||||||
{
|
|
||||||
this.wrapWords = wrapWords;
|
|
||||||
this.left = left;
|
|
||||||
this.leftColor = leftColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Line(String left, String right)
|
|
||||||
{
|
|
||||||
this.left = left;
|
|
||||||
this.right = right;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Line(boolean wrapWords, String left, String right)
|
|
||||||
{
|
|
||||||
this.wrapWords = wrapWords;
|
|
||||||
this.left = left;
|
|
||||||
this.right = right;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Line(String left, Color leftColor, String right, Color rightColor)
|
|
||||||
{
|
|
||||||
this.left = left;
|
|
||||||
this.leftColor = leftColor;
|
|
||||||
this.right = right;
|
|
||||||
this.rightColor = rightColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
@@ -117,152 +62,92 @@ public class PanelComponent implements RenderableEntity
|
|||||||
@Setter
|
@Setter
|
||||||
private Point position = new Point();
|
private Point position = new Point();
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private Dimension preferredSize = new Dimension(129, 0);
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private List<Line> lines = new ArrayList<>();
|
private List<LayoutableRenderableEntity> children = new ArrayList<>();
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private ProgressBarComponent progressBar;
|
private Orientation orientation = Orientation.VERTICAL;
|
||||||
|
|
||||||
@Setter
|
private final Dimension savedChildrenSize = new Dimension();
|
||||||
private int width = 129;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension render(Graphics2D graphics)
|
public Dimension render(Graphics2D graphics)
|
||||||
{
|
{
|
||||||
final FontMetrics metrics = graphics.getFontMetrics();
|
if (Strings.isNullOrEmpty(title) && children.isEmpty())
|
||||||
|
|
||||||
// Do word wrapping
|
|
||||||
ListIterator<Line> iterator = lines.listIterator();
|
|
||||||
while (iterator.hasNext())
|
|
||||||
{
|
|
||||||
Line line = iterator.next();
|
|
||||||
|
|
||||||
if (line.wrapWords)
|
|
||||||
{
|
|
||||||
iterator.remove();
|
|
||||||
|
|
||||||
int maxWidth = width;
|
|
||||||
if (line.right.length() > 0)
|
|
||||||
{
|
|
||||||
maxWidth /= 2;
|
|
||||||
}
|
|
||||||
maxWidth -= LEFT_BORDER + RIGHT_BORDER;
|
|
||||||
|
|
||||||
List<String> leftSplitLines = lineBreakText(line.getLeft(), maxWidth, metrics);
|
|
||||||
List<String> rightSplitLines = lineBreakText(line.getRight(), maxWidth, metrics);
|
|
||||||
|
|
||||||
int lineCount = Math.max(leftSplitLines.size(), rightSplitLines.size());
|
|
||||||
|
|
||||||
for (int i = 0; i < lineCount; i++)
|
|
||||||
{
|
|
||||||
String left = "";
|
|
||||||
String right = "";
|
|
||||||
|
|
||||||
if (i < leftSplitLines.size())
|
|
||||||
{
|
|
||||||
left = leftSplitLines.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < rightSplitLines.size())
|
|
||||||
{
|
|
||||||
right = rightSplitLines.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator.add(new Line(false, left, line.getLeftColor(), right, line.getRightColor()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Dimension dimension = new Dimension();
|
|
||||||
final int elementNumber = (Strings.isNullOrEmpty(title) ? 0 : 1) + lines.size() + (Objects.isNull(progressBar) ? 0 : 1);
|
|
||||||
int height = elementNumber == 0 ? 0 :
|
|
||||||
TOP_BORDER + (graphics.getFontMetrics().getHeight() * elementNumber)
|
|
||||||
+ SEPARATOR * elementNumber + (Objects.isNull(progressBar) ? 0 : progressBar.getHeight() / 2)
|
|
||||||
+ BOTTOM_BORDER;
|
|
||||||
dimension.setSize(width, height);
|
|
||||||
|
|
||||||
if (dimension.height == 0)
|
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final FontMetrics metrics = graphics.getFontMetrics();
|
||||||
|
|
||||||
// Calculate panel dimensions
|
// Calculate panel dimensions
|
||||||
int y = position.y + TOP_BORDER + metrics.getHeight();
|
int width = preferredSize.width;
|
||||||
|
int height = preferredSize.height;
|
||||||
|
int x = LEFT_BORDER;
|
||||||
|
int y = TOP_BORDER + metrics.getHeight();
|
||||||
|
|
||||||
|
// Set graphics offset at correct position
|
||||||
|
graphics.translate(position.x, position.y);
|
||||||
|
|
||||||
// Render background
|
// Render background
|
||||||
|
final Dimension dimension = new Dimension(
|
||||||
|
savedChildrenSize.width + RIGHT_BORDER,
|
||||||
|
savedChildrenSize.height + BOTTOM_BORDER);
|
||||||
|
|
||||||
final BackgroundComponent backgroundComponent = new BackgroundComponent();
|
final BackgroundComponent backgroundComponent = new BackgroundComponent();
|
||||||
|
backgroundComponent.setRectangle(new Rectangle(dimension));
|
||||||
backgroundComponent.setBackgroundColor(backgroundColor);
|
backgroundComponent.setBackgroundColor(backgroundColor);
|
||||||
backgroundComponent.setRectangle(new Rectangle(position.x, position.y, dimension.width, dimension.height));
|
|
||||||
backgroundComponent.render(graphics);
|
backgroundComponent.render(graphics);
|
||||||
|
|
||||||
// Render title
|
|
||||||
if (!Strings.isNullOrEmpty(title))
|
if (!Strings.isNullOrEmpty(title))
|
||||||
{
|
{
|
||||||
|
// Render title
|
||||||
final TextComponent titleComponent = new TextComponent();
|
final TextComponent titleComponent = new TextComponent();
|
||||||
titleComponent.setText(title);
|
titleComponent.setText(title);
|
||||||
titleComponent.setColor(titleColor);
|
titleComponent.setColor(titleColor);
|
||||||
titleComponent.setPosition(new Point(position.x + (width - metrics.stringWidth(title)) / 2, y));
|
titleComponent.setPosition(new Point((dimension.width - metrics.stringWidth(title)) / 2, y));
|
||||||
titleComponent.render(graphics);
|
titleComponent.render(graphics);
|
||||||
y += metrics.getHeight() + SEPARATOR;
|
|
||||||
|
// Move children a bit
|
||||||
|
height = y += metrics.getHeight() + SEPARATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render all lines
|
// Render all children
|
||||||
for (final Line line : lines)
|
final Dimension childPreferredSize = new Dimension(
|
||||||
|
preferredSize.width - RIGHT_BORDER,
|
||||||
|
preferredSize.height - BOTTOM_BORDER);
|
||||||
|
|
||||||
|
for (final LayoutableRenderableEntity child : children)
|
||||||
{
|
{
|
||||||
final TextComponent leftLineComponent = new TextComponent();
|
child.setPreferredSize(childPreferredSize);
|
||||||
leftLineComponent.setPosition(new Point(position.x + LEFT_BORDER, y));
|
graphics.translate(x, y);
|
||||||
leftLineComponent.setText(line.getLeft());
|
final Dimension childDimension = child.render(graphics);
|
||||||
leftLineComponent.setColor(line.getLeftColor());
|
graphics.translate(-x, -y);
|
||||||
leftLineComponent.render(graphics);
|
|
||||||
|
|
||||||
final TextComponent rightLineComponent = new TextComponent();
|
switch (orientation)
|
||||||
rightLineComponent.setPosition(new Point(position.x + width - RIGHT_BORDER - metrics.stringWidth(TextComponent.textWithoutColTags(line.getRight())), y));
|
{
|
||||||
rightLineComponent.setText(line.getRight());
|
case VERTICAL:
|
||||||
rightLineComponent.setColor(line.getRightColor());
|
height = y += childDimension.height + SEPARATOR;
|
||||||
rightLineComponent.render(graphics);
|
width = Math.max(width, x + childDimension.width);
|
||||||
y += metrics.getHeight() + SEPARATOR;
|
break;
|
||||||
|
case HORIZONTAL:
|
||||||
|
width = x += childDimension.width + SEPARATOR;
|
||||||
|
height = Math.max(height, y + childDimension.height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Render progress bar
|
// Reset the padding
|
||||||
if (!Objects.isNull(progressBar))
|
height -= metrics.getHeight();
|
||||||
{
|
|
||||||
progressBar.setWidth(width - LEFT_BORDER - RIGHT_BORDER);
|
|
||||||
progressBar.setPosition(new Point(position.x + LEFT_BORDER, y - (metrics.getHeight() / 2)));
|
|
||||||
progressBar.render(graphics);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Save children size
|
||||||
|
savedChildrenSize.setSize(width, height);
|
||||||
|
|
||||||
|
// Reset graphics position
|
||||||
|
graphics.translate(-position.x, -position.y);
|
||||||
return dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> lineBreakText(String text, int maxWidth, FontMetrics metrics)
|
|
||||||
{
|
|
||||||
List<String> lines = new ArrayList<>();
|
|
||||||
|
|
||||||
int pos = 0;
|
|
||||||
String[] words = text.split(" ");
|
|
||||||
String line = "";
|
|
||||||
|
|
||||||
while (pos < words.length)
|
|
||||||
{
|
|
||||||
String newLine = pos > 0 && !line.isEmpty()
|
|
||||||
? line + " " + words[pos]
|
|
||||||
: words[pos];
|
|
||||||
int width = metrics.stringWidth(newLine);
|
|
||||||
|
|
||||||
if (width >= maxWidth)
|
|
||||||
{
|
|
||||||
lines.add(line);
|
|
||||||
line = "";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
line = newLine;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.add(line);
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,9 @@ import java.awt.FontMetrics;
|
|||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class ProgressBarComponent
|
public class ProgressBarComponent implements LayoutableRenderableEntity
|
||||||
{
|
{
|
||||||
@Setter
|
@Setter
|
||||||
private String text;
|
private String text;
|
||||||
@@ -54,20 +53,16 @@ public class ProgressBarComponent
|
|||||||
@Setter
|
@Setter
|
||||||
private Color fontColor = Color.WHITE;
|
private Color fontColor = Color.WHITE;
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
@Setter
|
||||||
private int width = 140;
|
private Dimension preferredSize = new Dimension(129, 16);
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private int height = 16;
|
|
||||||
|
|
||||||
|
@Override
|
||||||
public Dimension render(Graphics2D graphics)
|
public Dimension render(Graphics2D graphics)
|
||||||
{
|
{
|
||||||
FontMetrics metrics = graphics.getFontMetrics();
|
FontMetrics metrics = graphics.getFontMetrics();
|
||||||
|
|
||||||
int barX = position.x;
|
int barX = position.x;
|
||||||
int barY = position.y;
|
int barY = position.y - metrics.getHeight();
|
||||||
String textToWrite;
|
String textToWrite;
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(text))
|
if (Strings.isNullOrEmpty(text))
|
||||||
@@ -80,6 +75,9 @@ public class ProgressBarComponent
|
|||||||
textToWrite = text;
|
textToWrite = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int width = preferredSize.width;
|
||||||
|
int height = Math.max(preferredSize.height, 16);
|
||||||
|
|
||||||
int progressTextX = barX + (width - metrics.stringWidth(textToWrite)) / 2;
|
int progressTextX = barX + (width - metrics.stringWidth(textToWrite)) / 2;
|
||||||
int progressTextY = barY + ((height - metrics.getHeight()) / 2) + metrics.getAscent();
|
int progressTextY = barY + ((height - metrics.getHeight()) / 2) + metrics.getAscent();
|
||||||
|
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ public class TextComponent implements RenderableEntity
|
|||||||
|
|
||||||
if (COL_TAG_PATTERN.matcher(text).find())
|
if (COL_TAG_PATTERN.matcher(text).find())
|
||||||
{
|
{
|
||||||
String[] parts = COL_TAG_PATTERN_W_LOOKAHEAD.split(text);
|
final String[] parts = COL_TAG_PATTERN_W_LOOKAHEAD.split(text);
|
||||||
int x = position.x;
|
int x = position.x;
|
||||||
for (int i = 0; i < parts.length; i++)
|
|
||||||
|
for (String textSplitOnCol : parts)
|
||||||
{
|
{
|
||||||
String textSplitOnCol = parts[i];
|
final String textWithoutCol = textWithoutColTags(textSplitOnCol);
|
||||||
String textWithoutCol = textWithoutColTags(textSplitOnCol);
|
final String colColor = textSplitOnCol.substring(textSplitOnCol.indexOf("=") + 1, textSplitOnCol.indexOf(">"));
|
||||||
String colColor = textSplitOnCol.substring(textSplitOnCol.indexOf("=") + 1, textSplitOnCol.indexOf(">"));
|
|
||||||
|
|
||||||
// shadow
|
// shadow
|
||||||
graphics.setColor(Color.BLACK);
|
graphics.setColor(Color.BLACK);
|
||||||
@@ -89,6 +89,7 @@ public class TextComponent implements RenderableEntity
|
|||||||
graphics.setColor(color);
|
graphics.setColor(color);
|
||||||
graphics.drawString(text, position.x, position.y);
|
graphics.drawString(text, position.x, position.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Dimension(fontMetrics.stringWidth(text), fontMetrics.getHeight());
|
return new Dimension(fontMetrics.stringWidth(text), fontMetrics.getHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user