Made new book builder algorithm work, cleaned up export dialog.
This commit is contained in:
parent
e32976fb8b
commit
605d050783
|
@ -3,6 +3,8 @@ package nl.andrewlalis.blockbookbinder.control.source;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import nl.andrewlalis.blockbookbinder.model.build.BookBuilder;
|
import nl.andrewlalis.blockbookbinder.model.build.BookBuilder;
|
||||||
|
import nl.andrewlalis.blockbookbinder.model.build.BookBuilder2;
|
||||||
|
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
|
||||||
import nl.andrewlalis.blockbookbinder.view.SourceTextPanel;
|
import nl.andrewlalis.blockbookbinder.view.SourceTextPanel;
|
||||||
import nl.andrewlalis.blockbookbinder.view.book.BookPreviewPanel;
|
import nl.andrewlalis.blockbookbinder.view.book.BookPreviewPanel;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package nl.andrewlalis.blockbookbinder.control.source;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import nl.andrewlalis.blockbookbinder.model.build.BookBuilder2;
|
||||||
|
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
|
||||||
|
import nl.andrewlalis.blockbookbinder.view.SourceTextPanel;
|
||||||
|
import nl.andrewlalis.blockbookbinder.view.book.BookPreviewPanel;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
|
||||||
|
public class CompileFromSourceAction2 extends AbstractAction {
|
||||||
|
@Getter
|
||||||
|
private static final CompileFromSourceAction2 instance = new CompileFromSourceAction2();
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private SourceTextPanel sourceTextPanel;
|
||||||
|
@Setter
|
||||||
|
private BookPreviewPanel bookPreviewPanel;
|
||||||
|
|
||||||
|
public CompileFromSourceAction2() {
|
||||||
|
super("Compile From Source 2");
|
||||||
|
this.putValue(SHORT_DESCRIPTION, "Compile the current source text into a book.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
this.bookPreviewPanel.setBook(
|
||||||
|
new BookBuilder2(
|
||||||
|
ApplicationProperties.getIntProp("book.page_max_lines"),
|
||||||
|
ApplicationProperties.getIntProp("book.page_max_chars"),
|
||||||
|
ApplicationProperties.getIntProp("book.page_max_width")
|
||||||
|
).addText(this.sourceTextPanel.getSourceText()).build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,20 @@ public class CharWidthMapper {
|
||||||
this.initCharWidthMap();
|
this.initCharWidthMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWidth(char c) {
|
public static int getWidth(char c) {
|
||||||
return this.charWidthMap.getOrDefault(c, 6);
|
return instance.charWidthMap.getOrDefault(c, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getWidth(String s) {
|
||||||
|
if (s.length() == 0) return 0;
|
||||||
|
int width = 0;
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
width += getWidth(s.charAt(i));
|
||||||
|
if (i < s.length() - 1) {
|
||||||
|
width++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initCharWidthMap() {
|
private void initCharWidthMap() {
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class BookBuilder {
|
||||||
sourceIndex++;
|
sourceIndex++;
|
||||||
symbolBuilder.setLength(0);
|
symbolBuilder.setLength(0);
|
||||||
symbolBuilder.append(c);
|
symbolBuilder.append(c);
|
||||||
int symbolWidth = CharWidthMapper.getInstance().getWidth(c);
|
int symbolWidth = CharWidthMapper.getWidth(c);
|
||||||
|
|
||||||
// Since there's a 1-pixel gap between characters, add it to the width if this isn't the first char.
|
// Since there's a 1-pixel gap between characters, add it to the width if this isn't the first char.
|
||||||
if (lineBuilder.length() > 0) {
|
if (lineBuilder.length() > 0) {
|
||||||
|
@ -86,7 +86,7 @@ public class BookBuilder {
|
||||||
) {
|
) {
|
||||||
char nextChar = sourceChars[sourceIndex];
|
char nextChar = sourceChars[sourceIndex];
|
||||||
symbolBuilder.append(nextChar);
|
symbolBuilder.append(nextChar);
|
||||||
symbolWidth += 1 + CharWidthMapper.getInstance().getWidth(nextChar);
|
symbolWidth += 1 + CharWidthMapper.getWidth(nextChar);
|
||||||
sourceIndex++;
|
sourceIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,10 @@ public class BookBuilder2 {
|
||||||
private final int MAX_CHARS_PER_PAGE;
|
private final int MAX_CHARS_PER_PAGE;
|
||||||
private final int MAX_LINE_PIXEL_WIDTH;
|
private final int MAX_LINE_PIXEL_WIDTH;
|
||||||
|
|
||||||
private List<String> lines;
|
private final List<String> lines;
|
||||||
|
|
||||||
private StringBuilder lineBuilder;
|
private final StringBuilder lineBuilder;
|
||||||
private StringBuilder wordBuilder;
|
private final StringBuilder wordBuilder;
|
||||||
private int currentLine;
|
|
||||||
private int currentLinePixelWidth;
|
|
||||||
private int currentWordPixelWidth;
|
|
||||||
|
|
||||||
public BookBuilder2(int maxLinesPerPage, int maxCharsPerPage, int maxLinePixelWidth) {
|
public BookBuilder2(int maxLinesPerPage, int maxCharsPerPage, int maxLinePixelWidth) {
|
||||||
this.MAX_LINES_PER_PAGE = maxLinesPerPage;
|
this.MAX_LINES_PER_PAGE = maxLinesPerPage;
|
||||||
|
@ -27,9 +24,6 @@ public class BookBuilder2 {
|
||||||
this.lines = new ArrayList<>();
|
this.lines = new ArrayList<>();
|
||||||
this.lineBuilder = new StringBuilder(64);
|
this.lineBuilder = new StringBuilder(64);
|
||||||
this.wordBuilder = new StringBuilder(64);
|
this.wordBuilder = new StringBuilder(64);
|
||||||
this.currentLine = 0;
|
|
||||||
this.currentLinePixelWidth = 0;
|
|
||||||
this.currentWordPixelWidth = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BookBuilder2 addText(String text) {
|
public BookBuilder2 addText(String text) {
|
||||||
|
@ -40,9 +34,37 @@ public class BookBuilder2 {
|
||||||
appendLine();
|
appendLine();
|
||||||
} else if (c == ' ' && lineBuilder.length() == 0) {
|
} else if (c == ' ' && lineBuilder.length() == 0) {
|
||||||
continue; // Skip spaces at the start of lines.
|
continue; // Skip spaces at the start of lines.
|
||||||
|
} else if (Character.isWhitespace(c)) {
|
||||||
|
if (CharWidthMapper.getWidth(lineBuilder.toString() + c) > MAX_LINE_PIXEL_WIDTH) {
|
||||||
|
appendLine();
|
||||||
|
if (c != ' ') {
|
||||||
|
lineBuilder.append(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lineBuilder.append(c);
|
||||||
|
}
|
||||||
} else { // Read a continuous word.
|
} else { // Read a continuous word.
|
||||||
int charsRead = readWord(text, idx - 1);
|
String word = readWord(text, idx - 1);
|
||||||
idx += charsRead - 1;
|
idx += word.length() - 1;
|
||||||
|
if (CharWidthMapper.getWidth(lineBuilder + word) <= MAX_LINE_PIXEL_WIDTH) {
|
||||||
|
// Append the word if it'll fit completely.
|
||||||
|
lineBuilder.append(word);
|
||||||
|
} else if (CharWidthMapper.getWidth(word) <= MAX_LINE_PIXEL_WIDTH) {
|
||||||
|
// Go to the next line and put the word there, since it'll fit.
|
||||||
|
appendLine();
|
||||||
|
lineBuilder.append(word);
|
||||||
|
} else {
|
||||||
|
// The word is so large that it doesn't fit on a line on its own.
|
||||||
|
// Find the largest substring of the word that'll fit with a hyphen.
|
||||||
|
int subStringSize = word.length() - 2;
|
||||||
|
while (CharWidthMapper.getWidth(word.substring(0, subStringSize) + "-") > MAX_LINE_PIXEL_WIDTH) {
|
||||||
|
subStringSize--;
|
||||||
|
}
|
||||||
|
appendLine();
|
||||||
|
lineBuilder.append(word, 0, subStringSize).append('-');
|
||||||
|
appendLine();
|
||||||
|
lineBuilder.append(word.substring(subStringSize));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -52,14 +74,28 @@ public class BookBuilder2 {
|
||||||
Book book = new Book();
|
Book book = new Book();
|
||||||
BookPage page = new BookPage();
|
BookPage page = new BookPage();
|
||||||
int currentPageLineCount = 0;
|
int currentPageLineCount = 0;
|
||||||
|
int currentPageCharCount = 0;
|
||||||
|
|
||||||
|
// Flush anything remaining in lineBuilder to a final line.
|
||||||
|
if (lineBuilder.length() > 0) {
|
||||||
|
appendLine();
|
||||||
|
}
|
||||||
|
|
||||||
for (String line : lines) {
|
for (String line : lines) {
|
||||||
|
if (currentPageCharCount + line.length() > MAX_CHARS_PER_PAGE) {
|
||||||
|
book.addPage(page);
|
||||||
|
page = new BookPage();
|
||||||
|
currentPageLineCount = 0;
|
||||||
|
currentPageCharCount = 0;
|
||||||
|
}
|
||||||
page.addLine(line);
|
page.addLine(line);
|
||||||
currentPageLineCount++;
|
currentPageLineCount++;
|
||||||
|
currentPageCharCount += line.length();
|
||||||
if (currentPageLineCount == MAX_LINES_PER_PAGE) {
|
if (currentPageLineCount == MAX_LINES_PER_PAGE) {
|
||||||
book.addPage(page);
|
book.addPage(page);
|
||||||
page = new BookPage();
|
page = new BookPage();
|
||||||
currentPageLineCount = 0;
|
currentPageLineCount = 0;
|
||||||
|
currentPageCharCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (page.hasContent()) {
|
if (page.hasContent()) {
|
||||||
|
@ -68,32 +104,22 @@ public class BookBuilder2 {
|
||||||
return book;
|
return book;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readWord(String text, int firstCharIdx) {
|
private String readWord(String text, int firstCharIdx) {
|
||||||
currentWordPixelWidth = 0;
|
|
||||||
wordBuilder.setLength(0);
|
wordBuilder.setLength(0);
|
||||||
int idx = firstCharIdx;
|
int idx = firstCharIdx;
|
||||||
while (idx < text.length()) {
|
while (idx < text.length()) {
|
||||||
char c = text.charAt(idx++);
|
char c = text.charAt(idx++);
|
||||||
if (!Character.isWhitespace(c)) {
|
if (!Character.isWhitespace(c)) {
|
||||||
currentWordPixelWidth += CharWidthMapper.getInstance().getWidth(c) + 1;
|
|
||||||
wordBuilder.append(c);
|
wordBuilder.append(c);
|
||||||
|
|
||||||
// If we notice that our word will cause the current line to exceed max width, go to a newline.
|
|
||||||
if (currentLinePixelWidth + currentWordPixelWidth > MAX_LINE_PIXEL_WIDTH) {
|
|
||||||
appendLine();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String word = wordBuilder.toString();
|
return wordBuilder.toString();
|
||||||
return word.length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendLine() {
|
private void appendLine() {
|
||||||
this.lines.add(this.lineBuilder.toString());
|
this.lines.add(this.lineBuilder.toString());
|
||||||
this.lineBuilder.setLength(0);
|
this.lineBuilder.setLength(0);
|
||||||
this.currentLine++;
|
|
||||||
this.currentLinePixelWidth = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import nl.andrewlalis.blockbookbinder.BlockBookBinder;
|
||||||
import nl.andrewlalis.blockbookbinder.control.export.ExportBookToMinecraftAction;
|
import nl.andrewlalis.blockbookbinder.control.export.ExportBookToMinecraftAction;
|
||||||
import nl.andrewlalis.blockbookbinder.control.source.CleanSourceAction;
|
import nl.andrewlalis.blockbookbinder.control.source.CleanSourceAction;
|
||||||
import nl.andrewlalis.blockbookbinder.control.source.CompileFromSourceAction;
|
import nl.andrewlalis.blockbookbinder.control.source.CompileFromSourceAction;
|
||||||
|
import nl.andrewlalis.blockbookbinder.control.source.CompileFromSourceAction2;
|
||||||
import nl.andrewlalis.blockbookbinder.control.source.ImportSourceAction;
|
import nl.andrewlalis.blockbookbinder.control.source.ImportSourceAction;
|
||||||
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
|
import nl.andrewlalis.blockbookbinder.util.ApplicationProperties;
|
||||||
import nl.andrewlalis.blockbookbinder.view.about.AboutDialog;
|
import nl.andrewlalis.blockbookbinder.view.about.AboutDialog;
|
||||||
|
@ -44,11 +45,13 @@ public class MainFrame extends JFrame {
|
||||||
BookPreviewPanel bookPreviewPanel = new BookPreviewPanel();
|
BookPreviewPanel bookPreviewPanel = new BookPreviewPanel();
|
||||||
doublePanel.add(bookPreviewPanel);
|
doublePanel.add(bookPreviewPanel);
|
||||||
CompileFromSourceAction.getInstance().setBookPreviewPanel(bookPreviewPanel);
|
CompileFromSourceAction.getInstance().setBookPreviewPanel(bookPreviewPanel);
|
||||||
|
CompileFromSourceAction2.getInstance().setBookPreviewPanel(bookPreviewPanel);
|
||||||
ExportBookToMinecraftAction.getInstance().setBookPreviewPanel(bookPreviewPanel);
|
ExportBookToMinecraftAction.getInstance().setBookPreviewPanel(bookPreviewPanel);
|
||||||
|
|
||||||
SourceTextPanel sourceTextPanel = new SourceTextPanel();
|
SourceTextPanel sourceTextPanel = new SourceTextPanel();
|
||||||
doublePanel.add(sourceTextPanel);
|
doublePanel.add(sourceTextPanel);
|
||||||
CompileFromSourceAction.getInstance().setSourceTextPanel(sourceTextPanel);
|
CompileFromSourceAction.getInstance().setSourceTextPanel(sourceTextPanel);
|
||||||
|
CompileFromSourceAction2.getInstance().setSourceTextPanel(sourceTextPanel);
|
||||||
CleanSourceAction.getInstance().setSourceTextPanel(sourceTextPanel);
|
CleanSourceAction.getInstance().setSourceTextPanel(sourceTextPanel);
|
||||||
|
|
||||||
mainPanel.add(doublePanel, BorderLayout.CENTER);
|
mainPanel.add(doublePanel, BorderLayout.CENTER);
|
||||||
|
@ -68,6 +71,7 @@ public class MainFrame extends JFrame {
|
||||||
|
|
||||||
JMenu bookMenu = new JMenu("Book");
|
JMenu bookMenu = new JMenu("Book");
|
||||||
bookMenu.add(CompileFromSourceAction.getInstance());
|
bookMenu.add(CompileFromSourceAction.getInstance());
|
||||||
|
bookMenu.add(CompileFromSourceAction2.getInstance());
|
||||||
bookMenu.add(CleanSourceAction.getInstance());
|
bookMenu.add(CleanSourceAction.getInstance());
|
||||||
bookMenu.add(ExportBookToMinecraftAction.getInstance());
|
bookMenu.add(ExportBookToMinecraftAction.getInstance());
|
||||||
menuBar.add(bookMenu);
|
menuBar.add(bookMenu);
|
||||||
|
|
|
@ -51,25 +51,32 @@ public class ExportToBookDialog extends JDialog {
|
||||||
private Container buildContentPane() {
|
private Container buildContentPane() {
|
||||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
JPanel setupPanel = new JPanel();
|
JPanel setupPanel = new JPanel(new GridBagLayout());
|
||||||
setupPanel.setLayout(new BoxLayout(setupPanel, BoxLayout.PAGE_AXIS));
|
String[] labels = {"", "First Page", "Last Page", "Auto-Paste Delay (Seconds)"};
|
||||||
this.autoCheckbox = new JCheckBox("Auto-paste", true);
|
this.autoCheckbox = new JCheckBox("Auto-paste", true);
|
||||||
this.firstPageSpinner = new JSpinner(new SpinnerNumberModel(1, 1, this.book.getPageCount(), 1));
|
this.firstPageSpinner = new JSpinner(new SpinnerNumberModel(1, 1, this.book.getPageCount(), 1));
|
||||||
JPanel firstPageSpinnerPanel = new JPanel(new BorderLayout());
|
|
||||||
firstPageSpinnerPanel.add(new JLabel("First Page:"), BorderLayout.WEST);
|
|
||||||
firstPageSpinnerPanel.add(this.firstPageSpinner, BorderLayout.CENTER);
|
|
||||||
this.lastPageSpinner = new JSpinner(new SpinnerNumberModel(this.book.getPageCount(), 1, this.book.getPageCount(), 1));
|
this.lastPageSpinner = new JSpinner(new SpinnerNumberModel(this.book.getPageCount(), 1, this.book.getPageCount(), 1));
|
||||||
JPanel lastPageSpinnerPanel = new JPanel(new BorderLayout());
|
|
||||||
lastPageSpinnerPanel.add(new JLabel("Last Page:"), BorderLayout.WEST);
|
|
||||||
lastPageSpinnerPanel.add(this.lastPageSpinner, BorderLayout.CENTER);
|
|
||||||
this.autoPasteDelaySpinner = new JSpinner(new SpinnerNumberModel(0.2, 0.1, 5.0, 0.1));
|
this.autoPasteDelaySpinner = new JSpinner(new SpinnerNumberModel(0.2, 0.1, 5.0, 0.1));
|
||||||
JPanel autoPasteDelaySpinnerPanel = new JPanel(new BorderLayout());
|
|
||||||
autoPasteDelaySpinnerPanel.add(new JLabel("Auto-Paste Delay (s):"), BorderLayout.WEST);
|
JComponent[] fields = {autoCheckbox, firstPageSpinner, lastPageSpinner, autoPasteDelaySpinner};
|
||||||
autoPasteDelaySpinnerPanel.add(this.autoPasteDelaySpinner, BorderLayout.CENTER);
|
GridBagConstraints c = new GridBagConstraints();
|
||||||
setupPanel.add(this.autoCheckbox);
|
c.gridx = 0;
|
||||||
setupPanel.add(firstPageSpinnerPanel);
|
c.gridy = 0;
|
||||||
setupPanel.add(lastPageSpinnerPanel);
|
c.anchor = GridBagConstraints.LINE_START;
|
||||||
setupPanel.add(autoPasteDelaySpinnerPanel);
|
c.weightx = 0.5;
|
||||||
|
c.fill = GridBagConstraints.NONE;
|
||||||
|
c.insets = new Insets(5, 5, 5, 5);
|
||||||
|
for (String label : labels) {
|
||||||
|
setupPanel.add(new JLabel(label), c);
|
||||||
|
c.gridy++;
|
||||||
|
}
|
||||||
|
c.gridx = 1;
|
||||||
|
c.gridy = 0;
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
for (JComponent field : fields) {
|
||||||
|
setupPanel.add(field, c);
|
||||||
|
c.gridy++;
|
||||||
|
}
|
||||||
|
|
||||||
this.exportStatusPanel = new ExportStatusPanel();
|
this.exportStatusPanel = new ExportStatusPanel();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
version=1.2.0
|
version=1.3.0
|
||||||
|
|
||||||
# Settings for the application's GUI.
|
# Settings for the application's GUI.
|
||||||
frame.title=Block Book Binder
|
frame.title=Block Book Binder
|
||||||
|
@ -19,5 +19,5 @@ about_dialog.source=html/about.html
|
||||||
book.max_pages=100
|
book.max_pages=100
|
||||||
book.page_max_lines=14
|
book.page_max_lines=14
|
||||||
book.page_max_width=113
|
book.page_max_width=113
|
||||||
book.page_max_chars=255
|
book.page_max_chars=700
|
||||||
book.default_char_width=5
|
book.default_char_width=5
|
||||||
|
|
Loading…
Reference in New Issue