mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Implement custom text box renderer
This commit is contained in:
@@ -77,8 +77,10 @@ public class CardFaceSymbols {
|
|||||||
|
|
||||||
MANA_IMAGES.put("S", FSkin.getImage(FSkinProp.IMG_MANA_SNOW));
|
MANA_IMAGES.put("S", FSkin.getImage(FSkinProp.IMG_MANA_SNOW));
|
||||||
MANA_IMAGES.put("T", FSkin.getImage(FSkinProp.IMG_TAP));
|
MANA_IMAGES.put("T", FSkin.getImage(FSkinProp.IMG_TAP));
|
||||||
|
MANA_IMAGES.put("Q", FSkin.getImage(FSkinProp.IMG_UNTAP));
|
||||||
MANA_IMAGES.put("E", FSkin.getImage(FSkinProp.IMG_ENERGY, 40, 40));
|
MANA_IMAGES.put("E", FSkin.getImage(FSkinProp.IMG_ENERGY, 40, 40));
|
||||||
MANA_IMAGES.put("EXPERIENCE", FSkin.getImage(FSkinProp.IMG_EXPERIENCE, 40, 30));
|
MANA_IMAGES.put("EXPERIENCE", FSkin.getImage(FSkinProp.IMG_EXPERIENCE, 40, 30));
|
||||||
|
MANA_IMAGES.put("CHAOS", FSkin.getImage(FSkinProp.IMG_CHAOS));
|
||||||
MANA_IMAGES.put("slash", FSkin.getImage(FSkinProp.IMG_SLASH));
|
MANA_IMAGES.put("slash", FSkin.getImage(FSkinProp.IMG_SLASH));
|
||||||
MANA_IMAGES.put("attack", FSkin.getImage(FSkinProp.IMG_ATTACK, 32, 32));
|
MANA_IMAGES.put("attack", FSkin.getImage(FSkinProp.IMG_ATTACK, 32, 32));
|
||||||
MANA_IMAGES.put("defend", FSkin.getImage(FSkinProp.IMG_DEFEND, 32, 32));
|
MANA_IMAGES.put("defend", FSkin.getImage(FSkinProp.IMG_DEFEND, 32, 32));
|
||||||
|
|||||||
@@ -9,10 +9,14 @@ import java.awt.Graphics2D;
|
|||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
|
import java.text.BreakIterator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import javax.swing.JEditorPane;
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -24,7 +28,9 @@ import forge.game.card.CardView.CardStateView;
|
|||||||
import forge.gui.card.CardDetailUtil;
|
import forge.gui.card.CardDetailUtil;
|
||||||
import forge.gui.card.CardDetailUtil.DetailColors;
|
import forge.gui.card.CardDetailUtil.DetailColors;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
|
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||||
import forge.localinstance.skin.FSkinProp;
|
import forge.localinstance.skin.FSkinProp;
|
||||||
|
import forge.model.FModel;
|
||||||
import forge.toolbox.CardFaceSymbols;
|
import forge.toolbox.CardFaceSymbols;
|
||||||
import forge.toolbox.FSkin;
|
import forge.toolbox.FSkin;
|
||||||
import forge.toolbox.FSkin.SkinIcon;
|
import forge.toolbox.FSkin.SkinIcon;
|
||||||
@@ -34,8 +40,8 @@ public class FCardImageRenderer {
|
|||||||
private static final float BASE_IMAGE_WIDTH = 480;
|
private static final float BASE_IMAGE_WIDTH = 480;
|
||||||
private static final float BASE_IMAGE_HEIGHT = 680;
|
private static final float BASE_IMAGE_HEIGHT = 680;
|
||||||
private static float MANA_SYMBOL_SIZE, PT_BOX_WIDTH, HEADER_PADDING, BORDER_THICKNESS;
|
private static float MANA_SYMBOL_SIZE, PT_BOX_WIDTH, HEADER_PADDING, BORDER_THICKNESS;
|
||||||
private static Font NAME_FONT, TYPE_FONT, TEXT_FONT, PT_FONT;
|
private static Font NAME_FONT, TYPE_FONT, TEXT_FONT, REMINDER_FONT, PT_FONT;
|
||||||
private static FontMetrics NAME_METRICS, TYPE_METRICS, TEXT_METRICS, PT_METRICS;
|
private static FontMetrics NAME_METRICS, TYPE_METRICS, TEXT_METRICS, REMINDER_METRICS, PT_METRICS;
|
||||||
private static float prevImageWidth, prevImageHeight;
|
private static float prevImageWidth, prevImageHeight;
|
||||||
private static final float BLACK_BORDER_THICKNESS_RATIO = 0.021f;
|
private static final float BLACK_BORDER_THICKNESS_RATIO = 0.021f;
|
||||||
private static final float NAME_BOX_TINT = 0.2f;
|
private static final float NAME_BOX_TINT = 0.2f;
|
||||||
@@ -43,6 +49,13 @@ public class FCardImageRenderer {
|
|||||||
private static final float PT_BOX_TINT = 0.2f;
|
private static final float PT_BOX_TINT = 0.2f;
|
||||||
private static final float CARD_ART_RATIO = 1.32f;
|
private static final float CARD_ART_RATIO = 1.32f;
|
||||||
|
|
||||||
|
private static Locale locale;
|
||||||
|
private static BreakIterator boundary;
|
||||||
|
private static Pattern linebreakPattern;
|
||||||
|
private static Pattern reminderPattern;
|
||||||
|
private static Pattern symbolPattern;
|
||||||
|
private static final Map<Font, Font[]> shrinkFonts = new HashMap<>();
|
||||||
|
|
||||||
private static Color tintColor(Color source, Color tint, float alpha) {
|
private static Color tintColor(Color source, Color tint, float alpha) {
|
||||||
float r = (tint.getRed() - source.getRed()) * alpha + source.getRed();
|
float r = (tint.getRed() - source.getRed()) * alpha + source.getRed();
|
||||||
float g = (tint.getGreen() - source.getGreen()) * alpha + source.getGreen();
|
float g = (tint.getGreen() - source.getGreen()) * alpha + source.getGreen();
|
||||||
@@ -83,12 +96,27 @@ public class FCardImageRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Font getShrinkFont(Font orgFont, int newSize) {
|
||||||
|
Font font = shrinkFonts.get(orgFont)[newSize];
|
||||||
|
if (font == null) {
|
||||||
|
font = orgFont.deriveFont((float)newSize);
|
||||||
|
shrinkFonts.get(orgFont)[newSize] = font;
|
||||||
|
}
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
private static void updateStaticFields(Graphics2D g, float w, float h) {
|
private static void updateStaticFields(Graphics2D g, float w, float h) {
|
||||||
if (w == prevImageWidth && h == prevImageHeight) {
|
if (w == prevImageWidth && h == prevImageHeight) {
|
||||||
//for performance sake, only update static fields if card image size is different than previous rendered card
|
//for performance sake, only update static fields if card image size is different than previous rendered card
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locale = new Locale(FModel.getPreferences().getPref(FPref.UI_LANGUAGE));
|
||||||
|
boundary = BreakIterator.getLineInstance(locale);
|
||||||
|
linebreakPattern = Pattern.compile("(\r\n\r\n)|(\n)");
|
||||||
|
reminderPattern = Pattern.compile("\\((.+?)\\)");
|
||||||
|
symbolPattern = Pattern.compile("\\{([A-Z0-9]+)\\}|\\{([A-Z0-9]+)/([A-Z0-9]+)\\}");
|
||||||
|
|
||||||
float ratio = Math.min(w / BASE_IMAGE_WIDTH, h / BASE_IMAGE_HEIGHT);
|
float ratio = Math.min(w / BASE_IMAGE_WIDTH, h / BASE_IMAGE_HEIGHT);
|
||||||
|
|
||||||
MANA_SYMBOL_SIZE = 26 * ratio;
|
MANA_SYMBOL_SIZE = 26 * ratio;
|
||||||
@@ -96,14 +124,26 @@ public class FCardImageRenderer {
|
|||||||
HEADER_PADDING = 7 * ratio;
|
HEADER_PADDING = 7 * ratio;
|
||||||
NAME_FONT = new Font(Font.SERIF, Font.BOLD, Math.round(MANA_SYMBOL_SIZE));
|
NAME_FONT = new Font(Font.SERIF, Font.BOLD, Math.round(MANA_SYMBOL_SIZE));
|
||||||
TYPE_FONT = new Font(Font.SERIF, Font.BOLD, Math.round(MANA_SYMBOL_SIZE * 0.8f));
|
TYPE_FONT = new Font(Font.SERIF, Font.BOLD, Math.round(MANA_SYMBOL_SIZE * 0.8f));
|
||||||
TEXT_FONT = new Font(Font.SERIF, Font.PLAIN, Math.round(MANA_SYMBOL_SIZE * 0.7f));
|
if ("ja-JP".equals(FModel.getPreferences().getPref(FPref.UI_LANGUAGE)) || "zh-CN".equals(FModel.getPreferences().getPref(FPref.UI_LANGUAGE))) {
|
||||||
|
TEXT_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, Math.round(MANA_SYMBOL_SIZE * 0.93f));
|
||||||
|
REMINDER_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, Math.round(MANA_SYMBOL_SIZE * 0.93f) - 2);
|
||||||
|
} else {
|
||||||
|
TEXT_FONT = new Font(Font.SERIF, Font.PLAIN, Math.round(MANA_SYMBOL_SIZE * 0.93f));
|
||||||
|
REMINDER_FONT = new Font(Font.SERIF, Font.ITALIC, Math.round(MANA_SYMBOL_SIZE * 0.93f));
|
||||||
|
}
|
||||||
PT_FONT = NAME_FONT;
|
PT_FONT = NAME_FONT;
|
||||||
NAME_METRICS = g.getFontMetrics(NAME_FONT);
|
NAME_METRICS = g.getFontMetrics(NAME_FONT);
|
||||||
TYPE_METRICS = g.getFontMetrics(TYPE_FONT);
|
TYPE_METRICS = g.getFontMetrics(TYPE_FONT);
|
||||||
TEXT_METRICS = g.getFontMetrics(TEXT_FONT);
|
TEXT_METRICS = g.getFontMetrics(TEXT_FONT);
|
||||||
|
REMINDER_METRICS = g.getFontMetrics(REMINDER_FONT);
|
||||||
PT_METRICS = NAME_METRICS;
|
PT_METRICS = NAME_METRICS;
|
||||||
BORDER_THICKNESS = Math.max(2 * ratio, 1f); //don't let border go below 1
|
BORDER_THICKNESS = Math.max(2 * ratio, 1f); //don't let border go below 1
|
||||||
|
|
||||||
|
shrinkFonts.put(NAME_FONT, new Font[NAME_FONT.getSize()]);
|
||||||
|
shrinkFonts.put(TYPE_FONT, new Font[TYPE_FONT.getSize()]);
|
||||||
|
shrinkFonts.put(TEXT_FONT, new Font[TEXT_FONT.getSize()]);
|
||||||
|
shrinkFonts.put(REMINDER_FONT, new Font[REMINDER_FONT.getSize()]);
|
||||||
|
|
||||||
prevImageWidth = w;
|
prevImageWidth = w;
|
||||||
prevImageHeight = h;
|
prevImageHeight = h;
|
||||||
}
|
}
|
||||||
@@ -155,7 +195,7 @@ public class FCardImageRenderer {
|
|||||||
|
|
||||||
//draw text box
|
//draw text box
|
||||||
Color[] textBoxColors = tintColors(Color.WHITE, colors, TEXT_BOX_TINT);
|
Color[] textBoxColors = tintColors(Color.WHITE, colors, TEXT_BOX_TINT);
|
||||||
drawTextBox(g, card, state, textBoxColors, x + artInset, textY, w - 2 * artInset, textBoxHeight);
|
drawTextBox(g, card, state, textBoxColors, x + artInset, textY, w - 2 * artInset, textBoxHeight, ptBoxHeight > 0);
|
||||||
|
|
||||||
//draw header containing name and mana cost
|
//draw header containing name and mana cost
|
||||||
Color[] headerColors = tintColors(Color.WHITE, colors, NAME_BOX_TINT);
|
Color[] headerColors = tintColors(Color.WHITE, colors, NAME_BOX_TINT);
|
||||||
@@ -206,16 +246,21 @@ public class FCardImageRenderer {
|
|||||||
g.setPaint(oldPaint);
|
g.setPaint(oldPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawVerticallyCenteredString(Graphics2D g, String text, Rectangle area, Font font, final FontMetrics fontMetrics) {
|
private static void drawVerticallyCenteredString(Graphics2D g, String text, Rectangle area, Font font, FontMetrics fontMetrics) {
|
||||||
Font oldFont = g.getFont();
|
Font originalFont = font;
|
||||||
|
|
||||||
|
// Shrink font if the text is too long
|
||||||
|
while (fontMetrics.stringWidth(text) > area.width) {
|
||||||
|
int newSize = font.getSize() - 1;
|
||||||
|
font = getShrinkFont(originalFont, newSize);
|
||||||
|
fontMetrics = g.getFontMetrics(font);
|
||||||
|
}
|
||||||
|
|
||||||
int x = area.x;
|
int x = area.x;
|
||||||
int y = area.y + (area.height - fontMetrics.getHeight()) / 2 + fontMetrics.getAscent();
|
int y = area.y + (area.height - fontMetrics.getHeight()) / 2 + fontMetrics.getAscent();
|
||||||
|
|
||||||
g.setFont(font);
|
g.setFont(font);
|
||||||
g.drawString(text, x, y);
|
g.drawString(text, x, y);
|
||||||
g.setFont(oldFont);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawHeader(Graphics2D g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h) {
|
private static void drawHeader(Graphics2D g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h) {
|
||||||
@@ -293,7 +338,7 @@ public class FCardImageRenderer {
|
|||||||
TYPE_FONT, TYPE_METRICS);
|
TYPE_FONT, TYPE_METRICS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawTextBox(Graphics2D g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h) {
|
private static void drawTextBox(Graphics2D g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h, boolean hasPTBox) {
|
||||||
fillColorBackground(g, colors, x, y, w, h);
|
fillColorBackground(g, colors, x, y, w, h);
|
||||||
g.setStroke(new BasicStroke(BORDER_THICKNESS));
|
g.setStroke(new BasicStroke(BORDER_THICKNESS));
|
||||||
g.setColor(Color.BLACK);
|
g.setColor(Color.BLACK);
|
||||||
@@ -339,14 +384,7 @@ public class FCardImageRenderer {
|
|||||||
float padding = TEXT_METRICS.getAscent() * 0.25f;
|
float padding = TEXT_METRICS.getAscent() * 0.25f;
|
||||||
x += padding;
|
x += padding;
|
||||||
w -= 2 * padding;
|
w -= 2 * padding;
|
||||||
String textShow = text.replaceAll("(\r\n\r\n)|(\n)", "<br>");
|
drawTextBoxText(g, text, Math.round(x), Math.round(y), Math.round(w), Math.round(h), hasPTBox);
|
||||||
textShow = FSkin.encodeSymbols(textShow, true);
|
|
||||||
JEditorPane textArea = new JEditorPane("text/html", textShow);
|
|
||||||
textArea.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
|
|
||||||
textArea.setOpaque(false);
|
|
||||||
textArea.setFont(TEXT_FONT);
|
|
||||||
textArea.setSize(Math.round(w), Math.round(h));
|
|
||||||
textArea.print(g.create(Math.round(x), Math.round(y), Math.round(w), Math.round(h)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,4 +436,238 @@ public class FCardImageRenderer {
|
|||||||
x += pieceWidths[i];
|
x += pieceWidths[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static abstract class Piece {
|
||||||
|
protected final boolean isReminder;
|
||||||
|
|
||||||
|
protected Piece(boolean isReminder) {
|
||||||
|
this.isReminder = isReminder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void restart();
|
||||||
|
public abstract int getNextWidth(FontMetrics txMetrics, FontMetrics rmMetrics);
|
||||||
|
public abstract void drawPrev(Graphics2D g, int x, int y, Font txFont, Font rmFont, FontMetrics txMetrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TextPiece extends Piece {
|
||||||
|
private String text;
|
||||||
|
private int index;
|
||||||
|
private List<Integer> boundaryList;
|
||||||
|
|
||||||
|
private void buildBoundaryList() {
|
||||||
|
boundaryList = new ArrayList<>();
|
||||||
|
boundary.setText(text);
|
||||||
|
boundaryList.add(boundary.first());
|
||||||
|
for (int next = boundary.next(); next != BreakIterator.DONE; next = boundary.next()) {
|
||||||
|
boundaryList.add(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextPiece(String text, boolean isReminder) {
|
||||||
|
super(isReminder);
|
||||||
|
this.text = text;
|
||||||
|
buildBoundaryList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restart()
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNextWidth(FontMetrics txMetrics, FontMetrics rmMetrics) {
|
||||||
|
++index;
|
||||||
|
if (index == boundaryList.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
String subtext = text.substring(boundaryList.get(index - 1), boundaryList.get(index));
|
||||||
|
if (isReminder) {
|
||||||
|
return rmMetrics.stringWidth(subtext);
|
||||||
|
}
|
||||||
|
return txMetrics.stringWidth(subtext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPrev(Graphics2D g, int x, int y, Font txFont, Font rmFont, FontMetrics txMetrics) {
|
||||||
|
int ascent = txMetrics.getAscent();
|
||||||
|
String subtext = text.substring(boundaryList.get(index - 1), boundaryList.get(index));
|
||||||
|
if (isReminder) {
|
||||||
|
g.setFont(rmFont);
|
||||||
|
} else {
|
||||||
|
g.setFont(txFont);
|
||||||
|
}
|
||||||
|
g.drawString(subtext, x, y + ascent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SymbolPiece extends Piece {
|
||||||
|
private List<String> symbols;
|
||||||
|
private boolean restarted;
|
||||||
|
|
||||||
|
public SymbolPiece(List<String> symbols) {
|
||||||
|
super(false);
|
||||||
|
this.symbols = symbols;
|
||||||
|
restarted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restart() {
|
||||||
|
restarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNextWidth(FontMetrics txMetrics, FontMetrics rmMetrics) {
|
||||||
|
if (restarted) {
|
||||||
|
int offset = Math.round(txMetrics.getAscent() * 0.8f);
|
||||||
|
restarted = false;
|
||||||
|
return offset * symbols.size();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPrev(Graphics2D g, int x, int y, Font txFont, Font rmFont, FontMetrics txMetrics) {
|
||||||
|
int xoffset = Math.round(txMetrics.getAscent() * 0.8f);
|
||||||
|
int yoffset = txMetrics.getAscent() - xoffset + 1;
|
||||||
|
for (String s : symbols) {
|
||||||
|
CardFaceSymbols.drawSymbol(s, g, x, y + yoffset, xoffset - 1);
|
||||||
|
x += xoffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Paragraph {
|
||||||
|
private String text;
|
||||||
|
private List<Piece> pieces;
|
||||||
|
|
||||||
|
private void parseSymbols(String subtext, boolean isReminder) {
|
||||||
|
List<String> symbols = new ArrayList<>();
|
||||||
|
Matcher sbMatcher = symbolPattern.matcher(subtext);
|
||||||
|
int parsed = 0;
|
||||||
|
while (sbMatcher.find()) {
|
||||||
|
if (sbMatcher.start() > parsed) {
|
||||||
|
if (!symbols.isEmpty()) {
|
||||||
|
pieces.add(new SymbolPiece(symbols));
|
||||||
|
symbols = new ArrayList<>();
|
||||||
|
}
|
||||||
|
pieces.add(new TextPiece(subtext.substring(parsed, sbMatcher.start()), isReminder));
|
||||||
|
}
|
||||||
|
symbols.add(sbMatcher.group(1) != null ? sbMatcher.group(1) : sbMatcher.group(2) + sbMatcher.group(3));
|
||||||
|
parsed = sbMatcher.end();
|
||||||
|
}
|
||||||
|
if (!symbols.isEmpty()) {
|
||||||
|
pieces.add(new SymbolPiece(symbols));
|
||||||
|
}
|
||||||
|
if (parsed < subtext.length())
|
||||||
|
pieces.add(new TextPiece(subtext.substring(parsed, subtext.length()), isReminder));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildPieceList() {
|
||||||
|
pieces = new ArrayList<>();
|
||||||
|
Matcher rmMatcher = reminderPattern.matcher(text);
|
||||||
|
int parsed = 0;
|
||||||
|
while (rmMatcher.find()) {
|
||||||
|
// Non-reminder text
|
||||||
|
if (rmMatcher.start() > parsed) {
|
||||||
|
parseSymbols(text.substring(parsed, rmMatcher.start()), false);
|
||||||
|
}
|
||||||
|
parseSymbols(text.substring(rmMatcher.start(), rmMatcher.end()), true);
|
||||||
|
parsed = rmMatcher.end();
|
||||||
|
}
|
||||||
|
// Remaining text
|
||||||
|
if (parsed < text.length())
|
||||||
|
parseSymbols(text.substring(parsed, text.length()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Paragraph(String text) {
|
||||||
|
this.text = text;
|
||||||
|
buildPieceList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int calculateLines(int width, FontMetrics txMetrics, FontMetrics rmMetrics, boolean hasPTBox) {
|
||||||
|
int pos = 0;
|
||||||
|
int lines = 1;
|
||||||
|
for (Piece p : pieces) {
|
||||||
|
p.restart();
|
||||||
|
int w = p.getNextWidth(txMetrics, rmMetrics);
|
||||||
|
while (w != -1) {
|
||||||
|
if (pos + w > width) {
|
||||||
|
++lines;
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
pos += w;
|
||||||
|
w = p.getNextWidth(txMetrics, rmMetrics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If last line will overlapp with PT box, add one more line.
|
||||||
|
if (hasPTBox && pos >= width - PT_BOX_WIDTH)
|
||||||
|
++lines;
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int drawPieces(Graphics2D g, int x, int y, int width, int lineHeight,
|
||||||
|
Font txFont, FontMetrics txMetrics, Font rmFont, FontMetrics rmMetrics) {
|
||||||
|
int pos = 0;
|
||||||
|
int lines = 1;
|
||||||
|
for (Piece p : pieces) {
|
||||||
|
p.restart();
|
||||||
|
int w = p.getNextWidth(txMetrics, rmMetrics);
|
||||||
|
while (w != -1) {
|
||||||
|
if (pos + w > width) {
|
||||||
|
++lines;
|
||||||
|
pos = 0;
|
||||||
|
y += lineHeight;
|
||||||
|
}
|
||||||
|
p.drawPrev(g, x + pos, y, txFont, rmFont, txMetrics);
|
||||||
|
pos += w;
|
||||||
|
w = p.getNextWidth(txMetrics, rmMetrics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines * lineHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawTextBoxText(Graphics2D g, final String text, int x, int y, int w, int h, boolean hasPTBox) {
|
||||||
|
String [] paragraphs = linebreakPattern.split(text);
|
||||||
|
List<Paragraph> pgList = new ArrayList<>();
|
||||||
|
for (String pg : paragraphs) {
|
||||||
|
pgList.add(new Paragraph(pg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find font size that fit in the text box area
|
||||||
|
Font txFont = TEXT_FONT, rmFont = REMINDER_FONT;
|
||||||
|
FontMetrics txMetrics = TEXT_METRICS, rmMetrics = REMINDER_METRICS;
|
||||||
|
int txFontSize = txFont.getSize(), rmFontSize = rmFont.getSize();
|
||||||
|
int lineHeight, paraSpacing, lineSpacing, totalHeight;
|
||||||
|
do {
|
||||||
|
int totalLineSpacings = 0;
|
||||||
|
totalHeight = 0;
|
||||||
|
paraSpacing = txMetrics.getLeading() + txMetrics.getDescent();
|
||||||
|
lineHeight = txMetrics.getAscent() + txMetrics.getDescent();
|
||||||
|
lineSpacing = -2;
|
||||||
|
for (int i = 0; i < pgList.size(); ++i) {
|
||||||
|
boolean ptBox = (i < pgList.size() - 1) ? false : hasPTBox;
|
||||||
|
Paragraph pg = pgList.get(i);
|
||||||
|
totalHeight += paraSpacing;
|
||||||
|
int lines = pg.calculateLines(w, txMetrics, rmMetrics, ptBox);
|
||||||
|
totalLineSpacings += lines - 1;
|
||||||
|
totalHeight += lines * lineHeight + (lines - 1) * lineSpacing;
|
||||||
|
}
|
||||||
|
while (totalHeight > h && lineSpacing > -txMetrics.getDescent()) {
|
||||||
|
--lineSpacing;
|
||||||
|
totalHeight -= totalLineSpacings;
|
||||||
|
}
|
||||||
|
if (totalHeight <= h)
|
||||||
|
break;
|
||||||
|
//Shrink font and do again
|
||||||
|
--txFontSize;
|
||||||
|
txFont = getShrinkFont(TEXT_FONT, txFontSize);
|
||||||
|
txMetrics = g.getFontMetrics(txFont);
|
||||||
|
--rmFontSize;
|
||||||
|
rmFont = getShrinkFont(REMINDER_FONT, rmFontSize);
|
||||||
|
rmMetrics = g.getFontMetrics(rmFont);
|
||||||
|
} while (txFontSize >= 8 && rmFontSize >= 8);
|
||||||
|
|
||||||
|
// Draw text
|
||||||
|
y += (h - totalHeight - paraSpacing / 2) / 2;
|
||||||
|
for (Paragraph pg : pgList) {
|
||||||
|
y += pg.drawPieces(g, x, y, w, lineSpacing + lineHeight, txFont, txMetrics, rmFont, rmMetrics);
|
||||||
|
y += paraSpacing - lineSpacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user