diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 9de132a..dbd97aa 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -465,7 +465,7 @@ org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_if_e org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_if_empty org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false -org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=true +org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line=one_line_never org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line=one_line_never diff --git a/.vscode/eclipse-format.xml b/.vscode/eclipse-format.xml index b5a0d6a..8a90945 100644 --- a/.vscode/eclipse-format.xml +++ b/.vscode/eclipse-format.xml @@ -198,7 +198,7 @@ - + diff --git a/app.properties b/app.properties index f9fe5e1..973b85d 100644 --- a/app.properties +++ b/app.properties @@ -1 +1 @@ -version=0.9.1 +version=0.9.2 diff --git a/src/main/java/app/Environment.java b/src/main/java/app/Environment.java index 21a998b..f7a6856 100644 --- a/src/main/java/app/Environment.java +++ b/src/main/java/app/Environment.java @@ -94,10 +94,14 @@ private static enum OSFamily private static String gitBuildTag; public static boolean isDeluxe() - { return isDeluxe; } + { + return isDeluxe; + } public static String getVersionString() - { return versionString; } + { + return versionString; + } public static String decorateTitle(String title) { @@ -239,7 +243,9 @@ public static void exit(int status) } public static boolean isCommandLine() - { return commandLine; } + { + return commandLine; + } public static File getWorkingDirectory() { @@ -250,10 +256,14 @@ public static File getWorkingDirectory() } public static File getProjectDirectory() - { return projectDirectory; } + { + return projectDirectory; + } public static File getSourceDirectory() - { return new File(projectDirectory, "/src/"); } + { + return new File(projectDirectory, "/src/"); + } public static File getProjectFile(String relativePath) { @@ -277,11 +287,11 @@ public static void checkForUpdate() if (!latestVersion.equals("v" + versionString)) { Logger.log("Detected newer remote version: " + latestVersion); - SwingUtils.showFramedMessageDialog(null, - "A newer version is available!\n" + - "Please visit the GitHub repo to download it.", - "Update Available", - JOptionPane.WARNING_MESSAGE); + + SwingUtils.getWarningDialog() + .setTitle("Update Available") + .setMessage("A newer version is available!", "Please visit the GitHub repo to download it.") + .show(); } } else { @@ -299,12 +309,13 @@ private static final void checkForDependencies() throws IOException File db = Directories.DATABASE.toFile(); if (!db.exists() || !db.isDirectory()) { - SwingUtils.showFramedMessageDialog(null, - "Could not find required directory: " + db.getName() + System.lineSeparator() + - "It should be in the same directory as StarRod.jar" + System.lineSeparator() + - "Did you extract ALL the files for Star Rod?", - "Missing Directory", - JOptionPane.ERROR_MESSAGE); + SwingUtils.getMessageDialog() + .setTitle("Missing Directory") + .setMessage("Could not find required directory: " + db.getName(), + "It should be in the same directory as the jar.") + .setMessageType(JOptionPane.ERROR_MESSAGE) + .show(); + exit(); } } @@ -315,21 +326,23 @@ private static final File readMainConfig() throws IOException // we may need to create a new config file here if (!configFile.exists()) { - int choice = SwingUtils.showFramedConfirmDialog(null, - String.format("Could not find Star Rod config! %nCreate a new one?"), - "Missing Config", - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE); + int choice = SwingUtils.getConfirmDialog() + .setTitle("Missing Config") + .setMessage("Could not find Star Rod config!", "Create a new one?") + .setMessageType(JOptionPane.QUESTION_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_OPTION) + .choose(); if (choice != JOptionPane.OK_OPTION) exit(); mainConfig = makeConfig(configFile, Scope.Main); - SwingUtils.showFramedMessageDialog(null, - "Select your project directory.", - "Select Project Directory", - JOptionPane.PLAIN_MESSAGE); + SwingUtils.getMessageDialog() + .setTitle("Select Project Directory") + .setMessage("Select your project directory.") + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .show(); return promptSelectProject(); } @@ -353,10 +366,10 @@ private static final File readMainConfig() throws IOException } // project directory is missing, prompt to select new one - SwingUtils.showFramedMessageDialog(null, - String.format("Could not find project directory! %nPlease select a new one."), - "Missing Project Directory", - JOptionPane.ERROR_MESSAGE); + SwingUtils.getErrorDialog() + .setTitle("Missing Project Directory") + .setMessage("Could not find project directory!", "Please select a new one.") + .show(); return promptSelectProject(); } @@ -384,7 +397,10 @@ private static void showErrorMessage(String title, String fmt, Object ... args) if (isCommandLine()) Logger.logError(message); else - SwingUtils.showFramedMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE); + SwingUtils.getErrorDialog() + .setTitle(title) + .setMessage(message) + .show(); } public static boolean loadProject(File projectDir) throws IOException @@ -475,11 +491,13 @@ private static void readProjectConfig() throws IOException File configFile = new File(projectDirectory, FN_PROJ_CONFIG); if (!configFile.exists()) { - int choice = SwingUtils.showFramedConfirmDialog(null, - "Could not find project config!\nCreate a new one?", - "Missing Config", - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE); + + int choice = SwingUtils.getConfirmDialog() + .setTitle("Missing Config") + .setMessage("Could not find project config!", "Create a new one?") + .setMessageType(JOptionPane.QUESTION_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_OPTION) + .choose(); if (choice != JOptionPane.OK_OPTION) exit(); @@ -545,13 +563,19 @@ private static List getAssetDirs(File directory, File splatFile) throws IO } public static boolean isWindows() - { return osFamily == OSFamily.Windows; } + { + return osFamily == OSFamily.Windows; + } public static boolean isMacOS() - { return osFamily == OSFamily.Mac; } + { + return osFamily == OSFamily.Mac; + } public static boolean isLinux() - { return osFamily == OSFamily.Linux; } + { + return osFamily == OSFamily.Linux; + } public static void reloadIcons() { @@ -562,10 +586,14 @@ public static void reloadIcons() } public static final Image getDefaultIconImage() - { return (ICON_DEFAULT == null) ? null : ICON_DEFAULT.getImage(); } + { + return (ICON_DEFAULT == null) ? null : ICON_DEFAULT.getImage(); + } public static final Image getErrorIconImage() - { return (ICON_DEFAULT == null) ? null : ICON_DEFAULT.getImage(); } + { + return (ICON_DEFAULT == null) ? null : ICON_DEFAULT.getImage(); + } private static ImageIcon loadIconAsset(ExpectedAsset asset) { diff --git a/src/main/java/app/RomValidator.java b/src/main/java/app/RomValidator.java index f60f1e5..4be15c9 100644 --- a/src/main/java/app/RomValidator.java +++ b/src/main/java/app/RomValidator.java @@ -39,10 +39,12 @@ public class RomValidator public static File validateROM(File f) throws IOException { if (f.length() != LENGTH) { - SwingUtils.showFramedMessageDialog(null, - "Selected file is not the correct size.", - "ROM Validation Error", - JOptionPane.ERROR_MESSAGE); + SwingUtils.getMessageDialog() + .setTitle("ROM Validation Error") + .setMessage("Selected file is not the correct size.") + .setMessageType(JOptionPane.ERROR_MESSAGE) + .show(); + return null; } @@ -76,10 +78,11 @@ public static File validateROM(File f) throws IOException if (v64 || n64 || x64) { // just need to byteswap - SwingUtils.showFramedMessageDialog(null, - "Selected ROM has incorrect byte order.\nA corrected copy will be made.", - "ROM Validation Warning", - JOptionPane.WARNING_MESSAGE); + SwingUtils.getMessageDialog() + .setTitle("ROM Validation Warning") + .setMessage("Selected ROM has incorrect byte order.", "A corrected copy will be made.") + .setMessageType(JOptionPane.WARNING_MESSAGE) + .show(); pleaseWait.setVisible(true); @@ -114,10 +117,13 @@ else if (x64) } else { pleaseWait.setVisible(false); - SwingUtils.showFramedMessageDialog(null, - "Incorrect ROM or version, CRC does not match.", - "ROM Validation Failure", - JOptionPane.ERROR_MESSAGE); + + SwingUtils.getMessageDialog() + .setTitle("ROM Validation Failure") + .setMessage("Incorrect ROM or version, CRC does not match.") + .setMessageType(JOptionPane.ERROR_MESSAGE) + .show(); + raf.close(); return null; } @@ -129,19 +135,25 @@ else if (x64) // now compute the checksum if (!verifyCRCs(raf)) { pleaseWait.setVisible(false); - SwingUtils.showFramedMessageDialog(null, - "ROM data does not match CRC values!", - "ROM Validation Failure", - JOptionPane.ERROR_MESSAGE); + + SwingUtils.getMessageDialog() + .setTitle("ROM Validation Failure") + .setMessage("ROM data does not match CRC values!") + .setMessageType(JOptionPane.ERROR_MESSAGE) + .show(); + return null; } } else { pleaseWait.setVisible(false); - SwingUtils.showFramedMessageDialog(null, - "Incorrect ROM or version, CRC does not match.", - "ROM Validation Failure", - JOptionPane.ERROR_MESSAGE); + + SwingUtils.getMessageDialog() + .setTitle("ROM Validation Failure") + .setMessage("Incorrect ROM or version, CRC does not match.") + .setMessageType(JOptionPane.ERROR_MESSAGE) + .show(); + raf.close(); return null; } @@ -162,18 +174,22 @@ else if (x64) String fileMD5 = sb.toString(); if (!fileMD5.equals(MD5)) { pleaseWait.setVisible(false); - SwingUtils.showFramedMessageDialog(null, - "MD5 hash does not match!", - "ROM Validation Failure", - JOptionPane.ERROR_MESSAGE); + + SwingUtils.getMessageDialog() + .setTitle("ROM Validation Failure") + .setMessage("MD5 hash does not match!") + .setMessageType(JOptionPane.ERROR_MESSAGE) + .show(); + return null; } } catch (NoSuchAlgorithmException e) { - SwingUtils.showFramedMessageDialog(null, - "Missing MD5 hash algorithm, could not complete validation!", - "ROM Validation Warning", - JOptionPane.WARNING_MESSAGE); + SwingUtils.getMessageDialog() + .setTitle("ROM Validation Warning") + .setMessage("Missing MD5 hash algorithm, could not complete validation!") + .setMessageType(JOptionPane.WARNING_MESSAGE) + .show(); } pleaseWait.setVisible(false); diff --git a/src/main/java/app/StackTraceDialog.java b/src/main/java/app/StackTraceDialog.java index d0ccb94..2824dc0 100644 --- a/src/main/java/app/StackTraceDialog.java +++ b/src/main/java/app/StackTraceDialog.java @@ -146,21 +146,19 @@ public void propertyChange(PropertyChangeEvent e) JOptionPane.UNINITIALIZED_VALUE); if (value.equals(OPT_DETAILS)) { - String[] options = { "OK", "Copy to Clipboard" }; - JScrollPane detailScrollPane = new JScrollPane(textArea); detailScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - int selection = SwingUtils.showFramedOptionDialog(null, - detailScrollPane, - "Exception Details", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.ERROR_MESSAGE, - Environment.ICON_ERROR, - options, - options[0]); + int choice = SwingUtils.getOptionDialog() + .setTitle("Exception Details") + .setMessage(detailScrollPane) + .setMessageType(JOptionPane.ERROR_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .setIcon(Environment.ICON_ERROR) + .setOptions("OK", "Copy to Clipboard") + .choose(); - if (selection == 1) { + if (choice == 1) { StringSelection stringSelection = new StringSelection(textArea.getText()); Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); cb.setContents(stringSelection, null); diff --git a/src/main/java/app/StarRodMain.java b/src/main/java/app/StarRodMain.java index 99b7104..4dd72f3 100644 --- a/src/main/java/app/StarRodMain.java +++ b/src/main/java/app/StarRodMain.java @@ -247,9 +247,12 @@ public void windowClosing(WindowEvent e) int choice = JOptionPane.OK_OPTION; if (taskRunning) - choice = SwingUtils.showFramedConfirmDialog(null, String.format( - "A task is still running. %nAre you sure you want to exit?"), - "Task Still Running", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + choice = SwingUtils.getConfirmDialog() + .setTitle("Task Still Running") + .setMessage("A task is still running.", "Are you sure you want to exit?") + .setMessageType(JOptionPane.WARNING_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_OPTION) + .choose(); if (choice == JOptionPane.OK_OPTION) { dispose(); @@ -387,32 +390,34 @@ private void action_extractMapData() { new EditorWorker(() -> { if (!Environment.projectConfig.getBoolean(Options.ExtractedMapData)) { - int result = SwingUtils.showFramedConfirmDialog(null, - "This action will modify the source files of almost every map.\n" - + "Consider creating a backup or committing any changes before proceeding.\n" - + "Are you ready to begin extracting?", - "Extraction Warning", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.WARNING_MESSAGE); - - if (result == JOptionPane.YES_OPTION) { + int choice = SwingUtils.getConfirmDialog() + .setTitle("Extraction Warning") + .setMessage("This action will modify the source files of almost every map.", + "Consider creating a backup or committing any changes before proceeding.", + "Are you ready to begin extracting?") + .setMessageType(JOptionPane.WARNING_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .choose(); + + if (choice == JOptionPane.YES_OPTION) { Logger.log("Extracting map data...", Priority.MILESTONE); Extractor.extractAll(); - SwingUtils.showFramedMessageDialog(null, - "Complete!", - "All Data Extracted", - JOptionPane.PLAIN_MESSAGE); + SwingUtils.getMessageDialog() + .setTitle("All Data Extracted") + .setMessage("Complete!") + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .show(); Environment.projectConfig.setBoolean(Options.ExtractedMapData, true); Environment.projectConfig.saveConfigFile(); } } else { - SwingUtils.showFramedMessageDialog(null, - "Map data has already been extracted for this project.", - "Data Already Extracted", - JOptionPane.WARNING_MESSAGE); + SwingUtils.getWarningDialog() + .setTitle("Data Already Extracted") + .setMessage("Map data has already been extracted for this project.") + .show(); } }); } diff --git a/src/main/java/app/SwingUtils.java b/src/main/java/app/SwingUtils.java index 121d0ac..4f79e3c 100644 --- a/src/main/java/app/SwingUtils.java +++ b/src/main/java/app/SwingUtils.java @@ -18,7 +18,6 @@ import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; -import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; @@ -75,141 +74,231 @@ private static final JFrame createDialogFrame(Component parentComponent, String return dialogFrame; } - public static final int showFramedOpenDialog(JFileChooser chooser, Component parentComponent) + public static class OpenDialogCounter { - JFrame dialogFrame = createDialogFrame(parentComponent, chooser.getDialogTitle()); - int choice = chooser.showOpenDialog(dialogFrame); - dialogFrame.dispose(); - return choice; + private int count; + + public OpenDialogCounter() + { + count = 0; + } + + public void increment() + { + count++; + } + + public void decrement() + { + count--; + } + + public void reset() + { + count = 0; + } + + public boolean isZero() + { + return count == 0; + } } - public static final int showFramedSaveDialog(JFileChooser chooser, Component parentComponent) + private static enum DialogType { - JFrame dialogFrame = createDialogFrame(parentComponent, chooser.getDialogTitle()); - int choice = chooser.showSaveDialog(dialogFrame); - dialogFrame.dispose(); - return choice; + MESSAGE, + CONFIRM, + INPUT, + OPTION, + WARNING, + ERROR } - public static final void showFramedMessageDialog( - Component parentComponent, - Object message, - String title, - int messageType, - Icon icon) + public static final DialogBuilder getMessageDialog() { - JFrame dialogFrame = createDialogFrame(parentComponent, title); - JOptionPane.showMessageDialog(dialogFrame, message, title, messageType, icon); - dialogFrame.dispose(); + return new DialogBuilder(DialogType.MESSAGE); } - public static final void showFramedMessageDialog( - Component parentComponent, - Object message, - String title, - int messageType) + public static final DialogBuilder getConfirmDialog() { - JFrame dialogFrame = createDialogFrame(parentComponent, title); - JOptionPane.showMessageDialog(dialogFrame, message, title, messageType); - dialogFrame.dispose(); + return new DialogBuilder(DialogType.CONFIRM); } - public static final void showFramedErrorMessage( - Component parentComponent, - Object message, - String title) + public static final DialogBuilder getInputDialog() { - showFramedMessageDialog(parentComponent, message, - title, JOptionPane.ERROR_MESSAGE, Environment.ICON_ERROR); + return new DialogBuilder(DialogType.INPUT); } - /* - public static final void showFramedMessageDialog( - Component parentComponent, - Object message, - String title) + public static final DialogBuilder getOptionDialog() { - JFrame dialogFrame = createDiaglogFrame(parentComponent, title); - JOptionPane.showMessageDialog(dialogFrame, message); - dialogFrame.dispose(); + return new DialogBuilder(DialogType.OPTION); } - */ - public static final int showFramedOptionDialog( - Component parentComponent, - Object message, - String title, - int optionType, - int messageType, - Object[] options, - Object initialValue) - { - JFrame dialogFrame = createDialogFrame(parentComponent, title); - int choice = JOptionPane.showOptionDialog( - dialogFrame, message, title, - optionType, messageType, null, - options, initialValue); - dialogFrame.dispose(); - return choice; - } - - public static final int showFramedOptionDialog( - Component parentComponent, - Object message, - String title, - int optionType, - int messageType, - Icon icon, - Object[] options, - Object initialValue) - { - JFrame dialogFrame = createDialogFrame(parentComponent, title); - int choice = JOptionPane.showOptionDialog( - dialogFrame, message, title, - optionType, messageType, icon, - options, initialValue); - dialogFrame.dispose(); - return choice; - } - - public static final int showFramedConfirmDialog( - Component parentComponent, - Object message, - String title, - int optionType, - int messageType) - { - JFrame dialogFrame = createDialogFrame(parentComponent, title); - int choice = JOptionPane.showConfirmDialog( - dialogFrame, message, title, - optionType, messageType); - dialogFrame.dispose(); - return choice; - } - - public static final int showFramedConfirmDialog( - Component parentComponent, - Object message, - String title, - int optionType) - { - JFrame dialogFrame = createDialogFrame(parentComponent, title); - int choice = JOptionPane.showConfirmDialog( - dialogFrame, message, title, optionType); - dialogFrame.dispose(); - return choice; - } - - public static final String showFramedInputDialog( - Component parentComponent, - Object message, - String title, - int messageType) - { - JFrame dialogFrame = createDialogFrame(parentComponent, title); - String reply = JOptionPane.showInputDialog(dialogFrame, message, title, messageType); - dialogFrame.dispose(); - return reply; + public static final DialogBuilder getWarningDialog() + { + return new DialogBuilder(DialogType.WARNING); + } + + public static final DialogBuilder getErrorDialog() + { + return new DialogBuilder(DialogType.ERROR); + } + + public static class DialogBuilder + { + private final DialogType type; + private String title = "TITLE MISSING"; + private Object message = "MESSAGE MISSING"; + private int optionType; + private int messageType; + private Icon icon; + private Object[] options = null; + private Object initialValue = null; + private Component parentComponent = null; + private OpenDialogCounter counter = null; + + private DialogBuilder(DialogType type) + { + this.type = type; + + // set defaults + switch (type) { + case MESSAGE: + optionType = JOptionPane.DEFAULT_OPTION; + messageType = JOptionPane.INFORMATION_MESSAGE; + break; + case CONFIRM: + optionType = JOptionPane.YES_NO_CANCEL_OPTION; + messageType = JOptionPane.QUESTION_MESSAGE; + break; + case INPUT: + break; + case OPTION: + break; + case WARNING: + messageType = JOptionPane.WARNING_MESSAGE; + break; + case ERROR: + messageType = JOptionPane.ERROR_MESSAGE; + icon = Environment.ICON_ERROR; + break; + } + } + + public DialogBuilder setTitle(String title) + { + this.title = title; + return this; + } + + public DialogBuilder setMessage(Object message) + { + this.message = message; + return this; + } + + public DialogBuilder setMessage(String ... lines) + { + this.message = String.join(System.lineSeparator(), lines); + return this; + } + + public DialogBuilder setMessageType(int messageType) + { + this.messageType = messageType; + return this; + } + + public DialogBuilder setOptionsType(int optionType) + { + this.optionType = optionType; + return this; + } + + public DialogBuilder setIcon(Icon icon) + { + this.icon = icon; + return this; + } + + public DialogBuilder setOptions(String ... options) + { + this.options = options; + return this; + } + + public DialogBuilder setDefault(Object initialValue) + { + this.initialValue = initialValue; + return this; + } + + public DialogBuilder setParent(Component parentComponent) + { + this.parentComponent = parentComponent; + return this; + } + + public DialogBuilder setCounter(OpenDialogCounter counter) + { + this.counter = counter; + return this; + } + + public void show() + { + choose(); + } + + public void showLater() + { + if (SwingUtilities.isEventDispatchThread()) { + choose(); + } + else { + SwingUtilities.invokeLater(() -> { + choose(); + }); + } + } + + public String prompt() + { + if (counter != null) + counter.increment(); + + JFrame dialogFrame = createDialogFrame(parentComponent, title); + + Object result = JOptionPane.showInputDialog(parentComponent, + message, title, messageType, + icon, options, initialValue); + + dialogFrame.dispose(); + + if (counter != null) + counter.decrement(); + + return (String) result; + } + + public int choose() + { + if (counter != null) + counter.increment(); + + JFrame dialogFrame = createDialogFrame(parentComponent, title); + + int result = JOptionPane.showOptionDialog(parentComponent, + message, title, optionType, messageType, + icon, options, initialValue); + + dialogFrame.dispose(); + + if (counter != null) + counter.decrement(); + + return result; + } } public static final void showDialog(JDialog dialog, String title) @@ -471,10 +560,14 @@ public static JLabel getLabelWithTooltip(String text, int alignment, String tool } public static Color getTextColor() - { return UIManager.getColor("Label.foreground"); } + { + return UIManager.getColor("Label.foreground"); + } private static Color getBackgoundColor() - { return UIManager.getColor("Label.background"); } + { + return UIManager.getColor("Label.background"); + } private static int getBackgroundLuminance() { diff --git a/src/main/java/app/ThemesEditor.java b/src/main/java/app/ThemesEditor.java index f4a9755..75b5c67 100644 --- a/src/main/java/app/ThemesEditor.java +++ b/src/main/java/app/ThemesEditor.java @@ -75,18 +75,21 @@ public void windowClosing(WindowEvent e) exitToMainMenu = true; String currentThemeName = Themes.getCurrentThemeName(); if (!initialThemeName.equals(currentThemeName)) { - int choice = SwingUtils.showFramedConfirmDialog(null, - String.format("Theme has been changed.%nDo you want to save changes?"), - "Save Changes", JOptionPane.YES_NO_CANCEL_OPTION); + int choice = SwingUtils.getConfirmDialog() + .setTitle("Save Changes") + .setMessage("Theme has been changed.", "Do you want to save changes?") + .choose(); switch (choice) { case JOptionPane.YES_OPTION: Environment.mainConfig.setString(Options.Theme, Themes.getCurrentThemeKey()); Environment.mainConfig.saveConfigFile(); - SwingUtils.showFramedMessageDialog(null, - String.format("Theme has been changed. %nStar Rod must restart."), - "Theme Changed", JOptionPane.WARNING_MESSAGE); + SwingUtils.getWarningDialog() + .setTitle("Theme Changed") + .setMessage("Theme has been changed.", "Star Rod must restart.") + .show(); + Environment.exit(); break; case JOptionPane.NO_OPTION: diff --git a/src/main/java/app/config/Config.java b/src/main/java/app/config/Config.java index 2f52320..08e6132 100644 --- a/src/main/java/app/config/Config.java +++ b/src/main/java/app/config/Config.java @@ -8,8 +8,6 @@ import java.util.List; import java.util.Map.Entry; -import javax.swing.JOptionPane; - import app.SwingUtils; import app.config.Options.Scope; import app.config.Options.Type; @@ -31,7 +29,9 @@ public Config(File cfg, Scope ... allowedScopes) } public File getFile() - { return file; } + { + return file; + } public void readConfig() throws IOException { @@ -100,10 +100,10 @@ public void saveConfigFile() pw.close(); } catch (FileNotFoundException e) { - SwingUtils.showFramedMessageDialog(null, - "Could not update config: " + file.getAbsolutePath(), - "Config Write Exception", - JOptionPane.ERROR_MESSAGE); + SwingUtils.getErrorDialog() + .setTitle("Config Write Exception") + .setMessage("Could not update config:", file.getAbsolutePath()) + .show(); System.exit(-1); } diff --git a/src/main/java/assets/ui/SelectMapDialog.java b/src/main/java/assets/ui/SelectMapDialog.java index 5842d10..0cc5e16 100644 --- a/src/main/java/assets/ui/SelectMapDialog.java +++ b/src/main/java/assets/ui/SelectMapDialog.java @@ -97,10 +97,12 @@ private static File promptCopyMap(File selectedFile) Map newMap = Map.loadMap(selectedFile); // prompt for a description - String newMapDesc = SwingUtils.showFramedInputDialog(null, - "Provide a map description", - "New Map Description", - JOptionPane.QUESTION_MESSAGE); + String newMapDesc = SwingUtils.getInputDialog() + .setTitle("New Map Description") + .setMessage("Provide a map description") + .setMessageType(JOptionPane.QUESTION_MESSAGE) + .prompt(); + newMap.desc = (newMapDesc != null) ? newMapDesc : ""; // save the new map @@ -128,10 +130,12 @@ public static File promptNewMap() Map newMap = new Map(newMapName); // prompt for a description - String newMapDesc = SwingUtils.showFramedInputDialog(null, - "Provide a map description", - "New Map Description", - JOptionPane.QUESTION_MESSAGE); + String newMapDesc = SwingUtils.getInputDialog() + .setTitle("New Map Description") + .setMessage("Provide a map description") + .setMessageType(JOptionPane.QUESTION_MESSAGE) + .prompt(); + newMap.desc = (newMapDesc != null) ? newMapDesc : ""; // prompt for textures @@ -160,10 +164,11 @@ public static File promptNewMap() public static File requestNewMapFile() { - String name = SwingUtils.showFramedInputDialog(null, - "Provide a new map name", - "New Map Name", - JOptionPane.QUESTION_MESSAGE); + String name = SwingUtils.getInputDialog() + .setTitle("New Map Name") + .setMessage("Provide a new map name") + .setMessageType(JOptionPane.QUESTION_MESSAGE) + .prompt(); if (name == null) return null; @@ -182,11 +187,13 @@ public static File requestNewMapFile() if (!existing.exists()) return existing; - int response = SwingUtils.showFramedConfirmDialog(null, - name + " already exists. Overwrite it?", - "Map Already Exists", JOptionPane.YES_NO_CANCEL_OPTION); + int choice = SwingUtils.getConfirmDialog() + .setTitle("Map Already Exists") + .setMessage(name + " already exists. Overwrite it?") + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .choose(); - return (response == JOptionPane.YES_OPTION) ? existing : null; + return (choice == JOptionPane.YES_OPTION) ? existing : null; } private final JList list; diff --git a/src/main/java/game/globals/editor/GlobalsEditor.java b/src/main/java/game/globals/editor/GlobalsEditor.java index 4ea4e9f..299ecf5 100644 --- a/src/main/java/game/globals/editor/GlobalsEditor.java +++ b/src/main/java/game/globals/editor/GlobalsEditor.java @@ -38,7 +38,7 @@ import game.globals.editor.tabs.ItemTab; import game.globals.editor.tabs.MoveTab; import game.message.Message; -import game.message.editor.MessageGroup; +import game.message.editor.MessageAsset; import net.miginfocom.swing.MigLayout; import util.DualHashMap; import util.IterableListModel; @@ -207,10 +207,15 @@ private void createGUI(CountDownLatch guiClosedSignal) @Override public void windowClosing(WindowEvent e) { - int choice = !tabsHaveChanges() ? JOptionPane.NO_OPTION - : SwingUtils.showFramedConfirmDialog(null, - String.format("Unsaved changes will be lost!%nWould you like to save now?"), - "Warning", JOptionPane.YES_NO_CANCEL_OPTION); + int choice = JOptionPane.NO_OPTION; + + if (tabsHaveChanges()) { + choice = SwingUtils.getConfirmDialog() + .setTitle("Warning") + .setMessage("Unsaved changes will be lost!", "Would you like to save now?") + .choose(); + } + switch (choice) { case JOptionPane.YES_OPTION: saveAllChanges(); @@ -263,10 +268,16 @@ private void addActionsMenu(JMenuBar menuBar) item = new JMenuItem("Reload Data"); item.addActionListener((e) -> { - int choice = !currentTabHasChanges() ? JOptionPane.OK_OPTION - : SwingUtils.showFramedConfirmDialog(null, - String.format("Any changes will be lost.%nAre you sure you want to reload?"), - "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + int choice = JOptionPane.OK_OPTION; + if (currentTabHasChanges()) { + choice = SwingUtils.getConfirmDialog() + .setTitle("Warning") + .setMessage("Any changes will be lost.", "Are you sure you want to reload?") + .setMessageType(JOptionPane.WARNING_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_OPTION) + .choose(); + } + if (choice == JOptionPane.OK_OPTION) reloadCurrentTab(); }); @@ -276,10 +287,15 @@ private void addActionsMenu(JMenuBar menuBar) item = new JMenuItem("Save Changes"); item.addActionListener((e) -> { - int choice = !tabsHaveChanges() ? JOptionPane.OK_OPTION - : SwingUtils.showFramedConfirmDialog(null, - String.format("Are you sure you want to overwrite existing data?"), - "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + int choice = JOptionPane.OK_OPTION; + if (tabsHaveChanges()) { + choice = SwingUtils.getConfirmDialog() + .setTitle("Warning") + .setMessage("Are you sure you want to overwrite existing data?") + .setMessageType(JOptionPane.WARNING_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_OPTION) + .choose(); + } if (choice == JOptionPane.OK_OPTION) saveAllChanges(); }); @@ -356,10 +372,9 @@ private void loadMessages() messageNameMap.clear(); try { - int sectionID = 0; for (AssetHandle ah : AssetManager.getMessages()) { Logger.log("Reading messages from: " + ah.getName()); - MessageGroup group = new MessageGroup(ah, sectionID++); + MessageAsset group = new MessageAsset(ah); for (Message msg : group.messages) { messageNameMap.put("MSG_" + msg.name, msg); messageListModel.addElement(msg); diff --git a/src/main/java/game/globals/editor/tabs/ItemTab.java b/src/main/java/game/globals/editor/tabs/ItemTab.java index 2d98d11..2467f55 100644 --- a/src/main/java/game/globals/editor/tabs/ItemTab.java +++ b/src/main/java/game/globals/editor/tabs/ItemTab.java @@ -42,6 +42,7 @@ import game.globals.editor.renderers.ItemListRenderer; import game.globals.editor.renderers.MessageCellRenderer; import game.globals.editor.renderers.PaddedCellRenderer; +import game.map.editor.ui.SwingGUI; import game.message.Message; import net.miginfocom.swing.MigLayout; import util.Logger; @@ -117,15 +118,21 @@ public void actionPerformed(ActionEvent e) @Override protected String getTabName() - { return "Items"; } + { + return "Items"; + } @Override protected ExpectedAsset getIcon() - { return ExpectedAsset.ICON_FIRE_FLOWER; } + { + return ExpectedAsset.ICON_FIRE_FLOWER; + } @Override protected GlobalsCategory getDataType() - { return GlobalsCategory.ITEM_TABLE; } + { + return GlobalsCategory.ITEM_TABLE; + } @Override protected void notifyDataChange(GlobalsCategory type) @@ -412,8 +419,14 @@ protected JPanel createInfoPanel(JLabel infoLabel) ItemRecord item = getSelected(); FlagEditorPanel flagPanel = new FlagEditorPanel(item.typeFlags); - if (JOptionPane.YES_OPTION == SwingUtils.showFramedConfirmDialog( - null, flagPanel, "Set Type Flags", JOptionPane.OK_CANCEL_OPTION)) { + int choice = SwingUtils.getConfirmDialog() + .setParent(SwingGUI.instance()) + .setTitle("Set Type Flags") + .setMessage(flagPanel) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); + + if (choice == JOptionPane.YES_OPTION) { int newValue = flagPanel.getValue(); if (newValue != item.typeFlags.getBits()) { item.typeFlags.setBits(newValue); @@ -438,8 +451,14 @@ protected JPanel createInfoPanel(JLabel infoLabel) ItemRecord item = getSelected(); FlagEditorPanel flagPanel = new FlagEditorPanel(item.targetFlags); - if (JOptionPane.YES_OPTION == SwingUtils.showFramedConfirmDialog( - null, flagPanel, "Set Target Flags", JOptionPane.OK_CANCEL_OPTION)) { + int choice = SwingUtils.getConfirmDialog() + .setParent(SwingGUI.instance()) + .setTitle("Set Target Flags") + .setMessage(flagPanel) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); + + if (choice == JOptionPane.YES_OPTION) { int newValue = flagPanel.getValue(); if (newValue != item.targetFlags.getBits()) { item.targetFlags.setBits(newValue); @@ -757,5 +776,7 @@ protected void updateInfoPanel(ItemRecord item, boolean fromSet) @Override protected ListCellRenderer getCellRenderer() - { return new ItemListRenderer(editor.data); } + { + return new ItemListRenderer(editor.data); + } } diff --git a/src/main/java/game/globals/editor/tabs/MoveTab.java b/src/main/java/game/globals/editor/tabs/MoveTab.java index 09742b3..467cb75 100644 --- a/src/main/java/game/globals/editor/tabs/MoveTab.java +++ b/src/main/java/game/globals/editor/tabs/MoveTab.java @@ -30,6 +30,7 @@ import game.globals.editor.renderers.MessageCellRenderer; import game.globals.editor.renderers.MoveListRenderer; import game.globals.editor.renderers.PaddedCellRenderer; +import game.map.editor.ui.SwingGUI; import game.message.Message; import net.miginfocom.swing.MigLayout; import util.Logger; @@ -87,15 +88,21 @@ public void actionPerformed(ActionEvent e) @Override protected String getTabName() - { return "Moves"; } + { + return "Moves"; + } @Override protected ExpectedAsset getIcon() - { return ExpectedAsset.ICON_POWER_JUMP; } + { + return ExpectedAsset.ICON_POWER_JUMP; + } @Override protected GlobalsCategory getDataType() - { return GlobalsCategory.MOVE_TABLE; } + { + return GlobalsCategory.MOVE_TABLE; + } @Override protected void notifyDataChange(GlobalsCategory type) @@ -377,8 +384,14 @@ protected JPanel createInfoPanel(JLabel infoLabel) MoveRecord move = getSelected(); FlagEditorPanel flagPanel = new FlagEditorPanel(move.targetFlags); - if (JOptionPane.YES_OPTION == SwingUtils.showFramedConfirmDialog( - null, flagPanel, "Set Flags", JOptionPane.OK_CANCEL_OPTION)) { + int choice = SwingUtils.getConfirmDialog() + .setParent(SwingGUI.instance()) + .setTitle("Set Flags") + .setMessage(flagPanel) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); + + if (choice == JOptionPane.YES_OPTION) { int newValue = flagPanel.getValue(); if (newValue != move.targetFlags.getBits()) { move.targetFlags.setBits(newValue); @@ -521,5 +534,7 @@ protected void updateInfoPanel(MoveRecord move, boolean fromSet) @Override protected ListCellRenderer getCellRenderer() - { return new MoveListRenderer(); } + { + return new MoveListRenderer(); + } } diff --git a/src/main/java/game/map/editor/EditorShortcut.java b/src/main/java/game/map/editor/EditorShortcut.java index 28f81e3..6de0225 100644 --- a/src/main/java/game/map/editor/EditorShortcut.java +++ b/src/main/java/game/map/editor/EditorShortcut.java @@ -9,8 +9,6 @@ import javax.swing.JMenuItem; import javax.swing.KeyStroke; -import game.sprite.editor.ShortcutListPanel; - /** * Key combinations that execute some action when pressed in the editor window * (specifically, when the GL canvas has focus). Each can be linked to a checkbox @@ -217,7 +215,9 @@ public void setCheckbox(boolean newValue) } public JCheckBoxMenuItem getCheckBox() - { return checkbox; } + { + return checkbox; + } private static final HashMap inputKeyMap; private static final HashMap inputCtrlKeyMap; diff --git a/src/main/java/game/map/editor/MapEditor.java b/src/main/java/game/map/editor/MapEditor.java index bd0f632..d519f0b 100644 --- a/src/main/java/game/map/editor/MapEditor.java +++ b/src/main/java/game/map/editor/MapEditor.java @@ -580,7 +580,9 @@ public MapEditor(boolean showLoadingScreen) throws IOException } public boolean isLoading() - { return loading; } + { + return loading; + } /** * Start running the editor, prompting the user to select a map @@ -865,9 +867,12 @@ private Map checkForCrashData() if (crashMap == null) return null; - int choice = SwingUtils.showFramedConfirmDialog(null, - "Found crash data for " + crashMap.getName() + ", would you like to load?", "Crash Recovery", - JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); + int choice = SwingUtils.getConfirmDialog() + .setTitle("Crash Recovery") + .setMessage("Found crash data for " + crashMap.getName(), "Would you like to load it?") + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_OPTION) + .choose(); if (choice == JOptionPane.YES_OPTION) return crashMap; @@ -894,11 +899,13 @@ private Map checkForBackup(Map baseMap) return baseMap; } - gui.notify_OpenDialog(); - int choice = SwingUtils.showFramedConfirmDialog(null, - "Found backup data for " + baseMap.getName() + ", would you like to load it instead?", "Backup Recovery", - JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); - gui.notify_CloseDialog(); + int choice = SwingUtils.getConfirmDialog() + .setCounter(gui.getDialogCounter()) + .setTitle("Backup Recovery") + .setMessage("Found backup data for " + baseMap.getName(), "Would you like to load it instead?") + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_OPTION) + .choose(); if (choice == JOptionPane.YES_OPTION) return backupMap; @@ -931,10 +938,14 @@ private Map showOpeningPrompt() Map selectedMap = null; while (true) { - int choice = SwingUtils.showFramedOptionDialog(null, - "Which map would you like to open?", "Choose Map", - JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, - null, options, "Browse Maps"); + int choice = SwingUtils.getOptionDialog() + .setTitle("Choose Map") + .setMessage("Which map would you like to open?") + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_OPTION) + .setOptions(options) + .setDefault("Browse Maps") + .choose(); if (choice == JOptionPane.CLOSED_OPTION) { selectedMap = null; @@ -1130,10 +1141,10 @@ private static Config readEditorConfig(File configFile) if (!configFile.exists()) { Config cfg = makeNewConfig(configFile); if (cfg == null) { - SwingUtils.showFramedMessageDialog(null, - "Failed to create new config: \n" + configFile.getAbsolutePath(), - "Create Config Failed", - JOptionPane.ERROR_MESSAGE); + SwingUtils.getErrorDialog() + .setTitle("Create Config Failed") + .setMessage("Failed to create new config:", configFile.getAbsolutePath()) + .show(); return null; } @@ -1146,10 +1157,10 @@ private static Config readEditorConfig(File configFile) cfg.readConfig(); } catch (IOException e) { - SwingUtils.showFramedMessageDialog(null, - "IOException occured while reading config: \n" + configFile.getAbsolutePath(), - "Load Config Failed", - JOptionPane.ERROR_MESSAGE); + SwingUtils.getErrorDialog() + .setTitle("Load Config Failed") + .setMessage("IOException occured while reading config:", configFile.getAbsolutePath()) + .show(); return null; } return cfg; @@ -1420,7 +1431,9 @@ else if (isPlayInEditorMode) { } public EditorMode getEditorMode() - { return editorMode; } + { + return editorMode; + } public Selection getSelectionForCurrentMode() { @@ -1441,7 +1454,9 @@ public Selection getSelectionForCurrentMode() } public List getEditorObjects() - { return editorObjects; } + { + return editorObjects; + } public void addEditorObject(EditorObject obj) { @@ -1454,13 +1469,19 @@ public boolean removeEditorObject(EditorObject obj) } public long getFrame() - { return frameCounter; } + { + return frameCounter; + } public double getDeltaTime() - { return deltaTime; } + { + return deltaTime; + } public double getTotalTime() - { return time; } + { + return time; + } /** * These methods allow the GUI to submit events to the editor. @@ -1517,10 +1538,11 @@ private void executeGuiCommand(GuiCommand cmd) Logger.log("Successfully compiled " + shapeMap.getName() + "_shape"); } catch (BuildException be) { - SwingUtilities.invokeLater(() -> { - SwingUtils.showFramedMessageDialog(gui, be.getMessage(), - "Geometry Build Failed", JOptionPane.ERROR_MESSAGE, Environment.ICON_ERROR); - }); + SwingUtils.getErrorDialog() + .setParent(gui) + .setTitle("Shape Build Failed") + .setMessage(be.getMessage()) + .showLater(); } catch (IOException ioe) { Logger.log("Build failed: IOException. Check log for more information.", Priority.ERROR); @@ -1535,10 +1557,11 @@ private void executeGuiCommand(GuiCommand cmd) Logger.log("Successfully compiled " + hitMap.getName() + "_hit"); } catch (BuildException be) { - SwingUtilities.invokeLater(() -> { - SwingUtils.showFramedMessageDialog(gui, be.getMessage(), - "Collision Build Failed", JOptionPane.ERROR_MESSAGE, Environment.ICON_ERROR); - }); + SwingUtils.getErrorDialog() + .setParent(gui) + .setTitle("Collision Build Failed") + .setMessage(be.getMessage()) + .showLater(); } catch (IOException ioe) { Logger.log("Build failed: IOException. Check log for more information.", Priority.ERROR); @@ -1705,14 +1728,18 @@ private void executeGuiCommand(GuiCommand cmd) List models = selectionManager.getSelectedObjects(Model.class); if (models.size() > 0) { SwingUtilities.invokeLater(() -> { - JComboBox selectionBox = new JComboBox<>(RenderMode.getEditorModes()); selectionBox.setSelectedItem(models.get(models.size() - 1).renderMode.get()); - gui.notify_OpenDialog(); - int choice = SwingUtils.showFramedConfirmDialog(gui, selectionBox, "Set Render Mode", - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE); - gui.notify_CloseDialog(); + + int choice = SwingUtils.getConfirmDialog() + .setParent(gui) + .setCounter(gui.getDialogCounter()) + .setTitle("Set Render Mode") + .setMessage(selectionBox) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); + RenderMode selectedMode = (RenderMode) selectionBox.getSelectedItem(); if (choice == JOptionPane.YES_OPTION && selectedMode != null) { @@ -3243,10 +3270,14 @@ private boolean tryMapExit(PickRay traceBelowCursor) } public boolean isPlayInEditorMode() - { return isPlayInEditorMode; } + { + return isPlayInEditorMode; + } public PerspCameraMode getCameraMode() - { return perspCameraMode; } + { + return perspCameraMode; + } public CameraController getCameraController() { @@ -3667,10 +3698,12 @@ private void loadMapResources(boolean reloadTextures) loadedTextures = TextureManager.load(map.texName); while (!loadedTextures) { - int choice = SwingUtils.showFramedConfirmDialog(gui, - "Could not open texture archive \"" + map.texName + "\", select a different one?", - "Missing Texture Archive", - JOptionPane.YES_NO_OPTION); + int choice = SwingUtils.getConfirmDialog() + .setParent(gui) + .setTitle("Missing Texture Archive") + .setMessage("Could not open texture archive \"" + map.texName + "\", select a different one?") + .setOptionsType(JOptionPane.YES_NO_OPTION) + .choose(); if (choice == JOptionPane.YES_OPTION) { File texFile = SelectTexDialog.showPrompt(); @@ -3893,10 +3926,14 @@ private void checkHitOverride() } public Map getGeometryMap() - { return shapeOverride == null ? map : shapeOverride; } + { + return shapeOverride == null ? map : shapeOverride; + } public Map getCollisionMap() - { return hitOverride == null ? map : hitOverride; } + { + return hitOverride == null ? map : hitOverride; + } private void openMap(Map newMap, boolean thumbnailMode) { @@ -4092,7 +4129,9 @@ private void nudge(Vector3f nudgeDirection) } public Vector3f getCursorPosition() - { return cursor3D != null ? cursor3D.getPosition() : new Vector3f(); } + { + return cursor3D != null ? cursor3D.getPosition() : new Vector3f(); + } private void findObject() { @@ -4641,13 +4680,19 @@ public void loadPreferences() } public float getDefaultUVScale() - { return uvScale; } + { + return uvScale; + } public float getNormalsLength() - { return normalsLength; } + { + return normalsLength; + } public double getRotationSnap() - { return rotationSnapIncrement; } + { + return rotationSnapIncrement; + } public boolean debugModeEnabled() { @@ -4662,11 +4707,12 @@ public void displayStackTrace(Throwable t) public void displayStackTrace(Throwable t, String errorMessage) { SwingUtilities.invokeLater(() -> { - gui.notify_OpenDialog(); Toolkit.getDefaultToolkit().beep(); Logger.logError(errorMessage); + + gui.getDialogCounter().increment(); StarRodMain.displayStackTrace(t); - gui.notify_CloseDialog(); + gui.getDialogCounter().decrement(); }); } diff --git a/src/main/java/game/map/editor/common/BaseEditor.java b/src/main/java/game/map/editor/common/BaseEditor.java index b5a9a8d..73ef172 100644 --- a/src/main/java/game/map/editor/common/BaseEditor.java +++ b/src/main/java/game/map/editor/common/BaseEditor.java @@ -44,6 +44,8 @@ import app.StarRodException; import app.StarRodMain; import app.SwingUtils; +import app.SwingUtils.DialogBuilder; +import app.SwingUtils.OpenDialogCounter; import app.config.Config; import app.config.Options; import app.config.Options.Scope; @@ -94,7 +96,7 @@ private enum RunState // editor state protected volatile boolean modified = false; private volatile boolean closeRequested = false; - private volatile int openDialogs = 0; + private volatile OpenDialogCounter openDialogs = new OpenDialogCounter(); protected boolean glWindowGrabsMouse; protected boolean glWindowHaltsForDialogs; @@ -209,7 +211,7 @@ public final boolean launch() time = t0 / 1e9; // gl canvas acquires focus on mouseover - if (glWindowGrabsMouse && !glCanvas.hasFocus() && mouse.hasLocation() && openDialogs == 0) { + if (glWindowGrabsMouse && !glCanvas.hasFocus() && mouse.hasLocation() && openDialogs.isZero()) { java.awt.EventQueue.invokeLater(() -> { glCanvas.requestFocusInWindow(); }); @@ -350,10 +352,10 @@ private final void createFrame(BaseEditorSettings windowSettings) @Override public void windowClosing(WindowEvent e) { - openDialogs++; + openDialogs.increment(); closeRequested = !modified || promptForSave(); if (!closeRequested) - openDialogs--; + openDialogs.decrement(); } }); @@ -418,19 +420,18 @@ private ActionListener createOpenLogAction() } if (!success) { - openDialogs++; - String[] options = { "Copy to Clipboard" }; - int selection = SwingUtils.showFramedOptionDialog(null, - logScrollPane, - "Editor Log", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE, - Environment.ICON_DEFAULT, - options, - options[0]); - openDialogs--; - - if (selection == 0) { + openDialogs.increment(); + int choice = SwingUtils.getOptionDialog() + .setTitle("Editor Log") + .setMessage(logScrollPane) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .setIcon(Environment.ICON_DEFAULT) + .setOptions("Copy to Clipboard") + .choose(); + openDialogs.decrement(); + + if (choice == 0) { StringSelection stringSelection = new StringSelection(logTextArea.getText()); Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); cb.setContents(stringSelection, null); @@ -444,10 +445,10 @@ private Config readEditorConfig(Scope scope, File configFile) if (!configFile.exists()) { Config cfg = makeNewConfig(scope, configFile); if (cfg == null) { - SwingUtils.showFramedMessageDialog(null, - "Failed to create new config: \n" + configFile.getAbsolutePath(), - "Create Config Failed", - JOptionPane.ERROR_MESSAGE); + SwingUtils.getErrorDialog() + .setTitle("Create Config Failed") + .setMessage("Failed to create new config:", configFile.getAbsolutePath()) + .show(); return null; } @@ -460,10 +461,10 @@ private Config readEditorConfig(Scope scope, File configFile) cfg.readConfig(); } catch (IOException e) { - SwingUtils.showFramedMessageDialog(null, - "IOException occured while reading config: \n" + configFile.getAbsolutePath(), - "Load Config Failed", - JOptionPane.ERROR_MESSAGE); + SwingUtils.getErrorDialog() + .setTitle("Load Config Failed") + .setMessage("IOException occured while reading config:", configFile.getAbsolutePath()) + .show(); return null; } return cfg; @@ -488,17 +489,23 @@ private Config makeNewConfig(Scope scope, File configFile) } protected Config getConfig() - { return config; } + { + return config; + } private final boolean promptForSave() { - openDialogs++; - int response = SwingUtils.showFramedConfirmDialog(frame, - String.format("Unsaved changes will be lost! %nWould you like to save now?"), - "Warning", JOptionPane.YES_NO_CANCEL_OPTION); - openDialogs--; + openDialogs.increment(); + + int choice = SwingUtils.getConfirmDialog() + .setTitle("Warning") + .setMessage("Unsaved changes will be lost!", "Would you like to save now?") + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .choose(); - switch (response) { + openDialogs.decrement(); + + switch (choice) { case JOptionPane.YES_OPTION: saveChanges(); break; @@ -512,48 +519,33 @@ private final boolean promptForSave() return true; } - protected final void showMessageDialog(Object message, String title) + protected final DialogBuilder getMessageDialog(String title, Object message) { - openDialogs++; - SwingUtils.showFramedMessageDialog(frame, - message, title, - JOptionPane.PLAIN_MESSAGE); - openDialogs--; + return SwingUtils.getMessageDialog() + .setParent(frame) + .setTitle(title) + .setMessage(message) + .setCounter(openDialogs); } - protected final int showConfirmDialog(Object message, String title) + protected final DialogBuilder getConfirmDialog(String title, Object message) { - openDialogs++; - int userAction = SwingUtils.showFramedConfirmDialog(frame, - message, title, - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE); - openDialogs--; - return userAction; + return SwingUtils.getConfirmDialog() + .setParent(frame) + .setTitle(title) + .setMessage(message) + .setCounter(openDialogs) + .setMessageType(JOptionPane.PLAIN_MESSAGE); } - protected final int showConfirmDialog(Object message, String title, int optionType) + protected final DialogBuilder getOptionDialog(String title, Object message) { - openDialogs++; - int userAction = SwingUtils.showFramedConfirmDialog(frame, - message, title, optionType, - JOptionPane.PLAIN_MESSAGE); - openDialogs--; - return userAction; - } - - protected final int showOptionDialog(Object message, String title, Object[] options) - { - openDialogs++; - int userAction = SwingUtils.showFramedOptionDialog(frame, - message, title, - JOptionPane.PLAIN_MESSAGE, - JOptionPane.PLAIN_MESSAGE, - null, - options, - options[0]); - openDialogs--; - return userAction; + return SwingUtils.getOptionDialog() + .setParent(frame) + .setTitle(title) + .setMessage(message) + .setCounter(openDialogs) + .setMessageType(JOptionPane.PLAIN_MESSAGE); } /** @@ -588,13 +580,19 @@ protected void glDraw() */ public final long getFrameCount() - { return frameCounter; } + { + return frameCounter; + } public final double getTime() - { return time; } + { + return time; + } public final double getDeltaTime() - { return deltaTime; } + { + return deltaTime; + } public final int glCanvasWidth() { @@ -613,37 +611,38 @@ protected final void revalidateFrame() protected final void showErrorDialog(String title, String msg) { - SwingUtilities.invokeLater(() -> { - SwingUtils.showFramedMessageDialog(frame, - msg, title, - JOptionPane.ERROR_MESSAGE, - Environment.ICON_ERROR); - }); + SwingUtils.getErrorDialog() + .setParent(frame) + .setTitle(title) + .setMessage(msg) + .showLater(); } protected final void showStackTrace(Throwable t) { - openDialogs++; + openDialogs.increment(); StarRodMain.displayStackTrace(t); - openDialogs--; + openDialogs.decrement(); } protected final JFrame getFrame() - { return frame; } + { + return frame; + } public boolean areDialogsOpen() { - return openDialogs > 0; + return !openDialogs.isZero(); } public final void incrementDialogsOpen() { - openDialogs++; + openDialogs.increment(); } public final void decrementDialogsOpen() { - openDialogs--; + openDialogs.decrement(); } /** diff --git a/src/main/java/game/map/editor/ui/ShorcutListPanel.java b/src/main/java/game/map/editor/ui/MapShortcutsPanel.java similarity index 99% rename from src/main/java/game/map/editor/ui/ShorcutListPanel.java rename to src/main/java/game/map/editor/ui/MapShortcutsPanel.java index 0e9eb2e..bfc1886 100644 --- a/src/main/java/game/map/editor/ui/ShorcutListPanel.java +++ b/src/main/java/game/map/editor/ui/MapShortcutsPanel.java @@ -8,9 +8,9 @@ import net.miginfocom.swing.MigLayout; -public class ShorcutListPanel extends JPanel +public class MapShortcutsPanel extends JPanel { - public ShorcutListPanel() + public MapShortcutsPanel() { setLayout(new MigLayout("fill")); diff --git a/src/main/java/game/map/editor/ui/SwingGUI.java b/src/main/java/game/map/editor/ui/SwingGUI.java index e480597..70ac973 100644 --- a/src/main/java/game/map/editor/ui/SwingGUI.java +++ b/src/main/java/game/map/editor/ui/SwingGUI.java @@ -50,6 +50,7 @@ import app.Environment; import app.SwingUtils; +import app.SwingUtils.OpenDialogCounter; import app.config.PreferencesPanel; import assets.AssetHandle; import assets.AssetManager; @@ -120,7 +121,7 @@ public final class SwingGUI extends JFrame implements ActionListener, Logger.Lis // for different EditorStates: modify, texture, and vertex paint. private volatile boolean closeRequested = false; - private volatile int openDialogCount = 0; + private volatile OpenDialogCounter openDialogCount = new OpenDialogCounter(); private volatile List popups = new LinkedList<>(); private HashMap commandMap; @@ -214,10 +215,11 @@ public SwingGUI(MapEditor editor, EditorCanvas glCanvas, File logFile) @Override public void windowClosing(WindowEvent e) { - openDialogCount++; + openDialogCount.increment(); closeRequested = (!editor.map.modified || promptForSave()) && (!ProjectDatabase.SpriteShading.modified || promptSaveShading()); if (!closeRequested) - openDialogCount--; + openDialogCount.decrement(); + ; } }); @@ -277,19 +279,18 @@ public void windowClosing(WindowEvent e) } if (!success) { - editor.gui.notify_OpenDialog(); - String[] options = { "Copy to Clipboard" }; - int selection = SwingUtils.showFramedOptionDialog(null, - logScrollPane, - "Editor Log", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE, - Environment.ICON_DEFAULT, - options, - options[0]); - editor.gui.notify_CloseDialog(); - - if (selection == 0) { + int choice = SwingUtils.getOptionDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("Editor Log") + .setMessage(logScrollPane) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .setIcon(Environment.ICON_DEFAULT) + .setOptions("Copy to Clipboard") + .choose(); + + if (choice == 0) { StringSelection stringSelection = new StringSelection(logTextArea.getText()); Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); cb.setContents(stringSelection, null); @@ -381,7 +382,14 @@ public void destroyGUI() } public boolean isModalDialogOpen() - { return openDialogCount > 0; } + { + return !openDialogCount.isZero(); + } + + public OpenDialogCounter getDialogCounter() + { + return openDialogCount; + } public void registerPopupMenu(JPopupMenu menu) { @@ -397,17 +405,21 @@ public void closePopupMenus() } public boolean isCloseRequested() - { return closeRequested; } + { + return closeRequested; + } public boolean promptForSave() { - openDialogCount++; - int response = SwingUtils.showFramedConfirmDialog(null, - "Unsaved changes will be lost!\r\nWould you like to save now?\r\n", - "Warning", JOptionPane.YES_NO_CANCEL_OPTION); - openDialogCount--; + int choice = SwingUtils.getConfirmDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("Warning") + .setMessage("Unsaved changes will be lost!", "Would you like to save now?") + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .choose(); - switch (response) { + switch (choice) { case JOptionPane.YES_OPTION: editor.action_SaveMap(); case JOptionPane.NO_OPTION: @@ -422,13 +434,15 @@ public boolean promptForSave() private boolean promptSaveShading() { - openDialogCount++; - int response = SwingUtils.showFramedConfirmDialog(null, - "Sprite shading data was changed!\r\nWould you like to save now?\r\n", - "Warning", JOptionPane.YES_NO_CANCEL_OPTION); - openDialogCount--; + int choice = SwingUtils.getConfirmDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("Warning") + .setMessage("Sprite shading data was changed!", "Would you like to save now?") + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .choose(); - switch (response) { + switch (choice) { case JOptionPane.YES_OPTION: editor.action_SaveShading(); case JOptionPane.NO_OPTION: @@ -1282,9 +1296,9 @@ public void changeMap(Map map) private void prompt_OpenMap() { if (!editor.map.modified || promptForSave()) { - openDialogCount++; + openDialogCount.increment(); File mapFile = SelectMapDialog.showPrompt(); - openDialogCount--; + openDialogCount.decrement(); if (mapFile != null) { editor.doNextFrame(() -> { @@ -1308,9 +1322,9 @@ private void prompt_OpenMap(String mapName) private void prompt_SaveMapAs() { - openDialogCount++; + openDialogCount.increment(); File newMapFile = SelectMapDialog.requestNewMapFile(); - openDialogCount--; + openDialogCount.decrement(); if (newMapFile != null) { editor.doNextFrame(() -> { @@ -1321,9 +1335,9 @@ private void prompt_SaveMapAs() private void prompt_LoadTextureArchive() { - openDialogCount++; + openDialogCount.increment(); File texFile = SelectTexDialog.showPrompt(); - openDialogCount--; + openDialogCount.decrement(); if (texFile != null) { String texName = FilenameUtils.getBaseName(texFile.getName()); @@ -1336,9 +1350,9 @@ private void prompt_LoadTextureArchive() private void prompt_ChangeBackground() { - openDialogCount++; + openDialogCount.increment(); File bgFile = SelectBackgroundDialog.showPrompt(); - openDialogCount--; + openDialogCount.decrement(); if (bgFile != null) { editor.doNextFrame(() -> { @@ -1356,12 +1370,12 @@ private void prompt_ChangeBackground() public void prompt_ImportObjects(MapObjectNode node) { - openDialogCount++; + openDialogCount.increment(); if (importFileChooser.prompt() == ChooseDialogResult.APPROVE) { File f = importFileChooser.getSelectedFile(); editor.map.importFromFile(f, node); } - openDialogCount--; + openDialogCount.decrement(); } private void prompt_ExportObjects() @@ -1371,12 +1385,12 @@ private void prompt_ExportObjects() if (selection.isEmpty()) return; - openDialogCount++; + openDialogCount.increment(); if (exportFileChooser.prompt() == ChooseDialogResult.APPROVE) { File f = exportFileChooser.getSelectedFile(); editor.map.exportToFile(f); } - openDialogCount--; + openDialogCount.decrement(); } public void prompt_EditTexPanner(TexturePanner panner) @@ -1417,11 +1431,16 @@ public void prompt_TransformSelection(Selection selection) transformSelectionPanel.setSelection(selection); - openDialogCount++; - int userAction = SwingUtils.showFramedConfirmDialog(this, transformSelectionPanel, "Transform Selection", JOptionPane.PLAIN_MESSAGE); - openDialogCount--; + int choice = SwingUtils.getConfirmDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("Transform Selection") + .setMessage(transformSelectionPanel) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); - if (userAction == JOptionPane.YES_OPTION) { + if (choice == JOptionPane.YES_OPTION) { final TransformMatrix m = transformSelectionPanel.createTransformMatrix(); if (m != null) { editor.doNextFrame(() -> { @@ -1435,11 +1454,16 @@ public int[] prompt_GetPositionVector(int x, int y, int z) { SetPositionPanel panel = new SetPositionPanel(x, y, z); - openDialogCount++; - int userAction = SwingUtils.showFramedConfirmDialog(this, panel, "Set Position", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); - openDialogCount--; + int choice = SwingUtils.getConfirmDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("Set Position") + .setMessage(panel) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); - if (userAction == JOptionPane.YES_OPTION) { + if (choice == JOptionPane.YES_OPTION) { return panel.getVector(); } else { @@ -1564,12 +1588,16 @@ private void createObjectFromBatch(TriangleBatch batch, String namePrefix, MapOb public void prompt_CreateMarker(MapObjectNode parent) { - openDialogCount++; - int userAction = SwingUtils.showFramedConfirmDialog(this, MarkerOptionsPanel.getInstance(), "Create Marker", - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); - openDialogCount--; + int choice = SwingUtils.getConfirmDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("Create Marker") + .setMessage(MarkerOptionsPanel.getInstance()) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); - if (userAction == JOptionPane.OK_OPTION) { + if (choice == JOptionPane.OK_OPTION) { editor.doNextFrame(() -> { editor.action_CreateMarker( MarkerOptionsPanel.getMarkerName(), @@ -1581,12 +1609,16 @@ public void prompt_CreateMarker(MapObjectNode parent) private void prompt_GenerateUV() { - openDialogCount++; - int userAction = SwingUtils.showFramedConfirmDialog(this, uvOptionsPanel, "UV Projection Options", - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); - openDialogCount--; + int choice = SwingUtils.getConfirmDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("UV Projection Options") + .setMessage(uvOptionsPanel) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); - if (userAction == JOptionPane.OK_OPTION) { + if (choice == JOptionPane.OK_OPTION) { final UVGenerator gen = uvOptionsPanel.getUVGenerator(); editor.doNextFrame(() -> { editor.action_GenerateUVs(gen); @@ -1596,21 +1628,26 @@ private void prompt_GenerateUV() public void prompt_ConfirmDialog(Object message, String title, Runnable action) { - openDialogCount++; - int userAction = SwingUtils.showFramedConfirmDialog(this, message, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); - openDialogCount--; + int choice = SwingUtils.getConfirmDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle(title) + .setMessage(message) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); - if (userAction == JOptionPane.OK_OPTION) { + if (choice == JOptionPane.OK_OPTION) { action.run(); } } private void prompt_ChooseColor() { - openDialogCount++; + openDialogCount.increment(); Color c = null; c = JColorChooser.showDialog(this, "Choose Color", c); - openDialogCount--; + openDialogCount.decrement(); if (c != null) { PaintManager.setSelectedColor(c); @@ -1618,21 +1655,15 @@ private void prompt_ChooseColor() } } - public void notify_OpenDialog() - { - openDialogCount++; - } - - public void notify_CloseDialog() - { - openDialogCount--; - } - private void showControls() { - openDialogCount++; - SwingUtils.showFramedMessageDialog(this, new ShorcutListPanel(), "Controls and Shortcuts", JOptionPane.PLAIN_MESSAGE); - openDialogCount--; + SwingUtils.getMessageDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("Controls and Shortcuts") + .setMessage(new MapShortcutsPanel()) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .show(); } private void showPreferences() @@ -1643,10 +1674,14 @@ private void showPreferences() PreferencesPanel preferences = new PreferencesPanel(); preferences.setValues(editor.editorConfig); - openDialogCount++; - int choice = SwingUtils.showFramedConfirmDialog(this, preferences, "Editor Preferences", JOptionPane.OK_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE); - openDialogCount--; + int choice = SwingUtils.getConfirmDialog() + .setParent(this) + .setCounter(openDialogCount) + .setTitle("Editor Preferences") + .setMessage(preferences) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); if (choice == JOptionPane.OK_OPTION) { preferences.getValues(editor.editorConfig); diff --git a/src/main/java/game/map/editor/ui/dialogs/SaveFileChooser.java b/src/main/java/game/map/editor/ui/dialogs/SaveFileChooser.java index a1ee15c..2c688c8 100644 --- a/src/main/java/game/map/editor/ui/dialogs/SaveFileChooser.java +++ b/src/main/java/game/map/editor/ui/dialogs/SaveFileChooser.java @@ -28,7 +28,9 @@ public SaveFileChooser(File dir, String title, String filterName, String ... fil } public void setCurrentDirectory(File dir) - { currentDirectory = dir; } + { + currentDirectory = dir; + } public ChooseDialogResult prompt(File dir) { @@ -66,16 +68,21 @@ public ChooseDialogResult prompt() } public File getSelectedFile() - { return selected; } + { + return selected; + } public boolean checkForOverwrite(File f) { if (!f.exists()) return true; - int result = SwingUtils.showFramedConfirmDialog(null, - "Overwrite existing file?", "File Already Exists", - JOptionPane.YES_NO_CANCEL_OPTION); - switch (result) { + + int choice = SwingUtils.getConfirmDialog() + .setTitle("File Already Exists") + .setMessage("Overwrite existing file?") + .choose(); + + switch (choice) { case JOptionPane.YES_OPTION: return true; case JOptionPane.CANCEL_OPTION: diff --git a/src/main/java/game/map/scripts/LightingPanel.java b/src/main/java/game/map/scripts/LightingPanel.java index 7ff9a5e..07b6f7a 100644 --- a/src/main/java/game/map/scripts/LightingPanel.java +++ b/src/main/java/game/map/scripts/LightingPanel.java @@ -103,10 +103,10 @@ public LightingPanel() JButton chooseColorButton = new JButton("Choose"); chooseColorButton.addActionListener((e) -> { - SwingGUI.instance().notify_OpenDialog(); + SwingGUI.instance().getDialogCounter().increment(); Color c = new Color(lightSet.ambient[0], lightSet.ambient[1], lightSet.ambient[2]); c = JColorChooser.showDialog(null, "Choose Ambient Color", c); - SwingGUI.instance().notify_CloseDialog(); + SwingGUI.instance().getDialogCounter().decrement(); if (c != null) MapEditor.execute(new SetAmbientColor(lightSet, c.getRed(), c.getGreen(), c.getBlue())); diff --git a/src/main/java/game/map/scripts/ShadingPanel.java b/src/main/java/game/map/scripts/ShadingPanel.java index 51738a4..2e59076 100644 --- a/src/main/java/game/map/scripts/ShadingPanel.java +++ b/src/main/java/game/map/scripts/ShadingPanel.java @@ -103,13 +103,14 @@ public ShadingPanel() boolean shouldDelete = true; if (selected.vanilla) { - SwingGUI.instance().notify_OpenDialog(); - int response = SwingUtils.showFramedConfirmDialog(SwingGUI.instance(), - "Selected profile is vanilla.\r\nAre you sure you want to delete it?\r\n", - "Warning", JOptionPane.YES_NO_CANCEL_OPTION); - SwingGUI.instance().notify_CloseDialog(); - - shouldDelete = (response == JOptionPane.YES_OPTION); + int choice = SwingUtils.getConfirmDialog() + .setParent(SwingGUI.instance()) + .setCounter(SwingGUI.instance().getDialogCounter()) + .setTitle("Warning") + .setMessage("Selected profile is vanilla.", "Are you sure you want to delete it?") + .choose(); + + shouldDelete = (choice == JOptionPane.YES_OPTION); } if (shouldDelete) { diff --git a/src/main/java/game/map/scripts/ShadingProfileInfoPanel.java b/src/main/java/game/map/scripts/ShadingProfileInfoPanel.java index 21e5748..2f1e427 100644 --- a/src/main/java/game/map/scripts/ShadingProfileInfoPanel.java +++ b/src/main/java/game/map/scripts/ShadingProfileInfoPanel.java @@ -90,10 +90,10 @@ public ShadingProfileInfoPanel(ShadingPanel parent) if (getData() == null) return; - SwingGUI.instance().notify_OpenDialog(); + SwingGUI.instance().getDialogCounter().increment(); Color c = new Color(getData().color.get()); c = JColorChooser.showDialog(null, "Choose Ambient Color", c); - SwingGUI.instance().notify_CloseDialog(); + SwingGUI.instance().getDialogCounter().decrement(); if (c != null) MapEditor.execute(new SetAmbientColor(getData(), c.getRGB())); @@ -119,11 +119,11 @@ public int locationToIndex(Point location) sourceList.addListSelectionListener((e) -> { if(getData() == null) return; - + MapEditor.instance().selectionManager.deselectLightsFromGUI(getData().sources); if(sourceList.getSelectedValue() != null) MapEditor.instance().selectionManager.selectLightsFromGUI(sourceList.getSelectedValue()); - + }); */ diff --git a/src/main/java/game/map/scripts/ShadingSourceInfoPanel.java b/src/main/java/game/map/scripts/ShadingSourceInfoPanel.java index e710fae..409040d 100644 --- a/src/main/java/game/map/scripts/ShadingSourceInfoPanel.java +++ b/src/main/java/game/map/scripts/ShadingSourceInfoPanel.java @@ -60,10 +60,10 @@ public ShadingSourceInfoPanel(ShadingProfileInfoPanel parent) if (getData() == null) return; - SwingGUI.instance().notify_OpenDialog(); + SwingGUI.instance().getDialogCounter().increment(); Color c = new Color(getData().color.get()); c = JColorChooser.showDialog(null, "Choose Ambient Color", c); - SwingGUI.instance().notify_CloseDialog(); + SwingGUI.instance().getDialogCounter().decrement(); if (c != null) MapEditor.execute(new SetLightColor(getData(), c.getRGB())); diff --git a/src/main/java/game/map/scripts/generators/foliage/FoliageInfoPanel.java b/src/main/java/game/map/scripts/generators/foliage/FoliageInfoPanel.java index 0ba8173..aba88e5 100644 --- a/src/main/java/game/map/scripts/generators/foliage/FoliageInfoPanel.java +++ b/src/main/java/game/map/scripts/generators/foliage/FoliageInfoPanel.java @@ -440,12 +440,16 @@ private static void tryEditModel(FoliageModel folMdl) SwingGUI gui = MapEditor.instance().gui; FoliageModelEditor editorPanel = new FoliageModelEditor(MapEditor.instance().map, folMdl); - gui.notify_OpenDialog(); - int userAction = SwingUtils.showFramedConfirmDialog(gui, editorPanel, "Edit Foliage Model", - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); - gui.notify_CloseDialog(); - - if (userAction == JOptionPane.OK_OPTION) + int choice = SwingUtils.getConfirmDialog() + .setParent(gui) + .setCounter(gui.getDialogCounter()) + .setTitle("Edit Foliage Model") + .setMessage(editorPanel) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); + + if (choice == JOptionPane.OK_OPTION) MapEditor.execute(folMdl.modelName.mutator(editorPanel.getValue())); } @@ -454,12 +458,16 @@ private static void tryEditVector(FoliageVector folVec) SwingGUI gui = MapEditor.instance().gui; FoliageVectorEditor editorPanel = new FoliageVectorEditor(MapEditor.instance().map, folVec); - gui.notify_OpenDialog(); - int userAction = SwingUtils.showFramedConfirmDialog(gui, editorPanel, "Edit Foliage Model", - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); - gui.notify_CloseDialog(); + int choice = SwingUtils.getConfirmDialog() + .setParent(gui) + .setCounter(gui.getDialogCounter()) + .setTitle("Edit Foliage Model") + .setMessage(editorPanel) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); - if (userAction == JOptionPane.OK_OPTION) + if (choice == JOptionPane.OK_OPTION) MapEditor.execute(folVec.modelName.mutator(editorPanel.getValue())); } @@ -468,12 +476,16 @@ private static void tryEditDrop(FoliageDrop folDrop) SwingGUI gui = MapEditor.instance().gui; FoliageDropEditor editorPanel = new FoliageDropEditor(MapEditor.instance().map, folDrop); - gui.notify_OpenDialog(); - int userAction = SwingUtils.showFramedConfirmDialog(gui, editorPanel, "Edit Foliage Drop", - JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); - gui.notify_CloseDialog(); + int choice = SwingUtils.getConfirmDialog() + .setParent(gui) + .setCounter(gui.getDialogCounter()) + .setTitle("Edit Foliage Model") + .setMessage(editorPanel) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.OK_CANCEL_OPTION) + .choose(); - if (userAction == JOptionPane.OK_OPTION) + if (choice == JOptionPane.OK_OPTION) MapEditor.execute(new EditFoliageDrop(folDrop, editorPanel.getEditedDrop())); } } diff --git a/src/main/java/game/map/shape/Light.java b/src/main/java/game/map/shape/Light.java index a841aab..52f374e 100644 --- a/src/main/java/game/map/shape/Light.java +++ b/src/main/java/game/map/shape/Light.java @@ -107,7 +107,9 @@ public Light deepCopy(LightSet parent) } public LightPanel getPanel() - { return panel; } + { + return panel; + } public static class LightPanel extends JPanel { @@ -160,10 +162,10 @@ private LightPanel(Light light) JButton chooseColorButton = new JButton("Choose"); chooseColorButton.addActionListener((e) -> { - SwingGUI.instance().notify_OpenDialog(); + SwingGUI.instance().getDialogCounter().increment(); Color c = new Color(light.color[0], light.color[1], light.color[2]); c = JColorChooser.showDialog(null, "Choose Light Color", c); - SwingGUI.instance().notify_CloseDialog(); + SwingGUI.instance().getDialogCounter().decrement(); if (c != null) MapEditor.execute(new SetLightColor(light, c.getRed(), c.getGreen(), c.getBlue())); diff --git a/src/main/java/game/message/Message.java b/src/main/java/game/message/Message.java index 4c21e9d..b026400 100644 --- a/src/main/java/game/message/Message.java +++ b/src/main/java/game/message/Message.java @@ -9,12 +9,12 @@ import app.input.Line; import app.input.PatchFileParser.PatchUnit; import game.message.StringConstants.ControlCharacter; -import game.message.editor.MessageGroup; +import game.message.editor.MessageAsset; import util.ui.FilterListable; public class Message implements FilterListable { - public final MessageGroup source; + public final MessageAsset source; public final PatchUnit unit; public int startLineNum = -1; @@ -38,7 +38,7 @@ public class Message implements FilterListable public String name; // loading from asset - public Message(MessageGroup res, PatchUnit unit, int section, int index, String name) + public Message(MessageAsset res, PatchUnit unit, int section, int index, String name) { this.source = res; this.unit = unit; @@ -54,16 +54,12 @@ public Message(MessageGroup res, PatchUnit unit, int section, int index, String } // created in editor - public Message(MessageGroup res, int section, int index, String name) + public Message(MessageAsset res) { this.source = res; this.unit = null; - this.section = section; - this.index = index; - this.name = name; - - name = "NewString"; + name = "NewMessage"; markup = "[END]"; previewText = ""; } diff --git a/src/main/java/game/message/StringEncoder.java b/src/main/java/game/message/StringEncoder.java index f85d568..2ae256c 100644 --- a/src/main/java/game/message/StringEncoder.java +++ b/src/main/java/game/message/StringEncoder.java @@ -26,9 +26,9 @@ import game.message.StringConstants.StringFunction; import game.message.StringConstants.StringStyle; import game.message.StringConstants.StringVoice; -import game.message.editor.MessageGroup; -import game.message.editor.StringTokenizer; -import game.message.editor.StringTokenizer.Sequence; +import game.message.editor.MessageAsset; +import game.message.editor.MessageTokenizer; +import game.message.editor.MessageTokenizer.Sequence; import util.CaseInsensitiveMap; import util.DualHashMap; import util.MathUtil; @@ -108,7 +108,7 @@ private void addArgsU8(String name, int ... bytes) addArgU8(name, i); } - public static List parseMessages(MessageGroup group) throws IOException + public static List parseMessages(MessageAsset group) throws IOException { List messages = new ArrayList<>(); @@ -130,30 +130,27 @@ public static List parseMessages(MessageGroup group) throws IOException int index = 0xFFFF; String name = ""; - if (unit.declaration.numTokens() == 2) { - if (!declareLine.getString(1).matches("\\S+")) - throw new InputFileException(declareLine, "String name could not be parsed: %n%s", declareLine.trimmedInput()); + if (unit.declaration.numTokens() == 3) { + if (!declareLine.getString(2).matches("\\(.+\\)")) + throw new InputFileException(declareLine, "String ID could not be parsed: %n%s", declareLine.trimmedInput()); - name = declareLine.getString(1); + section = declareLine.getHex(1); + name = declareLine.getString(2); + name = name.substring(1, name.length() - 1); } // LEGACY SUPPORT: #message | #string : section : index : (name) else if (unit.declaration.numTokens() == 4) { if (!declareLine.getString(3).matches("\\(.+\\)")) throw new InputFileException(declareLine, "String name could not be parsed: %n%s", declareLine.trimmedInput()); + section = declareLine.getHex(1); + index = declareLine.getHex(2); name = declareLine.getString(3); name = name.substring(1, name.length() - 1); } - // LEGACY SUPPORT: #message | #string : section : index | (name) - else if (unit.declaration.numTokens() == 3) { - if (!declareLine.getString(2).matches("\\(.+\\)")) - throw new InputFileException(declareLine, "String ID could not be parsed: %n%s", declareLine.trimmedInput()); - - name = declareLine.getString(2); - name = name.substring(1, name.length() - 1); - } - else + else { throw new InputFileException(declareLine, "String declaration could not be parsed: %n%s", declareLine.trimmedInput()); + } // parse lines @@ -204,7 +201,7 @@ public static ArrayList encodeText(String text, ByteBuffer[] vars) { StringEncoder builder = new StringEncoder(); builder.vars = vars; - ArrayList sequences = StringTokenizer.tokenize(text); + ArrayList sequences = MessageTokenizer.tokenize(text); encode(builder, sequences, false); return sequences; } @@ -214,7 +211,7 @@ public static ByteBuffer encodeVar(String text, boolean throwsExceptions) { StringEncoder builder = new StringEncoder(); builder.allowFontChange = false; - ArrayList sequences = StringTokenizer.tokenize(text); + ArrayList sequences = MessageTokenizer.tokenize(text); encode(builder, sequences, throwsExceptions); return getBuffer(sequences, false); } @@ -223,7 +220,7 @@ public static ByteBuffer encodeVar(String text, boolean throwsExceptions) public static ByteBuffer encode(String text) { StringEncoder builder = new StringEncoder(); - ArrayList sequences = StringTokenizer.tokenize(text); + ArrayList sequences = MessageTokenizer.tokenize(text); encode(builder, sequences, true); return getBuffer(sequences, false); } @@ -232,7 +229,7 @@ public static ByteBuffer encode(String text) public static ByteBuffer encodeLines(List lines) { StringEncoder builder = new StringEncoder(); - ArrayList sequences = StringTokenizer.tokenize(lines); + ArrayList sequences = MessageTokenizer.tokenize(lines); encode(builder, sequences, true); return getBuffer(sequences, true); } diff --git a/src/main/java/game/message/editor/AssetListTab.java b/src/main/java/game/message/editor/AssetListTab.java index c6af1d3..033eafd 100644 --- a/src/main/java/game/message/editor/AssetListTab.java +++ b/src/main/java/game/message/editor/AssetListTab.java @@ -3,7 +3,6 @@ import java.awt.Component; import java.io.IOException; import java.util.ArrayList; -import java.util.List; import javax.swing.BorderFactory; import javax.swing.JButton; @@ -17,19 +16,23 @@ import app.SwingUtils; import assets.AssetHandle; import assets.AssetManager; +import game.message.Message; import net.miginfocom.swing.MigLayout; import util.Logger; import util.ui.FilteredListPanel; public class AssetListTab extends JPanel { - private FilteredListPanel filteredList; + private final FilteredListPanel filteredList; + private final ArrayList assets; public AssetListTab(MessageEditor editor, MessageListTab listPanel) { + assets = new ArrayList<>(); + filteredList = new FilteredListPanel<>(new AssetCellRenderer()) { @Override - public String getFilterableText(MessageGroup group) + public String getFilterableText(MessageAsset group) { if (group != null) { return FilenameUtils.getBaseName(group.asset.getName()); @@ -40,9 +43,9 @@ public String getFilterableText(MessageGroup group) } @Override - public void handleSelection(MessageGroup asset) + public void handleSelection(MessageAsset asset) { - listPanel.setStrings((asset == null) ? null : asset.messages); + listPanel.setAsset(asset); } }; @@ -84,23 +87,37 @@ public void saveChanges() public void fullReload() { - List resources = new ArrayList<>(); + assets.clear(); try { - int sectionID = 0; for (AssetHandle ah : AssetManager.getMessages()) { Logger.log("Reading messages from: " + ah.getName()); - resources.add(new MessageGroup(ah, sectionID++)); + assets.add(new MessageAsset(ah)); } } catch (IOException e) { Logger.logError(e.getMessage()); } - filteredList.setContent(resources); + filteredList.setContent(assets); + } + + public boolean hasMessage(String name) + { + if (name == null) + return false; + + for (MessageAsset asset : assets) { + for (Message msg : asset.messages) { + if (name.equals(msg.name)) + return true; + } + } + + return false; } - public static class AssetCellRenderer extends JPanel implements ListCellRenderer + public static class AssetCellRenderer extends JPanel implements ListCellRenderer { private final JLabel nameLabel; @@ -117,8 +134,8 @@ public AssetCellRenderer() @Override public Component getListCellRendererComponent( - JList list, - MessageGroup group, + JList list, + MessageAsset group, int index, boolean isSelected, boolean cellHasFocus) diff --git a/src/main/java/game/message/editor/MessageGroup.java b/src/main/java/game/message/editor/MessageAsset.java similarity index 74% rename from src/main/java/game/message/editor/MessageGroup.java rename to src/main/java/game/message/editor/MessageAsset.java index 855500a..8568eec 100644 --- a/src/main/java/game/message/editor/MessageGroup.java +++ b/src/main/java/game/message/editor/MessageAsset.java @@ -16,19 +16,17 @@ import game.message.StringEncoder; import util.Logger; -public class MessageGroup +public class MessageAsset { public AssetHandle asset; public List messages = null; - public final int index; public boolean hasModified; public boolean hasError; - public MessageGroup(AssetHandle asset, int index) + public MessageAsset(AssetHandle asset) { this.asset = asset; - this.index = index; reload(); } @@ -43,42 +41,10 @@ public void reload() int msgIndex = 0; for (Message msg : messages) { - msg.section = this.index; msg.index = msgIndex++; } } - /* - public void saveChanges() - { - AssetHandle saveAsset = AssetManager.getTopLevel(asset); - - try (PrintWriter pw = IOUtils.getBufferedPrintWriter(saveAsset)) { - for (Message msg : strings) { - pw.println("#message:" + msg.name); - pw.println("{"); - msg.sanitize(); - String[] lines = msg.getMarkup().split("\r?\n"); - for (String line : lines) { - pw.println(msg.leadingTabs + line); - } - pw.println("}"); - pw.println(""); - } - - asset = saveAsset; - hasModified = false; - for (Message msg : strings) { - msg.modified = false; - } - } - catch (IOException e) { - Logger.logError("Failed to save " + asset.getName()); - Logger.printStackTrace(e); - } - } - */ - public void saveChanges() { List linesIn; @@ -101,7 +67,6 @@ public void saveChanges() linesOut = new ArrayList<>((int) (linesIn.size() * 1.2)); int currentLine = 0; - //TODO ensure strings are sorted for (Message msg : messages) { if (msg.startLineNum <= 0) { continue; @@ -158,7 +123,7 @@ public void saveChanges() private void writeString(Message msg, List linesOut) { - linesOut.add("#message:" + msg.name); + linesOut.add(String.format("#message:%02X:(%s)", msg.section, msg.name)); linesOut.add("{"); msg.sanitize(); diff --git a/src/main/java/game/message/editor/MessageEditor.java b/src/main/java/game/message/editor/MessageEditor.java index b49837e..73902a6 100644 --- a/src/main/java/game/message/editor/MessageEditor.java +++ b/src/main/java/game/message/editor/MessageEditor.java @@ -90,7 +90,7 @@ import game.message.StringConstants.StringStyle; import game.message.StringConstants.StringVoice; import game.message.StringEncoder; -import game.message.editor.StringTokenizer.Sequence; +import game.message.editor.MessageTokenizer.Sequence; import game.texture.ImageConverter; import game.texture.Tile; import net.miginfocom.swing.MigLayout; @@ -132,12 +132,12 @@ public class MessageEditor extends BaseEditor // tool settings - private final StringPrinter printer = new StringPrinter(this); - private StringRenderer renderer; + private final MessagePrinter printer = new MessagePrinter(this); + private MessageRenderer renderer; private JPanel editorPanel; - private AssetListTab resourcePanel; - private MessageListTab stringListPanel; + private AssetListTab assetListTab; + private MessageListTab messageListTab; private JTextPane inputTextPane; private JTabbedPane tabs; @@ -182,7 +182,7 @@ public class MessageEditor extends BaseEditor private volatile boolean ignoreDocumentFormatChanges = false; // IO - public ArrayList resourcesToSave = new ArrayList<>(); + public ArrayList resourcesToSave = new ArrayList<>(); public static enum PollResult { @@ -215,7 +215,7 @@ public MessageEditor() readVarImage(MessageBoxes.Graphic.Letter_Peach.getFile()); - resourcePanel.fullReload(); + assetListTab.fullReload(); setString(null); Logger.log("Loaded string editor."); @@ -393,9 +393,9 @@ private void handleInput(double deltaTime) private void handleSaving() { if (!resourcesToSave.isEmpty()) { - ArrayList saved = new ArrayList<>(); + ArrayList saved = new ArrayList<>(); - for (MessageGroup res : resourcesToSave) { + for (MessageAsset res : resourcesToSave) { res.saveChanges(); saved.add(res); } @@ -936,8 +936,8 @@ public void textChanged(DocumentEvent e) modified = true; workingString.setModified(); } - resourcePanel.repaint(); - stringListPanel.repaint(); + assetListTab.repaint(); + messageListTab.repaint(); } } @@ -976,12 +976,12 @@ public void actionPerformed(ActionEvent e) addEditorMenu(menuBar); addOptionsMenu(menuBar); - stringListPanel = new MessageListTab(this); - resourcePanel = new AssetListTab(this, stringListPanel); + messageListTab = new MessageListTab(this); + assetListTab = new AssetListTab(this, messageListTab); tabs = new JTabbedPane(); - createTab(tabs, "Assets", resourcePanel); - createTab(tabs, "Messages", stringListPanel); + createTab(tabs, "Assets", assetListTab); + createTab(tabs, "Messages", messageListTab); createTab(tabs, "Variables", makeVariablesTab()); // wrap input pane in a scroll pane to let us scroll @@ -1034,6 +1034,11 @@ public void redoEDT() } } + public boolean hasMessage(String name) + { + return assetListTab.hasMessage(name); + } + private static void createTab(JTabbedPane tabs, String name, Container contents) { JLabel lbl = SwingUtils.getLabel(name, 12); @@ -1126,18 +1131,17 @@ private JPanel makeVariablesTab() textArea.append(String.format("%n")); super.incrementDialogsOpen(); - String[] options = { "Copy to Clipboard" }; - int selection = SwingUtils.showFramedOptionDialog(null, - detailScrollPane, - "Patch for Loading Image", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.PLAIN_MESSAGE, - Environment.ICON_DEFAULT, - options, - options[0]); + int choice = SwingUtils.getOptionDialog() + .setTitle("Code for Loading Image") + .setMessage(detailScrollPane) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .setOptionsType(JOptionPane.YES_NO_CANCEL_OPTION) + .setIcon(Environment.ICON_DEFAULT) + .setOptions("Copy to Clipboard") + .choose(); super.decrementDialogsOpen(); - if (selection == 0) { + if (choice == 0) { StringSelection stringSelection = new StringSelection(textArea.getText()); Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); cb.setContents(stringSelection, null); @@ -1238,7 +1242,7 @@ private void addFileMenu(JMenuBar menuBar, ActionListener openLogAction) awtKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); item.setAccelerator(awtKeyStroke); item.addActionListener((e) -> { - resourcePanel.saveChanges(); + assetListTab.saveChanges(); }); menu.add(item); @@ -1301,7 +1305,14 @@ private void addEditorMenu(JMenuBar menuBar) item = new JMenuItem("View Tips"); item.addActionListener((e) -> { incrementDialogsOpen(); - SwingUtils.showFramedMessageDialog(getFrame(), new ControlsPanel(), "Controls", JOptionPane.PLAIN_MESSAGE); + + SwingUtils.getMessageDialog() + .setParent(getFrame()) + .setTitle("Message Editor Pro Tips") + .setMessage(new MessageTipsPanel()) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .show(); + decrementDialogsOpen(); }); menu.add(item); @@ -1329,7 +1340,7 @@ private void addOptionsMenu(JMenuBar menuBar) @Override protected void saveChanges() { - resourcePanel.saveChanges(); + assetListTab.saveChanges(); handleSaving(); } @@ -1337,7 +1348,7 @@ protected void saveChanges() public void glInit() { try { - renderer = new StringRenderer(this); + renderer = new MessageRenderer(this); } catch (Throwable t) { StarRodMain.displayStackTrace(t); @@ -1361,18 +1372,18 @@ public boolean printDelayEnabled() } public boolean isCullingEnabled() - { return cbCulling.isSelected(); } + { + return cbCulling.isSelected(); + } - public static class ControlsPanel extends JPanel + public static class MessageTipsPanel extends JPanel { - public ControlsPanel() + public MessageTipsPanel() { JTextPane tx = new JTextPane(); tx.setContentType("text/html"); tx.setText("" - + "

String Editor Tips

" - + "

RIGHT CLICK on items in the resource tab to see available actions

" - + "

You can insert newline tags in the text field with SHIFT + ENTER

" + + "

You can quickly insert newline tags with SHIFT + ENTER

" + ""); tx.setEditable(false); add(tx); diff --git a/src/main/java/game/message/editor/MessageListTab.java b/src/main/java/game/message/editor/MessageListTab.java index 0c1d01d..a7bfca8 100644 --- a/src/main/java/game/message/editor/MessageListTab.java +++ b/src/main/java/game/message/editor/MessageListTab.java @@ -2,9 +2,7 @@ import java.awt.Color; import java.awt.Component; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import java.awt.Toolkit; import javax.swing.BorderFactory; import javax.swing.JButton; @@ -15,8 +13,6 @@ import javax.swing.ListCellRenderer; import app.SwingUtils; -import assets.AssetHandle; -import assets.AssetManager; import game.message.Message; import net.miginfocom.swing.MigLayout; import util.Logger; @@ -24,10 +20,15 @@ public class MessageListTab extends JPanel { - private FilteredListPanel filteredList; + private final MessageEditor editor; + private final FilteredListPanel filteredList; + + private MessageAsset asset; public MessageListTab(MessageEditor editor) { + this.editor = editor; + filteredList = new FilteredListPanel<>(new MessageCellRenderer()) { @Override public String getFilterableText(Message msg) @@ -44,68 +45,140 @@ public void handleSelection(Message msg) } }; + JButton createButton = new JButton("Create"); + createButton.addActionListener((e) -> createMessage()); + + JButton deleteButton = new JButton("Delete"); + deleteButton.addActionListener((e) -> deleteMessage()); + deleteButton.setEnabled(false); //TODO + JButton renameButton = new JButton("Rename"); renameButton.addActionListener((e) -> renameMessage()); - JButton createButton = new JButton("Create"); - createButton.addActionListener((e) -> createMessage()); + JButton sectionButton = new JButton("Set Section"); + sectionButton.addActionListener((e) -> setMessageSection()); setLayout(new MigLayout("fill, ins 0")); add(filteredList, "grow, pushy, span, wrap"); add(renameButton, "sg but, growx, pushx, h 32!, split 2"); - add(createButton, "sg but, growx, pushx"); + add(sectionButton, "sg but, growx, pushx, wrap"); + add(createButton, "sg but, growx, pushx, h 32!, split 2"); + add(deleteButton, "sg but, growx, pushx"); + } + + public void createMessage() + { + if (asset != null) { + + int sectionID = 0; + if (asset.messages.size() > 0) { + sectionID = asset.messages.get(asset.messages.size() - 1).section; + } + + Message msg = new Message(asset); + msg.section = sectionID; + + msg.name = promptForUniqueName(null); + if (msg.name != null) { + asset.messages.add(msg); + filteredList.setContent(asset.messages); + + filteredList.setSelected(msg); + } + } + } + + public void deleteMessage() + { + Message selected = filteredList.getSelected(); + + if (asset != null && selected != null) { + Toolkit.getDefaultToolkit().beep(); + //TODO asset.messages.remove(selected); + } } public void renameMessage() { - Message msg = filteredList.getSelected(); - if (msg == null) + Message selected = filteredList.getSelected(); + if (selected == null) return; - String newName = promptForUniqueName(msg.name); + String newName = promptForUniqueName(selected.name); if (newName != null) { - msg.name = newName; + selected.name = newName; filteredList.repaint(); } } - public void createMessage() + public void setMessageSection() { + Message selected = filteredList.getSelected(); + if (selected == null) + return; - List resources = new ArrayList<>(); - - try { - int sectionID = 0; - for (AssetHandle ah : AssetManager.getMessages()) { - Logger.log("Reading strings from: " + ah.getName()); - resources.add(new MessageGroup(ah, sectionID++)); + String newSection = SwingUtils.getInputDialog() + .setTitle("Choose Message Section") + .setMessage("Enter the new message section (hex)") + .setMessageType(JOptionPane.QUESTION_MESSAGE) + .setDefault(String.format("%02X", selected.section)) + .prompt(); + + if (newSection != null) { + try { + selected.section = Integer.parseInt(newSection, 16); + filteredList.repaint(); + } + catch (NumberFormatException e) { + Toolkit.getDefaultToolkit().beep(); + Logger.logError(newSection + " is not a valid section!"); } } - catch (IOException e) { - Logger.logError(e.getMessage()); - } - - //TODO filteredList.setContent(resources); } public String promptForUniqueName(String originalName) { - String name = SwingUtils.showFramedInputDialog(null, - "Provide a message name", - "Name New Message", - JOptionPane.QUESTION_MESSAGE); + while (true) { + String name = SwingUtils.getInputDialog() + .setTitle("Choose Message Name") + .setMessage("Choose a unique message name") + .setMessageType(JOptionPane.QUESTION_MESSAGE) + .setDefault(originalName) + .prompt(); + + if (name == null || name.isBlank()) { + // empty name provided + return null; + } - if (name == null || name.isBlank()) { + if (originalName != null && name.equals(originalName)) { + // name did not change + return originalName; + } - } + if (!editor.hasMessage(name)) { + // name is unique + return name; + } - return name; //TODO + SwingUtils.getWarningDialog() + .setTitle("Name Conflict") + .setMessage(name + " is already in use!") + .show(); + } } - public void setStrings(List messages) + public void setAsset(MessageAsset asset) { - filteredList.setContent(messages); + this.asset = asset; + + if (asset == null) { + filteredList.setContent(null); + } + else { + filteredList.setContent(asset.messages); + } } private static class MessageCellRenderer extends JPanel implements ListCellRenderer diff --git a/src/main/java/game/message/editor/StringPrinter.java b/src/main/java/game/message/editor/MessagePrinter.java similarity index 99% rename from src/main/java/game/message/editor/StringPrinter.java rename to src/main/java/game/message/editor/MessagePrinter.java index fac561e..20e06c4 100644 --- a/src/main/java/game/message/editor/StringPrinter.java +++ b/src/main/java/game/message/editor/MessagePrinter.java @@ -15,10 +15,10 @@ import game.message.StringConstants.StringStyle; import game.message.StringEncoder; import game.message.editor.MessageUtil.StringProperties; -import game.message.editor.StringTokenizer.Sequence; +import game.message.editor.MessageTokenizer.Sequence; import util.MathUtil; -public class StringPrinter +public class MessagePrinter { private MessageEditor editor; @@ -387,7 +387,7 @@ public void drawMessageBox() } } - public StringPrinter(MessageEditor editor) + public MessagePrinter(MessageEditor editor) { this.editor = editor; setStyle(StringStyle.RIGHT, null); // initialize parameters for default window style diff --git a/src/main/java/game/message/editor/MessageRenderer.java b/src/main/java/game/message/editor/MessageRenderer.java index 89037e2..4f22425 100644 --- a/src/main/java/game/message/editor/MessageRenderer.java +++ b/src/main/java/game/message/editor/MessageRenderer.java @@ -1,73 +1,1240 @@ package game.message.editor; +import static game.message.StringConstants.StringEffect.*; +import static game.texture.TileFormat.CI_8; +import static org.lwjgl.opengl.GL11.*; + +import java.awt.image.BufferedImage; +import java.io.File; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.List; +import java.util.Random; + +import org.lwjgl.BufferUtils; +import assets.ExpectedAsset; +import game.SimpleItem; +import game.map.Axis; +import game.map.editor.common.MouseInput; +import game.map.editor.geometry.Vector3f; +import game.map.editor.render.PresetColor; +import game.map.editor.render.TextureManager; +import game.map.shape.TransformMatrix; +import game.message.MessageBoxes; import game.message.StringConstants; +import game.message.StringConstants.ControlCharacter; +import game.message.StringConstants.StringFunction; +import game.message.StringConstants.StringStyle; import game.message.font.FontManager; import game.message.font.FontType; +import game.sprite.ImgAsset; +import game.sprite.Sprite; +import game.sprite.SpriteLoader; +import game.sprite.SpriteLoader.SpriteSet; +import game.sprite.SpriteRaster; +import game.texture.ImageConverter; +import game.texture.Palette; +import game.texture.Texture; +import game.texture.Tile; +import renderer.GLUtils; +import renderer.buffers.LineRenderQueue; +import renderer.shaders.BaseShader; +import renderer.shaders.RenderState; import renderer.shaders.ShaderManager; +import renderer.shaders.scene.BasicIndexedShader; +import renderer.shaders.scene.BasicSolidShader; +import renderer.shaders.scene.BasicTexturedShader; import renderer.shaders.scene.FontShader; +import util.Logger; public class MessageRenderer { - private static final int FONT_SIZE_X = 16; - private static final int FONT_SIZE_Y = 16; + private final MessageEditor editor; + + public final TransformMatrix projMatrix; + public final TransformMatrix viewMatrix; + + private int glBackgroundTexID; + private int glNoiseTexID; + + private Random rng; + private boolean useFiltering = true; + + private int frameCounter = 0; + + // extra resources + private final SpriteLoader spriteLoader; + private Tile[] glItemPreviews = null; + + private BufferedImage varImage = null; + private boolean varImageLoaded = false; + private int glVarTexID; + + public MessageRenderer(MessageEditor editor) throws IOException + { + this.editor = editor; + + projMatrix = new TransformMatrix(); + viewMatrix = new TransformMatrix(); + + rng = new Random(); + loadTextures(); + loadItemIcons(); + + spriteLoader = new SpriteLoader(); + } + + public void cleanup() + { + MessageBoxes.glDelete(); + FontManager.glDelete(); + + glDeleteTextures(glBackgroundTexID); + glDeleteTextures(glNoiseTexID); + glDeleteTextures(glVarTexID); + + if (glItemPreviews != null) { + for (Tile tile : glItemPreviews) { + if (tile == null) + continue; + + tile.glDelete(); + tile.palette.glDelete(); + } + } + } + + private void loadTextures() throws IOException + { + Tile img; + BufferedImage bimg; + + glLoadNoise(); + + // background + try { + File imgFile = ExpectedAsset.KMR_BG.getFile(); + img = Tile.load(imgFile, CI_8); + bimg = ImageConverter.convertToBufferedImage(img); + glBackgroundTexID = glLoadImage(bimg); + } + catch (IOException e) { + Logger.logError("Could not load background asset: " + ExpectedAsset.KMR_BG.getPath()); + } + + MessageBoxes.loadImages(); + MessageBoxes.glLoad(); + + FontManager.loadData(); + FontManager.glLoad(); + } + + private void glLoadNoise() + { + BufferedImage bimg = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); + for (int i = 0; i < 256; i++) + for (int j = 0; j < 256; j++) { + int I = rng.nextInt() & 0xFF; + bimg.setRGB(i, j, (0xFF << 24) | (I << 16) | (I << 8) | I); + } + + ByteBuffer buffer = TextureManager.createByteBuffer(bimg); + + int glID = glGenTextures(); + glBindTexture(GL_TEXTURE_2D, glID); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, bimg.getWidth(), + bimg.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + glNoiseTexID = glID; + } + + private void loadItemIcons() throws IOException + { + List items = game.ProjectDatabase.getItemList(); + + glItemPreviews = new Tile[items.size()]; + for (int i = 0; i < items.size(); i++) { + Tile tile = items.get(i).iconTile; + if (tile == null) + continue; + + tile.glLoad(Texture.WRAP_CLAMP, Texture.WRAP_CLAMP, false); + tile.palette.glLoad(); + + glItemPreviews[i] = tile; + } + + Logger.log("Loaded icon previews"); + } + + public void setVarImage(BufferedImage bimg) + { + if (varImageLoaded) + glDeleteTextures(glVarTexID); + + glVarTexID = glLoadImage(bimg); + varImage = bimg; + varImageLoaded = true; + } + + private static int glLoadImage(BufferedImage bimg) + { + ByteBuffer buffer = TextureManager.createByteBuffer(bimg); + + int glID = glGenTextures(); + glBindTexture(GL_TEXTURE_2D, glID); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, bimg.getWidth(), + bimg.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + return glID; + } + + private final void drawBackground(int glTexID) + { + projMatrix.ortho(0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f); + RenderState.setProjectionMatrix(projMatrix); + RenderState.setViewMatrix(null); + + float hfov = 105; + float right = (hfov + 360) / 360; + float scaleX = RenderState.getViewportSizeX() / 600.0f; + + BasicTexturedShader shader = ShaderManager.use(BasicTexturedShader.class); + shader.texture.bind(glTexID); + shader.setXYQuadCoords(0, 0, 1, 1, 0); + shader.setQuadTexCoords(0, 1, right * scaleX, 0); + shader.renderQuad(); + } + + private static void drawGrid(MessagePrinter printer) + { + RenderState.setLineWidth(1.5f); + + int xstart = printer.windowBasePosX + printer.windowTextStartX; + int ystart = printer.windowBasePosY + printer.windowTextStartY; + int xmax = ((printer.clipMaxX - xstart) / 10) * 10; + int ymax = ((printer.clipMaxY - ystart) / 10) * 10; + + for (int i = 0; i <= xmax; i += 10) { + float alpha = ((i % 20) == 0) ? 0.5f : 0.2f; + int v1 = LineRenderQueue.addVertex() + .setPosition(xstart + i, ystart, 0) + .setColor(0.15f, 0.15f, 0.15f, alpha) + .getIndex(); + int v2 = LineRenderQueue.addVertex() + .setPosition(xstart + i, ystart + ymax, 0) + .setColor(0.15f, 0.15f, 0.15f, alpha) + .getIndex(); + LineRenderQueue.addLine(v1, v2); + } + + for (int i = 0; i <= ymax; i += 10) { + float alpha = ((i % 20) == 0) ? 0.5f : 0.2f; + int v1 = LineRenderQueue.addVertex() + .setPosition(xstart, ystart + i, 0) + .setColor(0.15f, 0.15f, 0.15f, alpha) + .getIndex(); + int v2 = LineRenderQueue.addVertex() + .setPosition(xstart + xmax, ystart + i, 0) + .setColor(0.15f, 0.15f, 0.15f, alpha) + .getIndex(); + LineRenderQueue.addLine(v1, v2); + } + + RenderState.setDepthWrite(false); + LineRenderQueue.render(true); + RenderState.setDepthWrite(true); + } + + private static void drawBackgroundGuide(MessagePrinter printer) + { + int v1, v2, v3, v4; + RenderState.setLineWidth(2.0f); + + RenderState.setColor(PresetColor.RED); + v1 = LineRenderQueue.addVertex().setPosition(0, 0, 0).getIndex(); + v2 = LineRenderQueue.addVertex().setPosition(320, 0, 0).getIndex(); + v3 = LineRenderQueue.addVertex().setPosition(320, 240, 0).getIndex(); + v4 = LineRenderQueue.addVertex().setPosition(0, 240, 0).getIndex(); + LineRenderQueue.addLine(v1, v2, v3, v4, v1); + + RenderState.setColor(PresetColor.BLUE); + v1 = LineRenderQueue.addVertex().setPosition(12, 20, 0).getIndex(); + v2 = LineRenderQueue.addVertex().setPosition(320 - 12, 20, 0).getIndex(); + v3 = LineRenderQueue.addVertex().setPosition(320 - 12, 240 - 20, 0).getIndex(); + v4 = LineRenderQueue.addVertex().setPosition(12, 240 - 20, 0).getIndex(); + LineRenderQueue.addLine(v1, v2, v3, v4, v1); + + // LineRenderQueue.printContents(); + + RenderState.setDepthWrite(false); + LineRenderQueue.render(true); + RenderState.setDepthWrite(true); + } + + private static void drawForegroundGuide(MessagePrinter printer) + { + int v1, v2, v3, v4; + RenderState.setLineWidth(1.5f); + + RenderState.setColor(PresetColor.GREEN); + v1 = LineRenderQueue.addVertex().setPosition(printer.windowBasePosX, printer.windowBasePosY, 0).getIndex(); + v2 = LineRenderQueue.addVertex().setPosition(printer.windowBasePosX, printer.windowBasePosY + printer.windowSizeY, 0).getIndex(); + v3 = LineRenderQueue.addVertex().setPosition(printer.windowBasePosX + printer.windowSizeX, printer.windowBasePosY + printer.windowSizeY, 0) + .getIndex(); + v4 = LineRenderQueue.addVertex().setPosition(printer.windowBasePosX + printer.windowSizeX, printer.windowBasePosY, 0).getIndex(); + LineRenderQueue.addLine(v1, v2, v3, v4, v1); + + RenderState.setColor(PresetColor.TEAL); + v1 = LineRenderQueue.addVertex().setPosition(printer.rewindArrowX, printer.rewindArrowY, 0).getIndex(); + v2 = LineRenderQueue.addVertex().setPosition(printer.rewindArrowX, printer.rewindArrowY + 24, 0).getIndex(); + v3 = LineRenderQueue.addVertex().setPosition(printer.rewindArrowX + 24, printer.rewindArrowY + 24, 0).getIndex(); + v4 = LineRenderQueue.addVertex().setPosition(printer.rewindArrowX + 24, printer.rewindArrowY, 0).getIndex(); + LineRenderQueue.addLine(v1, v2, v3, v4, v1); + + RenderState.setColor(PresetColor.YELLOW); + v1 = LineRenderQueue.addVertex().setPosition(printer.clipMinX, printer.clipMinY, 0).getIndex(); + v2 = LineRenderQueue.addVertex().setPosition(printer.clipMinX, printer.clipMaxY, 0).getIndex(); + v3 = LineRenderQueue.addVertex().setPosition(printer.clipMaxX, printer.clipMaxY, 0).getIndex(); + v4 = LineRenderQueue.addVertex().setPosition(printer.clipMaxX, printer.clipMinY, 0).getIndex(); + LineRenderQueue.addLine(v1, v2, v3, v4, v1); + + RenderState.setDepthWrite(false); + LineRenderQueue.render(true); + RenderState.setDepthWrite(true); + } + + private static final void drawAxes(float lineWidth) + { + RenderState.setLineWidth(lineWidth); + + RenderState.setColor(PresetColor.RED); + LineRenderQueue.addLine( + LineRenderQueue.addVertex().setPosition(0, 0, 0).getIndex(), + LineRenderQueue.addVertex().setPosition(Short.MAX_VALUE, 0, 0).getIndex()); + + RenderState.setColor(PresetColor.GREEN); + LineRenderQueue.addLine( + LineRenderQueue.addVertex().setPosition(0, 0, 0).getIndex(), + LineRenderQueue.addVertex().setPosition(0, Short.MAX_VALUE, 0).getIndex()); + + LineRenderQueue.render(true); + } + + public Vector3f getMousePosition(MouseInput mouse, boolean useDepth) + { + int mouseX = mouse.getPosX(); + int mouseY = mouse.getPosY(); + + int width = editor.glCanvasWidth(); + int height = editor.glCanvasHeight(); + + IntBuffer viewport = BufferUtils.createIntBuffer(16); + viewport.put(0); + viewport.put(0); + viewport.put(width); + viewport.put(height); + viewport.rewind(); + + float winX = mouseX; + float winY = mouseY; + float winZ = 0; + + if (useDepth) { + // this is the expensive part, reading z from the depth buffer + FloatBuffer fb = BufferUtils.createFloatBuffer(1); + glReadPixels(mouseX, mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, fb); + winZ = fb.get(); + } + + FloatBuffer position = BufferUtils.createFloatBuffer(3); + GLUtils.gluUnProject(winX, winY, winZ, viewMatrix.toFloatBuffer(), projMatrix.toFloatBuffer(), viewport, position); + + return new Vector3f(position.get(), position.get(), position.get()); + } + + public void render(MouseInput mouse, MessagePrinter printer, float cameraX, float cameraY, float cameraZoom, float cameraYaw) + { + assert (printer != null); + + drawBackground(glBackgroundTexID); + + float halfW = (editor.glCanvasWidth() / 2.0f) * cameraZoom; + float halfH = (editor.glCanvasHeight() / 2.0f) * cameraZoom; + projMatrix.ortho(-halfW, halfW, halfH, -halfH, 1, 0x20000); + // projMatrix.perspective(60, (float)editor.glCanvasWidth() / editor.glCanvasHeight(), 1, 0x2000); + RenderState.setProjectionMatrix(projMatrix); + + viewMatrix.setIdentity(); + viewMatrix.translate(new Vector3f(-cameraX, -cameraY, -400.0f * cameraZoom)); + viewMatrix.rotate(Axis.Y, cameraYaw); + RenderState.setViewMatrix(viewMatrix); + RenderState.setModelMatrix(null); + + if (editor.shouldShowViewportGuides()) + drawBackgroundGuide(printer); + + // drawAxes(1.0f); + + DrawState state = new DrawState(printer); + state.useCulling = editor.isCullingEnabled(); + + printer.drawMessageBox(); + + FontShader shader = ShaderManager.use(FontShader.class); + shader.enableFiltering.set(useFiltering); + shader.fadeAlpha.set(1.0f); + + float scrollY = printer.scrollAmount * (state.currentFont.chars.defaultY * state.stringScaleY + printer.style.lineOffset); + int printOffsetX = 0; + int printOffsetY = -(int) (scrollY); + + state.printPosX = 0; + state.printPosY = 0; + printer.drawBuffer.rewind(); + + read_buf: + while (printer.drawBuffer.position() < printer.printPos) { + byte charByte = printer.drawBuffer.get(); + int charInt = charByte & 0xFF; + + if (charInt == MessagePrinter.PAGE_END_MARK) { + continue; + } + else if (charInt == MessagePrinter.BUFFER_FILL) { + break; // end of string + } + else if (charInt < 0xF0) { + int charWidth = MessageUtil.getCharWidth(state.currentFont, state.fontVariant, charInt, state.stringScaleX, state.charWidthOverride, + 0); + if (charInt < state.currentFont.chars.numChars) + renderChar(printer, state, printOffsetX, printOffsetY, charInt); + state.printPosX += charWidth; + } + else if (charInt == 0xF7 || charInt == 0xF8 || charInt == 0xF9) { + int charWidth = MessageUtil.getCharWidth(state.currentFont, state.fontVariant, charInt, state.stringScaleX, state.charWidthOverride, + 0); + state.printPosX += charWidth; + } + else { + switch (ControlCharacter.decodeMap.get(charByte)) { + case ENDL: // 0xF0 + state.printPosX = 0; + state.printPosY += state.currentFont.chars.defaultY * state.stringScaleY + printer.style.lineOffset; + break; + + case NEXT: // 0xFB + break; + + case WAIT: // 0xF1 + throw new IllegalStateException(this.getClass().getSimpleName() + " should not encounter WAIT"); + + case PAUSE: // 0xF2 + printer.drawBuffer.get(); + throw new IllegalStateException(this.getClass().getSimpleName() + " should not encounter PAUSE"); + + case VARIANT0: // 0xF3 + case VARIANT1: // 0xF4 + case VARIANT2: // 0xF5 + case VARIANT3: // 0xF6 + state.fontVariant = charInt - 0xF3; + break; + + // 0xF7-0xF9 are spaces + // 0xFA = unknown + + case STYLE: // 0xFC + handleStyle(printer, state); + break; + + case END: // 0xFD + break read_buf; + + // 0xFE = unused afaik + case FUNC: // 0xFF + handleFunction(printer, state, printOffsetX, printOffsetY); + break; + } + } + } + + frameCounter++; + + RenderState.setModelMatrix(null); + if (editor.shouldShowGrid()) + drawGrid(printer); + + // drawForegroundGuide(printer); + + drawUI(mouse, printer); + } - public static void init() throws IOException + private void drawUI(MouseInput mouse, MessagePrinter printer) { - if (!FontManager.isLoaded()) - FontManager.loadData(); + // set UI matrices + TransformMatrix mtx = TransformMatrix.identity(); + mtx.ortho(0, editor.glCanvasWidth(), 0, editor.glCanvasHeight(), -1, 1); + RenderState.setProjectionMatrix(mtx); + RenderState.setViewMatrix(null); + RenderState.setModelMatrix(null); - if (!FontManager.isReadyForGL()) - FontManager.glLoad(); + RenderState.enableDepthTest(false); + + if (mouse.hasLocation()) { + Vector3f worldPos = getMousePosition(mouse, false); + int mx = Math.round(worldPos.x) - (printer.windowBasePosX + printer.windowTextStartX); + int my = Math.round(worldPos.y) - (printer.windowBasePosY + printer.windowTextStartY); + drawString(0x14, 8, editor.glCanvasHeight() - 4, 16, String.format("Cursor Pos: %3d, %2d", mx, my)); + } + + float bufferFillPercent = 100.0f * printer.compiledLength / MessagePrinter.MAX_LENGTH; + + if (bufferFillPercent > 100.0f) { + drawString(0x12, 176, editor.glCanvasHeight() - 4, 16, String.format("ERROR: String buffer at %.1f%% capacity! (%d/%d)", + bufferFillPercent, printer.compiledLength, MessagePrinter.MAX_LENGTH)); + } + else if (bufferFillPercent > 75.0f) { + int palID = 5; + if (bufferFillPercent > 90.0f) + palID = 6; + if (bufferFillPercent > 95.0f) + palID = 7; + drawString(palID, 176, editor.glCanvasHeight() - 4, 16, String.format("WARNING: String buffer at %.1f%% capacity! (%d/%d)", + bufferFillPercent, printer.compiledLength, MessagePrinter.MAX_LENGTH)); + } + + RenderState.enableDepthTest(true); + } + + private void handleStyle(MessagePrinter printer, DrawState state) + { + switch (StringStyle.decodeMap.get(printer.drawBuffer.get())) { + case RIGHT: + case LEFT: + case CENTER: + case TATTLE: + case CHOICE: + state.textColor = 0xA; + break; + case INSPECT: + case UPGRADE: + case NARRATE: + case STYLE_F: + state.textColor = 0; + break; + case SIGN: + state.textColor = 0x18; + break; + case LAMPPOST: + state.textColor = 0x1C; + break; + case POSTCARD: + case POPUP: + case STYLE_B: + state.textColor = 0; + break; + case EPILOGUE: + state.textColor = 0; + break; + } } - public void drawString(int posX, int posY, int size, String text) + private void handleFunction(MessagePrinter printer, DrawState state, int relativePosX, int relativePosY) + { + int startX = state.getScreenPosX(relativePosX); + int startY = state.getScreenPosY(relativePosY); + StringFunction func = StringFunction.decodeMap.get(printer.drawBuffer.get()); + + switch (func) { + case CURSOR: + case OPTION: + case SET_CANCEL: + case END_CHOICE: + printer.drawBuffer.get(); + break; // completely ignored by editor + + case VAR: + printer.drawBuffer.get(); + break; // already handled during encoding + + case FONT: + int fontType = (printer.drawBuffer.get() & 0xFF); + switch (fontType) { + case 0: + state.currentFont = FontType.Normal; + break; + case 1: + state.currentFont = FontType.Menus; + break; + case 2: + state.currentFont = FontType.Menus; + break; + case 3: + state.currentFont = FontType.Title; + break; + case 4: + state.currentFont = FontType.Subtitle; + break; + } + break; + + case VARIANT: + state.fontVariant = (printer.drawBuffer.get() & 0xFF); + break; + + case ANIM_DONE: + if (printer.hasAnim()) { + int spriteID = printer.getAnimSprite(); + int rasterID = printer.getAnimRaster(); + + Sprite npc = spriteLoader.getSprite(SpriteSet.Npc, spriteID); + if (npc != null && !npc.areTexturesLoaded()) + npc.loadTextures(); + + if (npc != null && npc.rasters.getSize() > rasterID) { + BasicIndexedShader shader = ShaderManager.use(BasicIndexedShader.class); + SpriteRaster raster = npc.rasters.get(rasterID); + ImgAsset front = raster.getFront(); + if (front != null) { + front.img.glBind(shader.texture); + front.getPalette().glBind(shader.palette); + drawClippedQuad(shader, state, startX, startX + front.img.width, startY, startY + front.img.height); + } + } + else { + BasicSolidShader shader = ShaderManager.use(BasicSolidShader.class); + float f = 0.5f + (float) Math.cos(Math.toRadians(16 * frameCounter)) * 0.25f; + shader.baseColor.set(1.0f, f, f, 1.0f); + drawClippedQuad(shader, state, startX, startX + 0x20, startY, startY + 0x40); + } + } + break; + + case IMAGE: + printer.drawBuffer.get(); // index -- ignored + int posX = printer.drawBuffer.getShort() & 0xFFFF; + int posY = printer.drawBuffer.get() & 0xFF; + int border = printer.drawBuffer.get() & 0xFF; + int alpha = printer.drawBuffer.get() & 0xFF; + int alphaStep = printer.drawBuffer.get() & 0xFF; + + if (varImageLoaded) { + BasicTexturedShader shader = ShaderManager.use(BasicTexturedShader.class); + shader.texture.bind(glVarTexID); + shader.multiplyBaseColor.set(true); + shader.baseColor.set(1.0f, 1.0f, 1.0f, alpha / 255.0f); + drawQuad(shader, posX, posX + varImage.getWidth(), posY, posY + varImage.getHeight()); + } + else { + BasicSolidShader shader = ShaderManager.use(BasicSolidShader.class); + float f = 0.5f + (float) Math.cos(Math.toRadians(16 * frameCounter)) * 0.25f; + shader.baseColor.set(1.0f, f, f, alpha / 255.0f); + drawQuad(shader, posX, posX + 150, posY, posY + 105); + } + break; + + case HIDE_IMAGE: + printer.drawBuffer.get(); // fade out time + break; + + case INLINE_IMAGE: + printer.drawBuffer.get(); // index -- ignored + + if (varImageLoaded) { + BasicTexturedShader shader = ShaderManager.use(BasicTexturedShader.class); + shader.texture.bind(glVarTexID); + drawClippedQuad(shader, state, startX, startX + varImage.getWidth(), startY, startY + varImage.getHeight()); + } + else { + BasicSolidShader shader = ShaderManager.use(BasicSolidShader.class); + float f = 0.5f + (float) Math.cos(Math.toRadians(16 * frameCounter)) * 0.25f; + shader.baseColor.set(1.0f, f, f, 1.0f); + drawClippedQuad(shader, state, startX, startX + 0x40, startY, startY + 0x40); + } + break; + + case ITEM_ICON: + int upperItemID = (printer.drawBuffer.get() & 0xFF); + int lowerItemID = (printer.drawBuffer.get() & 0xFF); + int itemID = (upperItemID << 8) | lowerItemID; + + if (glItemPreviews != null && glItemPreviews.length > itemID && glItemPreviews[itemID] != null) { + BasicIndexedShader shader = ShaderManager.use(BasicIndexedShader.class); + glItemPreviews[itemID].glBind(shader.texture); + glItemPreviews[itemID].palette.glBind(shader.palette); + drawClippedQuad(shader, state, startX, startX + 0x20, startY, startY + 0x20); + } + else { + BasicSolidShader shader = ShaderManager.use(BasicSolidShader.class); + float f = 0.5f + (float) Math.cos(Math.toRadians(16 * frameCounter)) * 0.25f; + shader.baseColor.set(1.0f, f, f, 1.0f); + drawClippedQuad(shader, state, startX, startX + 0x20, startY, startY + 0x20); + } + break; + + case COLOR: + state.textColor = (printer.drawBuffer.get() & 0xFF); + if (state.textColor < 0) + state.textColor = 0; + int numPals = state.currentFont.chars.numPals; + if (state.textColor >= numPals) + state.textColor = numPals - 1; + break; + + case PUSH_COLOR: + state.savedColor = state.textColor; + break; + case POP_COLOR: + state.textColor = state.savedColor; + break; + + case PUSH_POS: + state.savedPosX = state.printPosX; + state.savedPosY = state.printPosY; + break; + case POP_POS: + state.printPosX = state.savedPosX; + state.printPosY = state.savedPosY; + break; + + case SPACING: + state.charWidthOverride = (printer.drawBuffer.get() & 0xFF); + break; + + case SIZE: + int sx = (printer.drawBuffer.get() & 0xFF); + int sy = (printer.drawBuffer.get() & 0xFF); + state.stringScaleX = sx / 16.0f; + state.stringScaleY = sy / 16.0f; + state.charScaleX = state.stringScaleX; + state.charScaleY = state.stringScaleY; + break; + case SIZE_RESET: + state.stringScaleX = 1.0f; + state.stringScaleY = 1.0f; + state.charScaleX = state.stringScaleX; + state.charScaleY = state.stringScaleY; + break; + + case SET_X: // [80129EB4] + int upper = (printer.drawBuffer.get() & 0xFF); + int lower = (printer.drawBuffer.get() & 0xFF); + state.printPosX = (upper << 8) | lower; + break; + case SET_Y: // [80129ED8] + state.printPosY = (printer.drawBuffer.get() & 0xFF); + break; + case RIGHT: // [80129F0C] + state.printPosX += (printer.drawBuffer.get() & 0xFF); + break; + case DOWN: // [80129F38] + state.printPosY += (printer.drawBuffer.get() & 0xFF); + break; + case UP: // [80129F64] + state.printPosY -= (printer.drawBuffer.get() & 0xFF); + break; + case CENTER_X: // [8012AAEC] + state.centerPos = (printer.drawBuffer.get() & 0xFF); + break; + + case START_FX: + int startFXType = (printer.drawBuffer.get() & 0xFF); + state.effectActive[startFXType] = true; + switch (startFXType) { + case 0x2: + state.effectActive[3] = false; + break; + case 0x3: + state.effectActive[2] = false; + state.fadeNoiseAlpha = (printer.drawBuffer.get() & 0xFF) / 255.0f; + break; + case 0x5: + state.fadeJitterArg = (printer.drawBuffer.get() & 0xFF); + break; + case 0x7: + state.fadeAlpha = (printer.drawBuffer.get() & 0xFF) / 255.0f; + break; + case 0x6: + case 0x9: + state.savedFxColor = state.textColor; + break; + case 0xC: + case 0xD: + state.savedFxCharScaleX = state.charScaleX; + state.savedFxCharScaleY = state.charScaleY; + break; + } + break; + + case END_FX: + int endFXType = (printer.drawBuffer.get() & 0xFF); + // restore saved state (if it has been saved) + if (state.effectActive[endFXType]) { + switch (endFXType) { + case 0x2: + case 0x3: + // end clears the flags for these, + // but will not stop the effect since its + // part of the display list + break; + case 0x6: + case 0x9: + state.textColor = state.savedFxColor; + state.effectActive[endFXType] = false; + break; + case 0xC: + case 0xD: + state.charScaleX = state.savedFxCharScaleX; + state.charScaleY = state.savedFxCharScaleY; + state.effectActive[endFXType] = false; + break; + default: + state.effectActive[endFXType] = false; + } + } + break; + + case FUNC_03: + //XXX unknown, some graphics state reset? + break; + + case SETVOICE: + case VOICE: + case VOLUME: + case SPEED: + case SCROLL: + case DELAY_OFF: + case DELAY_ON: + case SKIP_OFF: + case INPUT_OFF: + case INPUT_ON: + case ENABLE_CDOWN: + break; // irrelevant to renderer + + case SET_REWIND: + printer.drawBuffer.get(); + break; // irrelevant to renderer + + case YIELD: + break; + + case SET_CURSOR: + break; + + case ANIM_SPRITE: + case ANIM_DELAY: + case ANIM_LOOP: + throw new IllegalStateException("LOGIC ERROR: " + func.name + " in encodeFunctionArgs!"); + } + } + + public void drawString(int palID, int posX, int posY, int size, String text) { FontShader shader = ShaderManager.use(FontShader.class); shader.noiseMode.set(0); shader.fadeAlpha.set(1.0f); shader.enableDropShadow.set(false); + FontType font = FontType.Normal; + for (char c : text.toCharArray()) { int index = StringConstants.getIndex(c, true); if (index < 0) continue; - int endX = posX + (int) (FONT_SIZE_X * size / 16.0f); - int endY = posY - (int) (FONT_SIZE_Y * size / 16.0f); - int charWidth = getCharWidth(FontType.Normal, 0, index, size / 16.0f); + int endX = posX + (int) (font.chars.defaultX * size / 16.0f); + int endY = posY - (int) (font.chars.defaultY * size / 16.0f); + int charWidth = MessageUtil.getCharWidth(font, 0, index, size / 16.0f, 0, 0); - if (index < FontType.Normal.chars.numChars) { - FontType.Normal.chars.images[index].glBind(shader.texture); - FontType.Normal.chars.palettes[0x14].glBind(shader.palette); - shader.setQuadTexCoords(0, 0, 1, 1); - shader.setXYQuadCoords(posX, posY, endX, endY, 0); // y flipped - shader.renderQuad(); + if (index < font.chars.numChars) { + font.chars.images[index].glBind(shader.texture); + font.chars.palettes[palID].glBind(shader.palette); + drawQuad(shader, posX, endX, posY, endY); } posX += charWidth; } } - private static int getCharWidth(FontType font, int subfont, int index, float stringScale) + private void renderChar(MessagePrinter printer, DrawState state, int relativePosX, int relativePosY, int charIndex) + { + FontShader shader = ShaderManager.use(FontShader.class); + + int[] lookahead = new int[4]; + for (int i = 0; i < lookahead.length; i++) + lookahead[i] = (printer.drawBuffer.get() & 0xFF); + printer.drawBuffer.position(printer.drawBuffer.position() - lookahead.length); + + //XXX correct? + state.charScaleX = state.stringScaleX; + state.charScaleY = state.stringScaleY; + float alpha = 1.0f; + + if (state.effectActive[BLUR.code]) // 0x20 + { + // fade code from [8012ADC4] + alpha = 0.35f; + } + + if (state.effectActive[SHAKE.code]) { + // code from [8012AE50] + relativePosX += rng.nextInt() % 2; + relativePosY += rng.nextInt() % 2; + } + + if (state.effectActive[WAVE.code]) // 0x2 + { + // code from [8012AEBC] + double dsx = state.stringScaleX - 1.0; + double dsy = state.stringScaleY - 1.0; + + //NOTE: game uses a message-specific 'local' frame counter here + double angle = frameCounter * (int) (20.0 - dsx * 5.0) - state.visibleCharCount * (int) (45.0 - dsx * 15.0); + relativePosX += Math.cos(Math.toRadians(angle)) * (dsx + 1.6); + relativePosY += Math.cos(Math.toRadians(angle + 270.0)) * (dsy + 1.6); + } + if (state.effectActive[GLOBAL_WAVE.code]) // 0x200 + { + // code from [8012B0BC] + double dsx = state.stringScaleX - 1.0; + double dsy = state.stringScaleY - 1.0; + + //NOTE: game uses a 'global' frame counter shared by all messages here + double angle = frameCounter * (int) (20.0 - dsx * 5.0) - state.visibleCharCount * 45.0; + relativePosX += Math.cos(Math.toRadians(angle)) * (dsx + 1.6); + relativePosY += Math.cos(Math.toRadians(angle + 270.0)) * (dsy + 1.6); + } + + if (state.effectActive[RAINBOW.code] || state.effectActive[GLOBAL_RAINBOW.code]) // 0x440 -- either rainbow + { + // code from [8012B1B4] + + // NOTE: global overrides local here, but they cant stack so we dont need to represent it + int i = Math.abs(state.visibleCharCount - frameCounter / 3); + state.textColor = i % 10; // original code: = i + (i / 10) * -10; + } + + // properly respect precedence of these effects + if (state.effectActive[RISE_PRINT.code] || state.effectActive[GROW_PRINT.code]) { + if (!printer.donePrinting + && (lookahead[0] != ControlCharacter.ENDL.code) && (lookahead[1] != ControlCharacter.ENDL.code) + && (lookahead[2] != ControlCharacter.ENDL.code) && (lookahead[3] != ControlCharacter.ENDL.code)) { + if (state.effectActive[RISE_PRINT.code]) { + // from [8012B4F0] + float dummyScale = 0.25f; //XXX needed to match, unknown why + if (lookahead[0] == MessagePrinter.BUFFER_FILL) { + state.charScaleX = 1.7f * state.stringScaleX; + state.charScaleY = 1.7f * state.stringScaleY; + relativePosX -= 6.0f * state.stringScaleY; + relativePosY -= dummyScale * 6.0f * state.stringScaleY; + } + else if (lookahead[1] == MessagePrinter.BUFFER_FILL) { + state.charScaleX = 1.4f * state.stringScaleX; + state.charScaleY = 1.4f * state.stringScaleY; + relativePosX -= 3.0f * state.stringScaleY; + relativePosY -= dummyScale * 3.0f * state.stringScaleY; + } + else if (lookahead[2] == MessagePrinter.BUFFER_FILL) { + state.charScaleX = 1.2f * state.stringScaleX; + state.charScaleY = 1.2f * state.stringScaleY; + relativePosX -= 2.0f * state.stringScaleY; + relativePosY -= dummyScale * 2.0f * state.stringScaleY; + } + } + else if (state.effectActive[GROW_PRINT.code]) { + // from [8012B740] + if (lookahead[0] == MessagePrinter.BUFFER_FILL) { + state.charScaleX = 0.3f * state.stringScaleX; + state.charScaleY = 0.3f * state.stringScaleY; + relativePosX += 5; + relativePosY += 5; + } + else if (lookahead[1] == MessagePrinter.BUFFER_FILL) { + state.charScaleX = 0.5f * state.stringScaleX; + state.charScaleY = 0.5f * state.stringScaleY; + relativePosX += 3; + relativePosY += 3; + } + else if (lookahead[2] == MessagePrinter.BUFFER_FILL) { + state.charScaleX = 0.75f * state.stringScaleX; + state.charScaleY = 0.75f * state.stringScaleY; + relativePosX += 2; + relativePosY += 2; + } + } + } + } + else if (state.effectActive[SIZE_JITTER.code] || state.effectActive[SIZE_WAVE.code]) { + float scale = 1.0f; + + if (state.effectActive[SIZE_JITTER.code]) // 0x2000 -- size jitter + { + // code from [8012B8BC] + scale = 0.75f + 0.5f * (rng.nextInt(101) / 100.0f); + } + else if (state.effectActive[SIZE_WAVE.code]) // 0x4000 -- size wave + { + // code from [8012BA24] + int i = (frameCounter - state.visibleCharCount) * 15; + scale = 1.0f + 0.25f * (float) Math.cos(Math.toRadians(i + ((i >> 3) / 45) * 360.0)); + } + + state.charScaleX *= scale; + state.charScaleY *= scale; + + if (scale >= 1.0) { + // [8012BACC] + int posOffset = (int) (scale * 8.0 - 8.5); + relativePosX -= posOffset; + relativePosY -= posOffset; + } + else { + // [8012BB7C] + int posOffset = (int) (8.0 - 8.0 * scale); + relativePosX += posOffset; + relativePosY += posOffset; + } + } + + shader.noiseMode.set(0); // initial value + + if (state.effectActive[DITHER_FADE.code]) //0x80 -- fade + { + alpha *= state.fadeAlpha; + shader.noiseMode.set(7); + shader.noiseAlpha.set(state.fadeAlpha); + shader.noiseOffset.set(rng.nextFloat(), rng.nextFloat()); + } + else { + if (state.effectActive[NOISE_OUTLINE.code]) // 0x04 -- noise + { + shader.noiseMode.set(2); + shader.noiseOffset.set(rng.nextFloat(), rng.nextFloat()); + + // add Gfx: + // SET_COMBINE FC70FEE1 FFFFF3F9 + + // color: G_CCMUX_NOISE * G_CCMUX_TEXEL0 + // alpha: G_ACMUX_TEXEL0 + } + + if (state.effectActive[STATIC.code]) // 0x10000 -- faded noise + { + shader.noiseMode.set(3); + shader.noiseAlpha.set(state.fadeNoiseAlpha); + shader.noiseOffset.set(rng.nextFloat(), rng.nextFloat()); + + // add Gfx: + // SET_ENVCOLOR FB000000 arg << 0x18 | arg << 0x10 | arg << 8; + // SET_COMBINE FC72FEE5 11FCF279 + + // color: (G_CCMUX_NOISE - G_CCMUX_TEXEL0) * G_CCMUX_ENVIRONMENT + G_CCMUX_TEXEL0 + // alpha: G_ACMUX_TEXEL0 + } + } + + shader.fadeAlpha.set(alpha); + + int baseOffset = 0; + if (state.fontVariant < state.currentFont.numVariants && state.fontVariant >= 0) + baseOffset = state.currentFont.baseHeightOffset[state.fontVariant]; + + int startX = state.getScreenPosX(relativePosX); + int startY = state.getScreenPosY(relativePosY + baseOffset); + int endX = startX + (int) (state.currentFont.chars.defaultX * state.charScaleX); + int endY = startY + (int) (state.currentFont.chars.defaultY * state.charScaleY); + + if (state.effectActive[DROP_SHADOW.code]) // 0x8000 -- drop shadow + { + shader.enableDropShadow.set(true); + drawFontQuad(shader, state, + state.currentFont.chars.images[charIndex], + state.currentFont.chars.palettes[state.getColor()], + startX + 2, endX + 2, startY + 2, endY + 2); + shader.enableDropShadow.set(false); + } + + if (state.effectActive[BLUR.code]) // 0x20 -- FadedJitter + { + // code from [8012BDF4] + for (int i = 0; i < 5; i++) { + int jx = (state.fadeJitterArg == 2) ? 0 : rng.nextInt(3) - 1; + int jy = (state.fadeJitterArg == 1) ? 0 : rng.nextInt(3) - 1; + + drawFontQuad(shader, state, + state.currentFont.chars.images[charIndex], + state.currentFont.chars.palettes[state.getColor()], + startX + jx, endX + jx, startY + jy, endY + jy); + } + } + else { + drawFontQuad(shader, state, + state.currentFont.chars.images[charIndex], + state.currentFont.chars.palettes[state.getColor()], + startX, endX, startY, endY); + } + + state.visibleCharCount++; + } + + private static class DrawState { - if (index < 0xFA) { - int width; - if ((index == 0xF7) || (index == 0xF8) || (index == 0xF9)) - width = font.fullspaceWidth[subfont]; + public final MessagePrinter printer; + + private FontType currentFont = FontType.Normal; + public int fontVariant = 0; + + private boolean[] effectActive; + private float fadeAlpha = 1.0f; + private float fadeNoiseAlpha = 0; + private int fadeJitterArg = 0; + + private int textColor = 0xA; + + private int visibleCharCount = 0; + + private boolean useCulling = true; + + private int printPosX = 0; + private int printPosY = 0; + + private int centerPos = 0; + + private int savedColor; + private int savedPosX = 0; + private int savedPosY = 0; + private int savedFxColor = -1; + private float savedFxCharScaleX = 1.0f; + private float savedFxCharScaleY = 1.0f; + + private int charWidthOverride = 0; + + private float charScaleX = 1.0f; + private float charScaleY = 1.0f; + + private float stringScaleX = 1.0f; + private float stringScaleY = 1.0f; + + private DrawState(MessagePrinter printer) + { + this.printer = printer; + effectActive = new boolean[StringConstants.StringEffect.values().length]; + } + + public int getColor() + { + switch (currentFont) { + case Normal: + case Menus: + default: + return textColor; + case Title: + case Subtitle: + return 0; + } + } + + public int getScreenPosX(int offsetX) + { + int centerOffset = 0; + if (centerPos == 0xFF) + centerOffset = 160 - (printer.stringWidth / 2); + else if (centerPos != 0) + centerOffset = centerPos - (printer.stringWidth / 2); + + if (centerOffset == 0) + return printer.windowBasePosX + printer.windowTextStartX + printPosX + offsetX; else - width = font.chars.widths[index]; - - if (index == 0xF7) - return (int) ((width * stringScale) * 0.6); - if (index == 0xF8) - return (int) (width * stringScale); - if (index == 0xF9) - return (int) ((width * stringScale) * 0.5); - if (index >= 0xF0) - return 0; // other control chars - return (int) (width * stringScale); - } - return 0; + return centerOffset + printPosX + offsetX; + } + + public int getScreenPosY(int offsetY) + { + return printer.windowBasePosY + printer.windowTextStartY + printPosY + offsetY; + } + } + + private void drawFontQuad(FontShader shader, DrawState state, Tile img, Palette pal, float x1, float x2, float y1, float y2) + { + img.glBind(shader.texture); + pal.glBind(shader.palette); + shader.noise.bind(glNoiseTexID); + drawClippedQuad(shader, state, x1, x2, y1, y2); + } + + private static final void drawClippedQuad(BaseShader shader, DrawState state, float x1, float x2, float y1, float y2) + { + if (state.useCulling) + drawClippedQuad(shader, state.printer, x1, x2, y1, y2); + else + drawQuad(shader, x1, x2, y1, y2); + } + + private static final void drawClippedQuad(BaseShader shader, MessagePrinter printer, float x1, float x2, float y1, float y2) + { + float x1c = x1; + float x2c = x2; + + float y1c = y1; + float y2c = y2; + + float u1c = 0.0f; + float u2c = 1.0f; + + float v1c = 0.0f; + float v2c = 1.0f; + + assert (x1 < x2); + assert (y1 < y2); + + if ((x2 < printer.clipMinX) || (x1 > printer.clipMaxX) || (y2 < printer.clipMinY) || (y1 > printer.clipMaxY)) + return; + + if (x1 < printer.clipMinX) { + x1c = printer.clipMinX; + u1c = ((printer.clipMinX - x1) / (x2 - x1)); + } + + if (x2 > printer.clipMaxX) { + x2c = printer.clipMaxX; + u2c = 1.0f - ((x2 - printer.clipMaxX) / (x2 - x1)); + } + + if (y1 < printer.clipMinY) { + y1c = printer.clipMinY; + v2c = 1.0f - ((printer.clipMinY - y1) / (y2 - y1)); + } + + if (y2 > printer.clipMaxY) { + y2c = printer.clipMaxY; + v1c = ((y2 - printer.clipMaxY) / (y2 - y1)); + } + + shader.setQuadTexCoords(u1c, v1c, u2c, v2c); + shader.setXYQuadCoords(x1c, y2c, x2c, y1c, 0); // y flipped + shader.renderQuad(); + } + + private static final void drawQuad(BaseShader shader, float x1, float x2, float y1, float y2) + { + shader.setQuadTexCoords(0, 0, 1, 1); + shader.setXYQuadCoords(x1, y2, x2, y1, 0); // y flipped + shader.renderQuad(); } } diff --git a/src/main/java/game/message/editor/StringTokenizer.java b/src/main/java/game/message/editor/MessageTokenizer.java similarity index 95% rename from src/main/java/game/message/editor/StringTokenizer.java rename to src/main/java/game/message/editor/MessageTokenizer.java index 136a41c..0f96ea4 100644 --- a/src/main/java/game/message/editor/StringTokenizer.java +++ b/src/main/java/game/message/editor/MessageTokenizer.java @@ -8,12 +8,12 @@ import app.input.Line; import game.message.MessageAnim; -public class StringTokenizer +public class MessageTokenizer { public static void main(String[] args) { String text = "%This [is] [[a] [] TE\\\\\\ST[b"; - (new StringTokenizer(text)).print(); + (new MessageTokenizer(text)).print(); } private void print() @@ -28,20 +28,20 @@ private void print() public static ArrayList tokenize(String text) { - return new StringTokenizer(text).sequences; + return new MessageTokenizer(text).sequences; } public static ArrayList tokenize(List lines) { - return new StringTokenizer(lines).sequences; + return new MessageTokenizer(lines).sequences; } - private StringTokenizer(String text) + private MessageTokenizer(String text) { add(text, null); } - private StringTokenizer(List lines) + private MessageTokenizer(List lines) { for (Line line : lines) add(line.str, line); diff --git a/src/main/java/game/message/editor/SimpleMessageRenderer.java b/src/main/java/game/message/editor/SimpleMessageRenderer.java new file mode 100644 index 0000000..e6b7758 --- /dev/null +++ b/src/main/java/game/message/editor/SimpleMessageRenderer.java @@ -0,0 +1,73 @@ +package game.message.editor; + +import java.io.IOException; + +import game.message.StringConstants; +import game.message.font.FontManager; +import game.message.font.FontType; +import renderer.shaders.ShaderManager; +import renderer.shaders.scene.FontShader; + +public class SimpleMessageRenderer +{ + private static final int FONT_SIZE_X = 16; + private static final int FONT_SIZE_Y = 16; + + public static void init() throws IOException + { + if (!FontManager.isLoaded()) + FontManager.loadData(); + + if (!FontManager.isReadyForGL()) + FontManager.glLoad(); + } + + public void drawString(int posX, int posY, int size, String text) + { + FontShader shader = ShaderManager.use(FontShader.class); + shader.noiseMode.set(0); + shader.fadeAlpha.set(1.0f); + shader.enableDropShadow.set(false); + + for (char c : text.toCharArray()) { + int index = StringConstants.getIndex(c, true); + if (index < 0) + continue; + + int endX = posX + (int) (FONT_SIZE_X * size / 16.0f); + int endY = posY - (int) (FONT_SIZE_Y * size / 16.0f); + int charWidth = getCharWidth(FontType.Normal, 0, index, size / 16.0f); + + if (index < FontType.Normal.chars.numChars) { + FontType.Normal.chars.images[index].glBind(shader.texture); + FontType.Normal.chars.palettes[0x14].glBind(shader.palette); + shader.setQuadTexCoords(0, 0, 1, 1); + shader.setXYQuadCoords(posX, posY, endX, endY, 0); // y flipped + shader.renderQuad(); + } + posX += charWidth; + } + } + + private static int getCharWidth(FontType font, int subfont, int index, float stringScale) + { + if (index < 0xFA) { + int width; + if ((index == 0xF7) || (index == 0xF8) || (index == 0xF9)) + width = font.fullspaceWidth[subfont]; + else + width = font.chars.widths[index]; + + if (index == 0xF7) + return (int) ((width * stringScale) * 0.6); + if (index == 0xF8) + return (int) (width * stringScale); + if (index == 0xF9) + return (int) ((width * stringScale) * 0.5); + if (index >= 0xF0) + return 0; // other control chars + return (int) (width * stringScale); + } + return 0; + } +} diff --git a/src/main/java/game/message/editor/StringRenderer.java b/src/main/java/game/message/editor/StringRenderer.java deleted file mode 100644 index 4689437..0000000 --- a/src/main/java/game/message/editor/StringRenderer.java +++ /dev/null @@ -1,1240 +0,0 @@ -package game.message.editor; - -import static game.message.StringConstants.StringEffect.*; -import static game.texture.TileFormat.CI_8; -import static org.lwjgl.opengl.GL11.*; - -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.util.List; -import java.util.Random; - -import org.lwjgl.BufferUtils; - -import assets.ExpectedAsset; -import game.SimpleItem; -import game.map.Axis; -import game.map.editor.common.MouseInput; -import game.map.editor.geometry.Vector3f; -import game.map.editor.render.PresetColor; -import game.map.editor.render.TextureManager; -import game.map.shape.TransformMatrix; -import game.message.MessageBoxes; -import game.message.StringConstants; -import game.message.StringConstants.ControlCharacter; -import game.message.StringConstants.StringFunction; -import game.message.StringConstants.StringStyle; -import game.message.font.FontManager; -import game.message.font.FontType; -import game.sprite.ImgAsset; -import game.sprite.Sprite; -import game.sprite.SpriteLoader; -import game.sprite.SpriteLoader.SpriteSet; -import game.sprite.SpriteRaster; -import game.texture.ImageConverter; -import game.texture.Palette; -import game.texture.Texture; -import game.texture.Tile; -import renderer.GLUtils; -import renderer.buffers.LineRenderQueue; -import renderer.shaders.BaseShader; -import renderer.shaders.RenderState; -import renderer.shaders.ShaderManager; -import renderer.shaders.scene.BasicIndexedShader; -import renderer.shaders.scene.BasicSolidShader; -import renderer.shaders.scene.BasicTexturedShader; -import renderer.shaders.scene.FontShader; -import util.Logger; - -public class StringRenderer -{ - private final MessageEditor editor; - - public final TransformMatrix projMatrix; - public final TransformMatrix viewMatrix; - - private int glBackgroundTexID; - private int glNoiseTexID; - - private Random rng; - private boolean useFiltering = true; - - private int frameCounter = 0; - - // extra resources - private final SpriteLoader spriteLoader; - private Tile[] glItemPreviews = null; - - private BufferedImage varImage = null; - private boolean varImageLoaded = false; - private int glVarTexID; - - public StringRenderer(MessageEditor editor) throws IOException - { - this.editor = editor; - - projMatrix = new TransformMatrix(); - viewMatrix = new TransformMatrix(); - - rng = new Random(); - loadTextures(); - loadItemIcons(); - - spriteLoader = new SpriteLoader(); - } - - public void cleanup() - { - MessageBoxes.glDelete(); - FontManager.glDelete(); - - glDeleteTextures(glBackgroundTexID); - glDeleteTextures(glNoiseTexID); - glDeleteTextures(glVarTexID); - - if (glItemPreviews != null) { - for (Tile tile : glItemPreviews) { - if (tile == null) - continue; - - tile.glDelete(); - tile.palette.glDelete(); - } - } - } - - private void loadTextures() throws IOException - { - Tile img; - BufferedImage bimg; - - glLoadNoise(); - - // background - try { - File imgFile = ExpectedAsset.KMR_BG.getFile(); - img = Tile.load(imgFile, CI_8); - bimg = ImageConverter.convertToBufferedImage(img); - glBackgroundTexID = glLoadImage(bimg); - } - catch (IOException e) { - Logger.logError("Could not load background asset: " + ExpectedAsset.KMR_BG.getPath()); - } - - MessageBoxes.loadImages(); - MessageBoxes.glLoad(); - - FontManager.loadData(); - FontManager.glLoad(); - } - - private void glLoadNoise() - { - BufferedImage bimg = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); - for (int i = 0; i < 256; i++) - for (int j = 0; j < 256; j++) { - int I = rng.nextInt() & 0xFF; - bimg.setRGB(i, j, (0xFF << 24) | (I << 16) | (I << 8) | I); - } - - ByteBuffer buffer = TextureManager.createByteBuffer(bimg); - - int glID = glGenTextures(); - glBindTexture(GL_TEXTURE_2D, glID); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, bimg.getWidth(), - bimg.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); - - glNoiseTexID = glID; - } - - private void loadItemIcons() throws IOException - { - List items = game.ProjectDatabase.getItemList(); - - glItemPreviews = new Tile[items.size()]; - for (int i = 0; i < items.size(); i++) { - Tile tile = items.get(i).iconTile; - if (tile == null) - continue; - - tile.glLoad(Texture.WRAP_CLAMP, Texture.WRAP_CLAMP, false); - tile.palette.glLoad(); - - glItemPreviews[i] = tile; - } - - Logger.log("Loaded icon previews"); - } - - public void setVarImage(BufferedImage bimg) - { - if (varImageLoaded) - glDeleteTextures(glVarTexID); - - glVarTexID = glLoadImage(bimg); - varImage = bimg; - varImageLoaded = true; - } - - private static int glLoadImage(BufferedImage bimg) - { - ByteBuffer buffer = TextureManager.createByteBuffer(bimg); - - int glID = glGenTextures(); - glBindTexture(GL_TEXTURE_2D, glID); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, bimg.getWidth(), - bimg.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); - - return glID; - } - - private final void drawBackground(int glTexID) - { - projMatrix.ortho(0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f); - RenderState.setProjectionMatrix(projMatrix); - RenderState.setViewMatrix(null); - - float hfov = 105; - float right = (hfov + 360) / 360; - float scaleX = RenderState.getViewportSizeX() / 600.0f; - - BasicTexturedShader shader = ShaderManager.use(BasicTexturedShader.class); - shader.texture.bind(glTexID); - shader.setXYQuadCoords(0, 0, 1, 1, 0); - shader.setQuadTexCoords(0, 1, right * scaleX, 0); - shader.renderQuad(); - } - - private static void drawGrid(StringPrinter printer) - { - RenderState.setLineWidth(1.5f); - - int xstart = printer.windowBasePosX + printer.windowTextStartX; - int ystart = printer.windowBasePosY + printer.windowTextStartY; - int xmax = ((printer.clipMaxX - xstart) / 10) * 10; - int ymax = ((printer.clipMaxY - ystart) / 10) * 10; - - for (int i = 0; i <= xmax; i += 10) { - float alpha = ((i % 20) == 0) ? 0.5f : 0.2f; - int v1 = LineRenderQueue.addVertex() - .setPosition(xstart + i, ystart, 0) - .setColor(0.15f, 0.15f, 0.15f, alpha) - .getIndex(); - int v2 = LineRenderQueue.addVertex() - .setPosition(xstart + i, ystart + ymax, 0) - .setColor(0.15f, 0.15f, 0.15f, alpha) - .getIndex(); - LineRenderQueue.addLine(v1, v2); - } - - for (int i = 0; i <= ymax; i += 10) { - float alpha = ((i % 20) == 0) ? 0.5f : 0.2f; - int v1 = LineRenderQueue.addVertex() - .setPosition(xstart, ystart + i, 0) - .setColor(0.15f, 0.15f, 0.15f, alpha) - .getIndex(); - int v2 = LineRenderQueue.addVertex() - .setPosition(xstart + xmax, ystart + i, 0) - .setColor(0.15f, 0.15f, 0.15f, alpha) - .getIndex(); - LineRenderQueue.addLine(v1, v2); - } - - RenderState.setDepthWrite(false); - LineRenderQueue.render(true); - RenderState.setDepthWrite(true); - } - - private static void drawBackgroundGuide(StringPrinter printer) - { - int v1, v2, v3, v4; - RenderState.setLineWidth(2.0f); - - RenderState.setColor(PresetColor.RED); - v1 = LineRenderQueue.addVertex().setPosition(0, 0, 0).getIndex(); - v2 = LineRenderQueue.addVertex().setPosition(320, 0, 0).getIndex(); - v3 = LineRenderQueue.addVertex().setPosition(320, 240, 0).getIndex(); - v4 = LineRenderQueue.addVertex().setPosition(0, 240, 0).getIndex(); - LineRenderQueue.addLine(v1, v2, v3, v4, v1); - - RenderState.setColor(PresetColor.BLUE); - v1 = LineRenderQueue.addVertex().setPosition(12, 20, 0).getIndex(); - v2 = LineRenderQueue.addVertex().setPosition(320 - 12, 20, 0).getIndex(); - v3 = LineRenderQueue.addVertex().setPosition(320 - 12, 240 - 20, 0).getIndex(); - v4 = LineRenderQueue.addVertex().setPosition(12, 240 - 20, 0).getIndex(); - LineRenderQueue.addLine(v1, v2, v3, v4, v1); - - // LineRenderQueue.printContents(); - - RenderState.setDepthWrite(false); - LineRenderQueue.render(true); - RenderState.setDepthWrite(true); - } - - private static void drawForegroundGuide(StringPrinter printer) - { - int v1, v2, v3, v4; - RenderState.setLineWidth(1.5f); - - RenderState.setColor(PresetColor.GREEN); - v1 = LineRenderQueue.addVertex().setPosition(printer.windowBasePosX, printer.windowBasePosY, 0).getIndex(); - v2 = LineRenderQueue.addVertex().setPosition(printer.windowBasePosX, printer.windowBasePosY + printer.windowSizeY, 0).getIndex(); - v3 = LineRenderQueue.addVertex().setPosition(printer.windowBasePosX + printer.windowSizeX, printer.windowBasePosY + printer.windowSizeY, 0) - .getIndex(); - v4 = LineRenderQueue.addVertex().setPosition(printer.windowBasePosX + printer.windowSizeX, printer.windowBasePosY, 0).getIndex(); - LineRenderQueue.addLine(v1, v2, v3, v4, v1); - - RenderState.setColor(PresetColor.TEAL); - v1 = LineRenderQueue.addVertex().setPosition(printer.rewindArrowX, printer.rewindArrowY, 0).getIndex(); - v2 = LineRenderQueue.addVertex().setPosition(printer.rewindArrowX, printer.rewindArrowY + 24, 0).getIndex(); - v3 = LineRenderQueue.addVertex().setPosition(printer.rewindArrowX + 24, printer.rewindArrowY + 24, 0).getIndex(); - v4 = LineRenderQueue.addVertex().setPosition(printer.rewindArrowX + 24, printer.rewindArrowY, 0).getIndex(); - LineRenderQueue.addLine(v1, v2, v3, v4, v1); - - RenderState.setColor(PresetColor.YELLOW); - v1 = LineRenderQueue.addVertex().setPosition(printer.clipMinX, printer.clipMinY, 0).getIndex(); - v2 = LineRenderQueue.addVertex().setPosition(printer.clipMinX, printer.clipMaxY, 0).getIndex(); - v3 = LineRenderQueue.addVertex().setPosition(printer.clipMaxX, printer.clipMaxY, 0).getIndex(); - v4 = LineRenderQueue.addVertex().setPosition(printer.clipMaxX, printer.clipMinY, 0).getIndex(); - LineRenderQueue.addLine(v1, v2, v3, v4, v1); - - RenderState.setDepthWrite(false); - LineRenderQueue.render(true); - RenderState.setDepthWrite(true); - } - - private static final void drawAxes(float lineWidth) - { - RenderState.setLineWidth(lineWidth); - - RenderState.setColor(PresetColor.RED); - LineRenderQueue.addLine( - LineRenderQueue.addVertex().setPosition(0, 0, 0).getIndex(), - LineRenderQueue.addVertex().setPosition(Short.MAX_VALUE, 0, 0).getIndex()); - - RenderState.setColor(PresetColor.GREEN); - LineRenderQueue.addLine( - LineRenderQueue.addVertex().setPosition(0, 0, 0).getIndex(), - LineRenderQueue.addVertex().setPosition(0, Short.MAX_VALUE, 0).getIndex()); - - LineRenderQueue.render(true); - } - - public Vector3f getMousePosition(MouseInput mouse, boolean useDepth) - { - int mouseX = mouse.getPosX(); - int mouseY = mouse.getPosY(); - - int width = editor.glCanvasWidth(); - int height = editor.glCanvasHeight(); - - IntBuffer viewport = BufferUtils.createIntBuffer(16); - viewport.put(0); - viewport.put(0); - viewport.put(width); - viewport.put(height); - viewport.rewind(); - - float winX = mouseX; - float winY = mouseY; - float winZ = 0; - - if (useDepth) { - // this is the expensive part, reading z from the depth buffer - FloatBuffer fb = BufferUtils.createFloatBuffer(1); - glReadPixels(mouseX, mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, fb); - winZ = fb.get(); - } - - FloatBuffer position = BufferUtils.createFloatBuffer(3); - GLUtils.gluUnProject(winX, winY, winZ, viewMatrix.toFloatBuffer(), projMatrix.toFloatBuffer(), viewport, position); - - return new Vector3f(position.get(), position.get(), position.get()); - } - - public void render(MouseInput mouse, StringPrinter printer, float cameraX, float cameraY, float cameraZoom, float cameraYaw) - { - assert (printer != null); - - drawBackground(glBackgroundTexID); - - float halfW = (editor.glCanvasWidth() / 2.0f) * cameraZoom; - float halfH = (editor.glCanvasHeight() / 2.0f) * cameraZoom; - projMatrix.ortho(-halfW, halfW, halfH, -halfH, 1, 0x20000); - // projMatrix.perspective(60, (float)editor.glCanvasWidth() / editor.glCanvasHeight(), 1, 0x2000); - RenderState.setProjectionMatrix(projMatrix); - - viewMatrix.setIdentity(); - viewMatrix.translate(new Vector3f(-cameraX, -cameraY, -400.0f * cameraZoom)); - viewMatrix.rotate(Axis.Y, cameraYaw); - RenderState.setViewMatrix(viewMatrix); - RenderState.setModelMatrix(null); - - if (editor.shouldShowViewportGuides()) - drawBackgroundGuide(printer); - - // drawAxes(1.0f); - - DrawState state = new DrawState(printer); - state.useCulling = editor.isCullingEnabled(); - - printer.drawMessageBox(); - - FontShader shader = ShaderManager.use(FontShader.class); - shader.enableFiltering.set(useFiltering); - shader.fadeAlpha.set(1.0f); - - float scrollY = printer.scrollAmount * (state.currentFont.chars.defaultY * state.stringScaleY + printer.style.lineOffset); - int printOffsetX = 0; - int printOffsetY = -(int) (scrollY); - - state.printPosX = 0; - state.printPosY = 0; - printer.drawBuffer.rewind(); - - read_buf: - while (printer.drawBuffer.position() < printer.printPos) { - byte charByte = printer.drawBuffer.get(); - int charInt = charByte & 0xFF; - - if (charInt == StringPrinter.PAGE_END_MARK) { - continue; - } - else if (charInt == StringPrinter.BUFFER_FILL) { - break; // end of string - } - else if (charInt < 0xF0) { - int charWidth = MessageUtil.getCharWidth(state.currentFont, state.fontVariant, charInt, state.stringScaleX, state.charWidthOverride, - 0); - if (charInt < state.currentFont.chars.numChars) - renderChar(printer, state, printOffsetX, printOffsetY, charInt); - state.printPosX += charWidth; - } - else if (charInt == 0xF7 || charInt == 0xF8 || charInt == 0xF9) { - int charWidth = MessageUtil.getCharWidth(state.currentFont, state.fontVariant, charInt, state.stringScaleX, state.charWidthOverride, - 0); - state.printPosX += charWidth; - } - else { - switch (ControlCharacter.decodeMap.get(charByte)) { - case ENDL: // 0xF0 - state.printPosX = 0; - state.printPosY += state.currentFont.chars.defaultY * state.stringScaleY + printer.style.lineOffset; - break; - - case NEXT: // 0xFB - break; - - case WAIT: // 0xF1 - throw new IllegalStateException(this.getClass().getSimpleName() + " should not encounter WAIT"); - - case PAUSE: // 0xF2 - printer.drawBuffer.get(); - throw new IllegalStateException(this.getClass().getSimpleName() + " should not encounter PAUSE"); - - case VARIANT0: // 0xF3 - case VARIANT1: // 0xF4 - case VARIANT2: // 0xF5 - case VARIANT3: // 0xF6 - state.fontVariant = charInt - 0xF3; - break; - - // 0xF7-0xF9 are spaces - // 0xFA = unknown - - case STYLE: // 0xFC - handleStyle(printer, state); - break; - - case END: // 0xFD - break read_buf; - - // 0xFE = unused afaik - case FUNC: // 0xFF - handleFunction(printer, state, printOffsetX, printOffsetY); - break; - } - } - } - - frameCounter++; - - RenderState.setModelMatrix(null); - if (editor.shouldShowGrid()) - drawGrid(printer); - - // drawForegroundGuide(printer); - - drawUI(mouse, printer); - } - - private void drawUI(MouseInput mouse, StringPrinter printer) - { - // set UI matrices - TransformMatrix mtx = TransformMatrix.identity(); - mtx.ortho(0, editor.glCanvasWidth(), 0, editor.glCanvasHeight(), -1, 1); - RenderState.setProjectionMatrix(mtx); - RenderState.setViewMatrix(null); - RenderState.setModelMatrix(null); - - RenderState.enableDepthTest(false); - - if (mouse.hasLocation()) { - Vector3f worldPos = getMousePosition(mouse, false); - int mx = Math.round(worldPos.x) - (printer.windowBasePosX + printer.windowTextStartX); - int my = Math.round(worldPos.y) - (printer.windowBasePosY + printer.windowTextStartY); - drawString(0x14, 8, editor.glCanvasHeight() - 4, 16, String.format("Cursor Pos: %3d, %2d", mx, my)); - } - - float bufferFillPercent = 100.0f * printer.compiledLength / StringPrinter.MAX_LENGTH; - - if (bufferFillPercent > 100.0f) { - drawString(0x12, 176, editor.glCanvasHeight() - 4, 16, String.format("ERROR: String buffer at %.1f%% capacity! (%d/%d)", - bufferFillPercent, printer.compiledLength, StringPrinter.MAX_LENGTH)); - } - else if (bufferFillPercent > 75.0f) { - int palID = 5; - if (bufferFillPercent > 90.0f) - palID = 6; - if (bufferFillPercent > 95.0f) - palID = 7; - drawString(palID, 176, editor.glCanvasHeight() - 4, 16, String.format("WARNING: String buffer at %.1f%% capacity! (%d/%d)", - bufferFillPercent, printer.compiledLength, StringPrinter.MAX_LENGTH)); - } - - RenderState.enableDepthTest(true); - } - - private void handleStyle(StringPrinter printer, DrawState state) - { - switch (StringStyle.decodeMap.get(printer.drawBuffer.get())) { - case RIGHT: - case LEFT: - case CENTER: - case TATTLE: - case CHOICE: - state.textColor = 0xA; - break; - case INSPECT: - case UPGRADE: - case NARRATE: - case STYLE_F: - state.textColor = 0; - break; - case SIGN: - state.textColor = 0x18; - break; - case LAMPPOST: - state.textColor = 0x1C; - break; - case POSTCARD: - case POPUP: - case STYLE_B: - state.textColor = 0; - break; - case EPILOGUE: - state.textColor = 0; - break; - } - } - - private void handleFunction(StringPrinter printer, DrawState state, int relativePosX, int relativePosY) - { - int startX = state.getScreenPosX(relativePosX); - int startY = state.getScreenPosY(relativePosY); - StringFunction func = StringFunction.decodeMap.get(printer.drawBuffer.get()); - - switch (func) { - case CURSOR: - case OPTION: - case SET_CANCEL: - case END_CHOICE: - printer.drawBuffer.get(); - break; // completely ignored by editor - - case VAR: - printer.drawBuffer.get(); - break; // already handled during encoding - - case FONT: - int fontType = (printer.drawBuffer.get() & 0xFF); - switch (fontType) { - case 0: - state.currentFont = FontType.Normal; - break; - case 1: - state.currentFont = FontType.Menus; - break; - case 2: - state.currentFont = FontType.Menus; - break; - case 3: - state.currentFont = FontType.Title; - break; - case 4: - state.currentFont = FontType.Subtitle; - break; - } - break; - - case VARIANT: - state.fontVariant = (printer.drawBuffer.get() & 0xFF); - break; - - case ANIM_DONE: - if (printer.hasAnim()) { - int spriteID = printer.getAnimSprite(); - int rasterID = printer.getAnimRaster(); - - Sprite npc = spriteLoader.getSprite(SpriteSet.Npc, spriteID); - if (npc != null && !npc.areTexturesLoaded()) - npc.loadTextures(); - - if (npc != null && npc.rasters.getSize() > rasterID) { - BasicIndexedShader shader = ShaderManager.use(BasicIndexedShader.class); - SpriteRaster raster = npc.rasters.get(rasterID); - ImgAsset front = raster.getFront(); - if (front != null) { - front.img.glBind(shader.texture); - front.getPalette().glBind(shader.palette); - drawClippedQuad(shader, state, startX, startX + front.img.width, startY, startY + front.img.height); - } - } - else { - BasicSolidShader shader = ShaderManager.use(BasicSolidShader.class); - float f = 0.5f + (float) Math.cos(Math.toRadians(16 * frameCounter)) * 0.25f; - shader.baseColor.set(1.0f, f, f, 1.0f); - drawClippedQuad(shader, state, startX, startX + 0x20, startY, startY + 0x40); - } - } - break; - - case IMAGE: - printer.drawBuffer.get(); // index -- ignored - int posX = printer.drawBuffer.getShort() & 0xFFFF; - int posY = printer.drawBuffer.get() & 0xFF; - int border = printer.drawBuffer.get() & 0xFF; - int alpha = printer.drawBuffer.get() & 0xFF; - int alphaStep = printer.drawBuffer.get() & 0xFF; - - if (varImageLoaded) { - BasicTexturedShader shader = ShaderManager.use(BasicTexturedShader.class); - shader.texture.bind(glVarTexID); - shader.multiplyBaseColor.set(true); - shader.baseColor.set(1.0f, 1.0f, 1.0f, alpha / 255.0f); - drawQuad(shader, posX, posX + varImage.getWidth(), posY, posY + varImage.getHeight()); - } - else { - BasicSolidShader shader = ShaderManager.use(BasicSolidShader.class); - float f = 0.5f + (float) Math.cos(Math.toRadians(16 * frameCounter)) * 0.25f; - shader.baseColor.set(1.0f, f, f, alpha / 255.0f); - drawQuad(shader, posX, posX + 150, posY, posY + 105); - } - break; - - case HIDE_IMAGE: - printer.drawBuffer.get(); // fade out time - break; - - case INLINE_IMAGE: - printer.drawBuffer.get(); // index -- ignored - - if (varImageLoaded) { - BasicTexturedShader shader = ShaderManager.use(BasicTexturedShader.class); - shader.texture.bind(glVarTexID); - drawClippedQuad(shader, state, startX, startX + varImage.getWidth(), startY, startY + varImage.getHeight()); - } - else { - BasicSolidShader shader = ShaderManager.use(BasicSolidShader.class); - float f = 0.5f + (float) Math.cos(Math.toRadians(16 * frameCounter)) * 0.25f; - shader.baseColor.set(1.0f, f, f, 1.0f); - drawClippedQuad(shader, state, startX, startX + 0x40, startY, startY + 0x40); - } - break; - - case ITEM_ICON: - int upperItemID = (printer.drawBuffer.get() & 0xFF); - int lowerItemID = (printer.drawBuffer.get() & 0xFF); - int itemID = (upperItemID << 8) | lowerItemID; - - if (glItemPreviews != null && glItemPreviews.length > itemID && glItemPreviews[itemID] != null) { - BasicIndexedShader shader = ShaderManager.use(BasicIndexedShader.class); - glItemPreviews[itemID].glBind(shader.texture); - glItemPreviews[itemID].palette.glBind(shader.palette); - drawClippedQuad(shader, state, startX, startX + 0x20, startY, startY + 0x20); - } - else { - BasicSolidShader shader = ShaderManager.use(BasicSolidShader.class); - float f = 0.5f + (float) Math.cos(Math.toRadians(16 * frameCounter)) * 0.25f; - shader.baseColor.set(1.0f, f, f, 1.0f); - drawClippedQuad(shader, state, startX, startX + 0x20, startY, startY + 0x20); - } - break; - - case COLOR: - state.textColor = (printer.drawBuffer.get() & 0xFF); - if (state.textColor < 0) - state.textColor = 0; - int numPals = state.currentFont.chars.numPals; - if (state.textColor >= numPals) - state.textColor = numPals - 1; - break; - - case PUSH_COLOR: - state.savedColor = state.textColor; - break; - case POP_COLOR: - state.textColor = state.savedColor; - break; - - case PUSH_POS: - state.savedPosX = state.printPosX; - state.savedPosY = state.printPosY; - break; - case POP_POS: - state.printPosX = state.savedPosX; - state.printPosY = state.savedPosY; - break; - - case SPACING: - state.charWidthOverride = (printer.drawBuffer.get() & 0xFF); - break; - - case SIZE: - int sx = (printer.drawBuffer.get() & 0xFF); - int sy = (printer.drawBuffer.get() & 0xFF); - state.stringScaleX = sx / 16.0f; - state.stringScaleY = sy / 16.0f; - state.charScaleX = state.stringScaleX; - state.charScaleY = state.stringScaleY; - break; - case SIZE_RESET: - state.stringScaleX = 1.0f; - state.stringScaleY = 1.0f; - state.charScaleX = state.stringScaleX; - state.charScaleY = state.stringScaleY; - break; - - case SET_X: // [80129EB4] - int upper = (printer.drawBuffer.get() & 0xFF); - int lower = (printer.drawBuffer.get() & 0xFF); - state.printPosX = (upper << 8) | lower; - break; - case SET_Y: // [80129ED8] - state.printPosY = (printer.drawBuffer.get() & 0xFF); - break; - case RIGHT: // [80129F0C] - state.printPosX += (printer.drawBuffer.get() & 0xFF); - break; - case DOWN: // [80129F38] - state.printPosY += (printer.drawBuffer.get() & 0xFF); - break; - case UP: // [80129F64] - state.printPosY -= (printer.drawBuffer.get() & 0xFF); - break; - case CENTER_X: // [8012AAEC] - state.centerPos = (printer.drawBuffer.get() & 0xFF); - break; - - case START_FX: - int startFXType = (printer.drawBuffer.get() & 0xFF); - state.effectActive[startFXType] = true; - switch (startFXType) { - case 0x2: - state.effectActive[3] = false; - break; - case 0x3: - state.effectActive[2] = false; - state.fadeNoiseAlpha = (printer.drawBuffer.get() & 0xFF) / 255.0f; - break; - case 0x5: - state.fadeJitterArg = (printer.drawBuffer.get() & 0xFF); - break; - case 0x7: - state.fadeAlpha = (printer.drawBuffer.get() & 0xFF) / 255.0f; - break; - case 0x6: - case 0x9: - state.savedFxColor = state.textColor; - break; - case 0xC: - case 0xD: - state.savedFxCharScaleX = state.charScaleX; - state.savedFxCharScaleY = state.charScaleY; - break; - } - break; - - case END_FX: - int endFXType = (printer.drawBuffer.get() & 0xFF); - // restore saved state (if it has been saved) - if (state.effectActive[endFXType]) { - switch (endFXType) { - case 0x2: - case 0x3: - // end clears the flags for these, - // but will not stop the effect since its - // part of the display list - break; - case 0x6: - case 0x9: - state.textColor = state.savedFxColor; - state.effectActive[endFXType] = false; - break; - case 0xC: - case 0xD: - state.charScaleX = state.savedFxCharScaleX; - state.charScaleY = state.savedFxCharScaleY; - state.effectActive[endFXType] = false; - break; - default: - state.effectActive[endFXType] = false; - } - } - break; - - case FUNC_03: - //XXX unknown, some graphics state reset? - break; - - case SETVOICE: - case VOICE: - case VOLUME: - case SPEED: - case SCROLL: - case DELAY_OFF: - case DELAY_ON: - case SKIP_OFF: - case INPUT_OFF: - case INPUT_ON: - case ENABLE_CDOWN: - break; // irrelevant to renderer - - case SET_REWIND: - printer.drawBuffer.get(); - break; // irrelevant to renderer - - case YIELD: - break; - - case SET_CURSOR: - break; - - case ANIM_SPRITE: - case ANIM_DELAY: - case ANIM_LOOP: - throw new IllegalStateException("LOGIC ERROR: " + func.name + " in encodeFunctionArgs!"); - } - } - - public void drawString(int palID, int posX, int posY, int size, String text) - { - FontShader shader = ShaderManager.use(FontShader.class); - shader.noiseMode.set(0); - shader.fadeAlpha.set(1.0f); - shader.enableDropShadow.set(false); - - FontType font = FontType.Normal; - - for (char c : text.toCharArray()) { - int index = StringConstants.getIndex(c, true); - if (index < 0) - continue; - - int endX = posX + (int) (font.chars.defaultX * size / 16.0f); - int endY = posY - (int) (font.chars.defaultY * size / 16.0f); - int charWidth = MessageUtil.getCharWidth(font, 0, index, size / 16.0f, 0, 0); - - if (index < font.chars.numChars) { - font.chars.images[index].glBind(shader.texture); - font.chars.palettes[palID].glBind(shader.palette); - drawQuad(shader, posX, endX, posY, endY); - } - posX += charWidth; - } - } - - private void renderChar(StringPrinter printer, DrawState state, int relativePosX, int relativePosY, int charIndex) - { - FontShader shader = ShaderManager.use(FontShader.class); - - int[] lookahead = new int[4]; - for (int i = 0; i < lookahead.length; i++) - lookahead[i] = (printer.drawBuffer.get() & 0xFF); - printer.drawBuffer.position(printer.drawBuffer.position() - lookahead.length); - - //XXX correct? - state.charScaleX = state.stringScaleX; - state.charScaleY = state.stringScaleY; - float alpha = 1.0f; - - if (state.effectActive[BLUR.code]) // 0x20 - { - // fade code from [8012ADC4] - alpha = 0.35f; - } - - if (state.effectActive[SHAKE.code]) { - // code from [8012AE50] - relativePosX += rng.nextInt() % 2; - relativePosY += rng.nextInt() % 2; - } - - if (state.effectActive[WAVE.code]) // 0x2 - { - // code from [8012AEBC] - double dsx = state.stringScaleX - 1.0; - double dsy = state.stringScaleY - 1.0; - - //NOTE: game uses a message-specific 'local' frame counter here - double angle = frameCounter * (int) (20.0 - dsx * 5.0) - state.visibleCharCount * (int) (45.0 - dsx * 15.0); - relativePosX += Math.cos(Math.toRadians(angle)) * (dsx + 1.6); - relativePosY += Math.cos(Math.toRadians(angle + 270.0)) * (dsy + 1.6); - } - if (state.effectActive[GLOBAL_WAVE.code]) // 0x200 - { - // code from [8012B0BC] - double dsx = state.stringScaleX - 1.0; - double dsy = state.stringScaleY - 1.0; - - //NOTE: game uses a 'global' frame counter shared by all messages here - double angle = frameCounter * (int) (20.0 - dsx * 5.0) - state.visibleCharCount * 45.0; - relativePosX += Math.cos(Math.toRadians(angle)) * (dsx + 1.6); - relativePosY += Math.cos(Math.toRadians(angle + 270.0)) * (dsy + 1.6); - } - - if (state.effectActive[RAINBOW.code] || state.effectActive[GLOBAL_RAINBOW.code]) // 0x440 -- either rainbow - { - // code from [8012B1B4] - - // NOTE: global overrides local here, but they cant stack so we dont need to represent it - int i = Math.abs(state.visibleCharCount - frameCounter / 3); - state.textColor = i % 10; // original code: = i + (i / 10) * -10; - } - - // properly respect precedence of these effects - if (state.effectActive[RISE_PRINT.code] || state.effectActive[GROW_PRINT.code]) { - if (!printer.donePrinting - && (lookahead[0] != ControlCharacter.ENDL.code) && (lookahead[1] != ControlCharacter.ENDL.code) - && (lookahead[2] != ControlCharacter.ENDL.code) && (lookahead[3] != ControlCharacter.ENDL.code)) { - if (state.effectActive[RISE_PRINT.code]) { - // from [8012B4F0] - float dummyScale = 0.25f; //XXX needed to match, unknown why - if (lookahead[0] == StringPrinter.BUFFER_FILL) { - state.charScaleX = 1.7f * state.stringScaleX; - state.charScaleY = 1.7f * state.stringScaleY; - relativePosX -= 6.0f * state.stringScaleY; - relativePosY -= dummyScale * 6.0f * state.stringScaleY; - } - else if (lookahead[1] == StringPrinter.BUFFER_FILL) { - state.charScaleX = 1.4f * state.stringScaleX; - state.charScaleY = 1.4f * state.stringScaleY; - relativePosX -= 3.0f * state.stringScaleY; - relativePosY -= dummyScale * 3.0f * state.stringScaleY; - } - else if (lookahead[2] == StringPrinter.BUFFER_FILL) { - state.charScaleX = 1.2f * state.stringScaleX; - state.charScaleY = 1.2f * state.stringScaleY; - relativePosX -= 2.0f * state.stringScaleY; - relativePosY -= dummyScale * 2.0f * state.stringScaleY; - } - } - else if (state.effectActive[GROW_PRINT.code]) { - // from [8012B740] - if (lookahead[0] == StringPrinter.BUFFER_FILL) { - state.charScaleX = 0.3f * state.stringScaleX; - state.charScaleY = 0.3f * state.stringScaleY; - relativePosX += 5; - relativePosY += 5; - } - else if (lookahead[1] == StringPrinter.BUFFER_FILL) { - state.charScaleX = 0.5f * state.stringScaleX; - state.charScaleY = 0.5f * state.stringScaleY; - relativePosX += 3; - relativePosY += 3; - } - else if (lookahead[2] == StringPrinter.BUFFER_FILL) { - state.charScaleX = 0.75f * state.stringScaleX; - state.charScaleY = 0.75f * state.stringScaleY; - relativePosX += 2; - relativePosY += 2; - } - } - } - } - else if (state.effectActive[SIZE_JITTER.code] || state.effectActive[SIZE_WAVE.code]) { - float scale = 1.0f; - - if (state.effectActive[SIZE_JITTER.code]) // 0x2000 -- size jitter - { - // code from [8012B8BC] - scale = 0.75f + 0.5f * (rng.nextInt(101) / 100.0f); - } - else if (state.effectActive[SIZE_WAVE.code]) // 0x4000 -- size wave - { - // code from [8012BA24] - int i = (frameCounter - state.visibleCharCount) * 15; - scale = 1.0f + 0.25f * (float) Math.cos(Math.toRadians(i + ((i >> 3) / 45) * 360.0)); - } - - state.charScaleX *= scale; - state.charScaleY *= scale; - - if (scale >= 1.0) { - // [8012BACC] - int posOffset = (int) (scale * 8.0 - 8.5); - relativePosX -= posOffset; - relativePosY -= posOffset; - } - else { - // [8012BB7C] - int posOffset = (int) (8.0 - 8.0 * scale); - relativePosX += posOffset; - relativePosY += posOffset; - } - } - - shader.noiseMode.set(0); // initial value - - if (state.effectActive[DITHER_FADE.code]) //0x80 -- fade - { - alpha *= state.fadeAlpha; - shader.noiseMode.set(7); - shader.noiseAlpha.set(state.fadeAlpha); - shader.noiseOffset.set(rng.nextFloat(), rng.nextFloat()); - } - else { - if (state.effectActive[NOISE_OUTLINE.code]) // 0x04 -- noise - { - shader.noiseMode.set(2); - shader.noiseOffset.set(rng.nextFloat(), rng.nextFloat()); - - // add Gfx: - // SET_COMBINE FC70FEE1 FFFFF3F9 - - // color: G_CCMUX_NOISE * G_CCMUX_TEXEL0 - // alpha: G_ACMUX_TEXEL0 - } - - if (state.effectActive[STATIC.code]) // 0x10000 -- faded noise - { - shader.noiseMode.set(3); - shader.noiseAlpha.set(state.fadeNoiseAlpha); - shader.noiseOffset.set(rng.nextFloat(), rng.nextFloat()); - - // add Gfx: - // SET_ENVCOLOR FB000000 arg << 0x18 | arg << 0x10 | arg << 8; - // SET_COMBINE FC72FEE5 11FCF279 - - // color: (G_CCMUX_NOISE - G_CCMUX_TEXEL0) * G_CCMUX_ENVIRONMENT + G_CCMUX_TEXEL0 - // alpha: G_ACMUX_TEXEL0 - } - } - - shader.fadeAlpha.set(alpha); - - int baseOffset = 0; - if (state.fontVariant < state.currentFont.numVariants && state.fontVariant >= 0) - baseOffset = state.currentFont.baseHeightOffset[state.fontVariant]; - - int startX = state.getScreenPosX(relativePosX); - int startY = state.getScreenPosY(relativePosY + baseOffset); - int endX = startX + (int) (state.currentFont.chars.defaultX * state.charScaleX); - int endY = startY + (int) (state.currentFont.chars.defaultY * state.charScaleY); - - if (state.effectActive[DROP_SHADOW.code]) // 0x8000 -- drop shadow - { - shader.enableDropShadow.set(true); - drawFontQuad(shader, state, - state.currentFont.chars.images[charIndex], - state.currentFont.chars.palettes[state.getColor()], - startX + 2, endX + 2, startY + 2, endY + 2); - shader.enableDropShadow.set(false); - } - - if (state.effectActive[BLUR.code]) // 0x20 -- FadedJitter - { - // code from [8012BDF4] - for (int i = 0; i < 5; i++) { - int jx = (state.fadeJitterArg == 2) ? 0 : rng.nextInt(3) - 1; - int jy = (state.fadeJitterArg == 1) ? 0 : rng.nextInt(3) - 1; - - drawFontQuad(shader, state, - state.currentFont.chars.images[charIndex], - state.currentFont.chars.palettes[state.getColor()], - startX + jx, endX + jx, startY + jy, endY + jy); - } - } - else { - drawFontQuad(shader, state, - state.currentFont.chars.images[charIndex], - state.currentFont.chars.palettes[state.getColor()], - startX, endX, startY, endY); - } - - state.visibleCharCount++; - } - - private static class DrawState - { - public final StringPrinter printer; - - private FontType currentFont = FontType.Normal; - public int fontVariant = 0; - - private boolean[] effectActive; - private float fadeAlpha = 1.0f; - private float fadeNoiseAlpha = 0; - private int fadeJitterArg = 0; - - private int textColor = 0xA; - - private int visibleCharCount = 0; - - private boolean useCulling = true; - - private int printPosX = 0; - private int printPosY = 0; - - private int centerPos = 0; - - private int savedColor; - private int savedPosX = 0; - private int savedPosY = 0; - private int savedFxColor = -1; - private float savedFxCharScaleX = 1.0f; - private float savedFxCharScaleY = 1.0f; - - private int charWidthOverride = 0; - - private float charScaleX = 1.0f; - private float charScaleY = 1.0f; - - private float stringScaleX = 1.0f; - private float stringScaleY = 1.0f; - - private DrawState(StringPrinter printer) - { - this.printer = printer; - effectActive = new boolean[StringConstants.StringEffect.values().length]; - } - - public int getColor() - { - switch (currentFont) { - case Normal: - case Menus: - default: - return textColor; - case Title: - case Subtitle: - return 0; - } - } - - public int getScreenPosX(int offsetX) - { - int centerOffset = 0; - if (centerPos == 0xFF) - centerOffset = 160 - (printer.stringWidth / 2); - else if (centerPos != 0) - centerOffset = centerPos - (printer.stringWidth / 2); - - if (centerOffset == 0) - return printer.windowBasePosX + printer.windowTextStartX + printPosX + offsetX; - else - return centerOffset + printPosX + offsetX; - } - - public int getScreenPosY(int offsetY) - { - return printer.windowBasePosY + printer.windowTextStartY + printPosY + offsetY; - } - } - - private void drawFontQuad(FontShader shader, DrawState state, Tile img, Palette pal, float x1, float x2, float y1, float y2) - { - img.glBind(shader.texture); - pal.glBind(shader.palette); - shader.noise.bind(glNoiseTexID); - drawClippedQuad(shader, state, x1, x2, y1, y2); - } - - private static final void drawClippedQuad(BaseShader shader, DrawState state, float x1, float x2, float y1, float y2) - { - if (state.useCulling) - drawClippedQuad(shader, state.printer, x1, x2, y1, y2); - else - drawQuad(shader, x1, x2, y1, y2); - } - - private static final void drawClippedQuad(BaseShader shader, StringPrinter printer, float x1, float x2, float y1, float y2) - { - float x1c = x1; - float x2c = x2; - - float y1c = y1; - float y2c = y2; - - float u1c = 0.0f; - float u2c = 1.0f; - - float v1c = 0.0f; - float v2c = 1.0f; - - assert (x1 < x2); - assert (y1 < y2); - - if ((x2 < printer.clipMinX) || (x1 > printer.clipMaxX) || (y2 < printer.clipMinY) || (y1 > printer.clipMaxY)) - return; - - if (x1 < printer.clipMinX) { - x1c = printer.clipMinX; - u1c = ((printer.clipMinX - x1) / (x2 - x1)); - } - - if (x2 > printer.clipMaxX) { - x2c = printer.clipMaxX; - u2c = 1.0f - ((x2 - printer.clipMaxX) / (x2 - x1)); - } - - if (y1 < printer.clipMinY) { - y1c = printer.clipMinY; - v2c = 1.0f - ((printer.clipMinY - y1) / (y2 - y1)); - } - - if (y2 > printer.clipMaxY) { - y2c = printer.clipMaxY; - v1c = ((y2 - printer.clipMaxY) / (y2 - y1)); - } - - shader.setQuadTexCoords(u1c, v1c, u2c, v2c); - shader.setXYQuadCoords(x1c, y2c, x2c, y1c, 0); // y flipped - shader.renderQuad(); - } - - private static final void drawQuad(BaseShader shader, float x1, float x2, float y1, float y2) - { - shader.setQuadTexCoords(0, 0, 1, 1); - shader.setXYQuadCoords(x1, y2, x2, y1, 0); // y flipped - shader.renderQuad(); - } -} diff --git a/src/main/java/game/sprite/editor/SpriteEditor.java b/src/main/java/game/sprite/editor/SpriteEditor.java index 71e9c3c..5eadf22 100644 --- a/src/main/java/game/sprite/editor/SpriteEditor.java +++ b/src/main/java/game/sprite/editor/SpriteEditor.java @@ -611,7 +611,9 @@ private boolean setAnimation(SpriteAnimation animation) } public SpriteAnimation getAnimation() - { return currentAnim; } + { + return currentAnim; + } private void setComponent(int id, boolean fromTabChange) { @@ -649,7 +651,9 @@ private void setComponent(int id, boolean fromTabChange) } public ImgAsset getSelectedImage() - { return selectedImgAsset; } + { + return selectedImgAsset; + } private void setPalette(SpritePalette pm) { @@ -702,7 +706,7 @@ public void keyPress(KeyInputEvent key) if (sprite != null && currentAnim != null && currentComp != null && currentComp.selected) { if (currentAnim.components.size() > 1) { SwingUtilities.invokeLater(() -> { - if (JOptionPane.YES_OPTION == super.showConfirmDialog("Delete component?", "Confirm")) { + if (JOptionPane.YES_OPTION == super.getConfirmDialog("Confirm", "Delete component?").choose()) { invokeLater(() -> { currentAnim.components.removeElement(currentComp); sprite.recalculateIndices(); @@ -968,12 +972,12 @@ private void addOptionsMenu(JMenuBar menuBar, ActionListener openLogAction) try { int id = SpriteLoader.getMaximumID(spriteSet) + 1; SpriteLoader.create(spriteSet, id); - + if(spriteSet == SpriteSet.Npc) useNpcFiles(id); else usePlayerFiles(id); - + } catch (Throwable t) { Logger.logError("Failed to create new sprite."); incrementDialogsOpen(); @@ -983,7 +987,7 @@ private void addOptionsMenu(JMenuBar menuBar, ActionListener openLogAction) }); }); menu.add(item); - + menu.addSeparator(); */ @@ -1439,7 +1443,7 @@ private void showAnimationsEditorWindow() return; ListEditPanel listPanel = new AnimationListEditPanel(sprite, sprite.animations, this); - showOptionDialog(listPanel, "Edit " + sprite + " Animations", new String[] { "Done" }); + getOptionDialog("Edit " + sprite + " Animations", listPanel).setOptions("Done").choose(); invokeLater(() -> { setSprite(spriteID, false); @@ -1456,7 +1460,7 @@ private void showComponentsEditorWindow() return; ListEditPanel listPanel = new ComponentListEditPanel(currentAnim, currentAnim.components); - showOptionDialog(listPanel, "Edit " + currentAnim + " Components", new String[] { "Done" }); + getOptionDialog("Edit " + currentAnim + " Components", listPanel).setOptions("Done").choose(); invokeLater(() -> { sprite.recalculateIndices(); @@ -1474,7 +1478,14 @@ else if (!currentAnim.components.isEmpty()) private void showControls() { incrementDialogsOpen(); - SwingUtils.showFramedMessageDialog(getFrame(), new ShortcutListPanel(), "Controls and Shortcuts", JOptionPane.PLAIN_MESSAGE); + + SwingUtils.getMessageDialog() + .setParent(getFrame()) + .setTitle("Controls and Shortcuts") + .setMessage(new SpriteShortcutsPanel()) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .show(); + decrementDialogsOpen(); } diff --git a/src/main/java/game/sprite/editor/ShortcutListPanel.java b/src/main/java/game/sprite/editor/SpriteShortcutsPanel.java similarity index 96% rename from src/main/java/game/sprite/editor/ShortcutListPanel.java rename to src/main/java/game/sprite/editor/SpriteShortcutsPanel.java index 098a680..d2a49b3 100644 --- a/src/main/java/game/sprite/editor/ShortcutListPanel.java +++ b/src/main/java/game/sprite/editor/SpriteShortcutsPanel.java @@ -8,9 +8,9 @@ import net.miginfocom.swing.MigLayout; -public class ShortcutListPanel extends JPanel +public class SpriteShortcutsPanel extends JPanel { - public ShortcutListPanel() + public SpriteShortcutsPanel() { setLayout(new MigLayout("fill")); diff --git a/src/main/java/game/texture/editor/ImageEditor.java b/src/main/java/game/texture/editor/ImageEditor.java index cd760fc..926f628 100644 --- a/src/main/java/game/texture/editor/ImageEditor.java +++ b/src/main/java/game/texture/editor/ImageEditor.java @@ -53,10 +53,10 @@ import game.texture.editor.dialogs.ConvertOptionsPanel.ConvertSettings; import game.texture.editor.dialogs.ConvertOptionsPanel.ConvertSettings.IntensityMethod; import game.texture.editor.dialogs.CreateOptionsPanel; +import game.texture.editor.dialogs.ImageShortcutsPanel; import game.texture.editor.dialogs.ImportOptionsPanel; import game.texture.editor.dialogs.ResizeOptionsPanel; import game.texture.editor.dialogs.ResizeOptionsPanel.ResizeOptions; -import game.texture.editor.dialogs.ShorcutListPanel; import net.miginfocom.swing.MigLayout; import renderer.buffers.LineRenderQueue; import renderer.shaders.RenderState; @@ -302,11 +302,15 @@ public void setSelectedColor(Color c) private void showControls() { - JPanel panel = new JPanel(); - panel.add(new ShorcutListPanel()); - incrementDialogsOpen(); - SwingUtils.showFramedMessageDialog(getFrame(), new ShorcutListPanel(), "Controls and Shortcuts", JOptionPane.PLAIN_MESSAGE); + + SwingUtils.getMessageDialog() + .setParent(getFrame()) + .setTitle("Controls and Shortcuts") + .setMessage(new ImageShortcutsPanel()) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .show(); + decrementDialogsOpen(); } @@ -854,9 +858,9 @@ private void exportImage() private File promptOverwrite(File file) { - int choice = showOptionDialog( - "File already exists: \n" + file.getName(), - "Export Image", new String[] { "Overwrite", "Choose File", "Cancel" }); + int choice = getOptionDialog("Export Image", "File already exists: \n" + file.getName()) + .setOptions("Overwrite", "Choose File", "Cancel") + .choose(); if (choice == 0) return file; @@ -901,7 +905,7 @@ private void newImageEDT() assert (SwingUtilities.isEventDispatchThread()); CreateOptionsPanel createOptions = new CreateOptionsPanel(); - int choice = ImageEditor.super.showConfirmDialog(createOptions, "New Image Options"); + int choice = ImageEditor.super.getConfirmDialog("New Image Options", createOptions).choose(); if (choice != JOptionPane.OK_OPTION) return; @@ -964,7 +968,7 @@ private void openImageEDT(File file) assert (SwingUtilities.isEventDispatchThread()); ImportOptionsPanel importOptions = new ImportOptionsPanel(); - int choice = ImageEditor.super.showConfirmDialog(importOptions, "Import Options"); + int choice = ImageEditor.super.getConfirmDialog("Import Options", importOptions).choose(); if (choice != JOptionPane.OK_OPTION) return; @@ -976,8 +980,8 @@ private void openImageEDT(File file) } catch (ImageFormatException e) { if (importOptions.getFormat().type == TileFormat.TYPE_CI) { - choice = ImageEditor.super.showConfirmDialog( - "Image file is not color-indexed. \nWould you like to convert it?", "Incorrect Image Format"); + choice = ImageEditor.super.getConfirmDialog( + "Incorrect Image Format", "Image file is not color-indexed. \nWould you like to convert it?").choose(); if (choice != JOptionPane.OK_OPTION) return; @@ -1012,7 +1016,7 @@ private Palette getPaletteEDT(File file) assert (SwingUtilities.isEventDispatchThread()); ImportOptionsPanel importOptions = new ImportOptionsPanel(); - int choice = ImageEditor.super.showConfirmDialog(importOptions, "Import Options"); + int choice = ImageEditor.super.getConfirmDialog("Import Options", importOptions).choose(); if (choice != JOptionPane.OK_OPTION) return null; @@ -1058,7 +1062,7 @@ private void choosePaletteEDT() importFileChooser.setDirectoryContaining(image.source.getParentFile()); if (importFileChooser.prompt() == ChooseDialogResult.APPROVE) { ImportOptionsPanel importOptions = new ImportOptionsPanel(); - int choice = ImageEditor.super.showConfirmDialog(importOptions, "Import Options"); + int choice = ImageEditor.super.getConfirmDialog("Import Options", importOptions).choose(); if (choice != JOptionPane.OK_OPTION) return; @@ -1084,7 +1088,7 @@ private void resizeImageEDT() return; ResizeOptionsPanel resizeOptionsPanel = new ResizeOptionsPanel(); - int choice = ImageEditor.super.showConfirmDialog(resizeOptionsPanel, "Resize Image Options"); + int choice = ImageEditor.super.getConfirmDialog("Resize Image Options", resizeOptionsPanel).choose(); if (choice != JOptionPane.OK_OPTION) return; @@ -1103,7 +1107,7 @@ private void convertImageEDT() return; ConvertOptionsPanel convertOptionsPanel = new ConvertOptionsPanel(); - int choice = ImageEditor.super.showConfirmDialog(convertOptionsPanel, "Convert Image Options"); + int choice = ImageEditor.super.getConfirmDialog("Convert Image Options", convertOptionsPanel).choose(); if (choice != JOptionPane.OK_OPTION) return; @@ -1191,7 +1195,7 @@ public void moveMouse(int dx, int dy) else image.draw(mousePixelX, mousePixelY, pickedPixel); } - + if(mouseManager.holdingRMB && mousePixelValid) image.deselect(mousePixelX, mousePixelY); */ diff --git a/src/main/java/game/texture/editor/dialogs/ShorcutListPanel.java b/src/main/java/game/texture/editor/dialogs/ImageShortcutsPanel.java similarity index 96% rename from src/main/java/game/texture/editor/dialogs/ShorcutListPanel.java rename to src/main/java/game/texture/editor/dialogs/ImageShortcutsPanel.java index 062fc9b..95ff8b0 100644 --- a/src/main/java/game/texture/editor/dialogs/ShorcutListPanel.java +++ b/src/main/java/game/texture/editor/dialogs/ImageShortcutsPanel.java @@ -7,9 +7,9 @@ import net.miginfocom.swing.MigLayout; -public class ShorcutListPanel extends JPanel +public class ImageShortcutsPanel extends JPanel { - public ShorcutListPanel() + public ImageShortcutsPanel() { setLayout(new MigLayout("fill", "[50%][50%]")); diff --git a/src/main/java/game/worldmap/WorldMapEditor.java b/src/main/java/game/worldmap/WorldMapEditor.java index 5b59c5c..fe23aa7 100644 --- a/src/main/java/game/worldmap/WorldMapEditor.java +++ b/src/main/java/game/worldmap/WorldMapEditor.java @@ -667,8 +667,14 @@ private void drawGrid(float lineWidth) private void showControls() { incrementDialogsOpen(); - SwingUtils.showFramedMessageDialog(getFrame(), new ShorcutListPanel(), - "Controls and Shortcuts", JOptionPane.PLAIN_MESSAGE); + + SwingUtils.getMessageDialog() + .setParent(getFrame()) + .setTitle("Controls and Shortcuts") + .setMessage(new WorldShortcutsPanel()) + .setMessageType(JOptionPane.PLAIN_MESSAGE) + .show(); + decrementDialogsOpen(); } diff --git a/src/main/java/game/worldmap/ShorcutListPanel.java b/src/main/java/game/worldmap/WorldShortcutsPanel.java similarity index 95% rename from src/main/java/game/worldmap/ShorcutListPanel.java rename to src/main/java/game/worldmap/WorldShortcutsPanel.java index 7ab4ab6..bcebed0 100644 --- a/src/main/java/game/worldmap/ShorcutListPanel.java +++ b/src/main/java/game/worldmap/WorldShortcutsPanel.java @@ -7,9 +7,9 @@ import net.miginfocom.swing.MigLayout; -public class ShorcutListPanel extends JPanel +public class WorldShortcutsPanel extends JPanel { - public ShorcutListPanel() + public WorldShortcutsPanel() { setLayout(new MigLayout("fill", "[45%]32[45%]")); diff --git a/src/main/java/util/ui/FilteredListPanel.java b/src/main/java/util/ui/FilteredListPanel.java index a010014..4c7baac 100644 --- a/src/main/java/util/ui/FilteredListPanel.java +++ b/src/main/java/util/ui/FilteredListPanel.java @@ -52,14 +52,14 @@ public void mouseClicked(MouseEvent evt) if (evt.getButton() != MouseEvent.BUTTON1) { return; } - + if (evt.getClickCount() == 1) { Rectangle rect = list.getCellBounds(0, list.getLastVisibleIndex()); if (rect != null && !rect.contains(evt.getPoint())) { list.clearSelection(); } } - + if (evt.getClickCount() == 2) { Rectangle rect = list.getCellBounds(0, list.getLastVisibleIndex()); if (rect != null && rect.contains(evt.getPoint())) { @@ -156,4 +156,9 @@ private void updateListFilter() public T getSelected() { return list.getSelectedValue(); } + + public void setSelected(T value) + { + list.setSelectedValue(value, true); + } }