diff --git a/jme3-android/src/main/java/com/jme3/system/android/JmeAndroidSystem.java b/jme3-android/src/main/java/com/jme3/system/android/JmeAndroidSystem.java
index e36319c0bc..0d6ee82c6d 100644
--- a/jme3-android/src/main/java/com/jme3/system/android/JmeAndroidSystem.java
+++ b/jme3-android/src/main/java/com/jme3/system/android/JmeAndroidSystem.java
@@ -17,6 +17,8 @@
import com.jme3.system.*;
import com.jme3.system.JmeContext.Type;
import com.jme3.util.AndroidScreenshots;
+import com.jme3.util.functional.VoidFunction;
+
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
@@ -35,6 +37,18 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
} catch (UnsatisfiedLinkError e) {
}
}
+
+ public JmeAndroidSystem(){
+ setErrorMessageHandler((message) -> {
+ String finalMsg = message;
+ String finalTitle = "Error in application";
+ Context context = JmeAndroidSystem.getView().getContext();
+ view.getHandler().post(() -> {
+ AlertDialog dialog = new AlertDialog.Builder(context).setTitle(finalTitle).setMessage(finalMsg).create();
+ dialog.show();
+ });
+ });
+ }
@Override
public URL getPlatformAssetConfigURL() {
@@ -57,26 +71,8 @@ public void writeImageFile(OutputStream outStream, String format, ByteBuffer ima
bitmapImage.recycle();
}
- @Override
- public void showErrorDialog(String message) {
- final String finalMsg = message;
- final String finalTitle = "Error in application";
- final Context context = JmeAndroidSystem.getView().getContext();
- view.getHandler().post(new Runnable() {
- @Override
- public void run() {
- AlertDialog dialog = new AlertDialog.Builder(context)
- .setTitle(finalTitle).setMessage(finalMsg).create();
- dialog.show();
- }
- });
- }
- @Override
- public boolean showSettingsDialog(AppSettings sourceSettings, boolean loadFromRegistry) {
- return true;
- }
@Override
public JmeContext newContext(AppSettings settings, Type contextType) {
diff --git a/jme3-awt-dialogs/build.gradle b/jme3-awt-dialogs/build.gradle
new file mode 100644
index 0000000000..9dd715218e
--- /dev/null
+++ b/jme3-awt-dialogs/build.gradle
@@ -0,0 +1,3 @@
+dependencies {
+ api project(':jme3-core')
+}
diff --git a/jme3-awt-dialogs/src/main/java/com/jme3/awt/AWTErrorDialog.java b/jme3-awt-dialogs/src/main/java/com/jme3/awt/AWTErrorDialog.java
new file mode 100644
index 0000000000..002f80a20b
--- /dev/null
+++ b/jme3-awt-dialogs/src/main/java/com/jme3/awt/AWTErrorDialog.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009-2022 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.awt;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+/**
+ * Simple dialog for displaying error messages,
+ *
+ * @author kwando
+ */
+public class AWTErrorDialog extends JDialog {
+ public static String DEFAULT_TITLE = "Error in application";
+ public static int PADDING = 8;
+
+ /**
+ * Create a new Dialog with a title and a message.
+ *
+ * @param message the message to display
+ * @param title the title to display
+ */
+ protected AWTErrorDialog(String message, String title) {
+ setTitle(title);
+ setSize(new Dimension(600, 400));
+ setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ setLocationRelativeTo(null);
+
+ Container container = getContentPane();
+ container.setLayout(new BorderLayout());
+
+ JTextArea textArea = new JTextArea();
+ textArea.setText(message);
+ textArea.setEditable(false);
+ textArea.setMargin(new Insets(PADDING, PADDING, PADDING, PADDING));
+ add(new JScrollPane(textArea), BorderLayout.CENTER);
+
+ final JDialog dialog = this;
+ JButton button = new JButton(new AbstractAction("OK"){
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ dialog.dispose();
+ }
+ });
+ add(button, BorderLayout.SOUTH);
+ }
+
+ protected AWTErrorDialog(String message){
+ this(message, DEFAULT_TITLE);
+ }
+
+ /**
+ * Show a dialog with the provided message.
+ *
+ * @param message the message to display
+ */
+ public static void showDialog(String message) {
+ AWTErrorDialog dialog = new AWTErrorDialog(message);
+ dialog.setVisible(true);
+ }
+}
diff --git a/jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java b/jme3-awt-dialogs/src/main/java/com/jme3/awt/AWTSettingsDialog.java
similarity index 82%
rename from jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java
rename to jme3-awt-dialogs/src/main/java/com/jme3/awt/AWTSettingsDialog.java
index 9e20251dac..34744b2298 100644
--- a/jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java
+++ b/jme3-awt-dialogs/src/main/java/com/jme3/awt/AWTSettingsDialog.java
@@ -29,9 +29,12 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.app;
+package com.jme3.awt;
+import com.jme3.asset.AssetNotFoundException;
import com.jme3.system.AppSettings;
+import com.jme3.system.JmeSystem;
+
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
@@ -46,6 +49,8 @@
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
@@ -64,24 +69,23 @@
* @author Eric Woroshow
* @author Joshua Slack - reworked for proper use of GL commands.
*/
-public final class SettingsDialog extends JFrame {
+public final class AWTSettingsDialog extends JFrame {
public static interface SelectionListener {
public void onSelection(int selection);
}
- private static final Logger logger = Logger.getLogger(SettingsDialog.class.getName());
+
+ private static final Logger logger = Logger.getLogger(AWTSettingsDialog.class.getName());
private static final long serialVersionUID = 1L;
- public static final int NO_SELECTION = 0,
- APPROVE_SELECTION = 1,
- CANCEL_SELECTION = 2;
-
+ public static final int NO_SELECTION = 0, APPROVE_SELECTION = 1, CANCEL_SELECTION = 2;
+
// Resource bundle for i18n.
ResourceBundle resourceBundle = ResourceBundle.getBundle("com.jme3.app/SettingsDialog");
-
+
// the instance being configured
private final AppSettings source;
-
+
// Title Image
private URL imageFile = null;
// Array of supported display modes
@@ -109,7 +113,70 @@ public static interface SelectionListener {
private int minWidth = 0;
private int minHeight = 0;
-
+
+ public static boolean showDialog(AppSettings sourceSettings) {
+ return showDialog(sourceSettings, true);
+ }
+
+ public static boolean showDialog(AppSettings sourceSettings, boolean loadSettings) {
+ String iconPath = sourceSettings.getSettingsDialogImage();
+ final URL iconUrl = JmeSystem.class.getResource(iconPath.startsWith("/") ? iconPath : "/" + iconPath);
+ if (iconUrl == null) {
+ throw new AssetNotFoundException(sourceSettings.getSettingsDialogImage());
+ }
+ return showDialog(sourceSettings, iconUrl, loadSettings);
+ }
+
+ public static boolean showDialog(AppSettings sourceSettings, String imageFile, boolean loadSettings) {
+ return showDialog(sourceSettings, getURL(imageFile), loadSettings);
+ }
+
+ public static boolean showDialog(AppSettings sourceSettings, URL imageFile, boolean loadSettings) {
+ if (SwingUtilities.isEventDispatchThread()) {
+ throw new IllegalStateException("Cannot run from EDT");
+ }
+ if (GraphicsEnvironment.isHeadless()) {
+ throw new IllegalStateException("Cannot show dialog in headless environment");
+ }
+
+ AppSettings settings = new AppSettings(false);
+ settings.copyFrom(sourceSettings);
+
+ Object lock = new Object();
+ AtomicBoolean done = new AtomicBoolean();
+ AtomicInteger result = new AtomicInteger();
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ final SelectionListener selectionListener = new SelectionListener() {
+ @Override
+ public void onSelection(int selection) {
+ synchronized (lock) {
+ done.set(true);
+ result.set(selection);
+ lock.notifyAll();
+ }
+ }
+ };
+ AWTSettingsDialog dialog = new AWTSettingsDialog(settings, imageFile, loadSettings);
+ dialog.setSelectionListener(selectionListener);
+ dialog.showDialog();
+ }
+ });
+ synchronized (lock) {
+ while (!done.get()) {
+ try {
+ lock.wait();
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+
+ sourceSettings.copyFrom(settings);
+
+ return result.get() == AWTSettingsDialog.APPROVE_SELECTION;
+ }
+
/**
* Instantiate a SettingsDialog for the primary display.
*
@@ -123,12 +190,12 @@ public static interface SelectionListener {
* @throws IllegalArgumentException
* if the source is null
*/
- public SettingsDialog(AppSettings source, String imageFile, boolean loadSettings) {
+ protected AWTSettingsDialog(AppSettings source, String imageFile, boolean loadSettings) {
this(source, getURL(imageFile), loadSettings);
}
/**
- * Instantiate a SettingsDialog for the primary display.
+ * /** Instantiate a SettingsDialog for the primary display.
*
* @param source
* the AppSettings object (not null)
@@ -140,7 +207,7 @@ public SettingsDialog(AppSettings source, String imageFile, boolean loadSettings
* @throws IllegalArgumentException
* if the source is null
*/
- public SettingsDialog(AppSettings source, URL imageFile, boolean loadSettings) {
+ protected AWTSettingsDialog(AppSettings source, URL imageFile, boolean loadSettings) {
if (source == null) {
throw new IllegalArgumentException("Settings source cannot be null");
}
@@ -148,32 +215,31 @@ public SettingsDialog(AppSettings source, URL imageFile, boolean loadSettings) {
this.source = source;
this.imageFile = imageFile;
- //setModal(true);
+ // setModal(true);
setAlwaysOnTop(true);
setResizable(false);
AppSettings registrySettings = new AppSettings(true);
String appTitle;
- if(source.getTitle()!=null){
+ if (source.getTitle() != null) {
appTitle = source.getTitle();
- }else{
- appTitle = registrySettings.getTitle();
+ } else {
+ appTitle = registrySettings.getTitle();
}
-
+
minWidth = source.getMinWidth();
minHeight = source.getMinHeight();
-
+
try {
registrySettings.load(appTitle);
} catch (BackingStoreException ex) {
- logger.log(Level.WARNING,
- "Failed to load settings", ex);
+ logger.log(Level.WARNING, "Failed to load settings", ex);
}
if (loadSettings) {
source.copyFrom(registrySettings);
- } else if(!registrySettings.isEmpty()) {
+ } else if (!registrySettings.isEmpty()) {
source.mergeFrom(registrySettings);
}
@@ -183,17 +249,13 @@ public SettingsDialog(AppSettings source, URL imageFile, boolean loadSettings) {
Arrays.sort(modes, new DisplayModeSorter());
DisplayMode[] merged = new DisplayMode[modes.length + windowDefaults.length];
-
+
int wdIndex = 0;
int dmIndex = 0;
int mergedIndex;
-
- for (mergedIndex = 0;
- mergedIndex= modes.length) {
merged[mergedIndex] = windowDefaults[wdIndex++];
} else if (wdIndex >= windowDefaults.length) {
@@ -213,13 +275,13 @@ public SettingsDialog(AppSettings source, URL imageFile, boolean loadSettings) {
merged[mergedIndex] = windowDefaults[wdIndex++];
}
}
-
+
if (merged.length == mergedIndex) {
windowModes = merged;
} else {
windowModes = Arrays.copyOfRange(merged, 0, mergedIndex);
}
-
+
createUI();
}
@@ -252,9 +314,6 @@ public void setMinHeight(int minHeight) {
this.minHeight = minHeight;
}
-
-
-
/**
* setImage sets the background image of the dialog.
*
@@ -266,7 +325,7 @@ public void setImage(String image) {
URL file = new URL("file:" + image);
setImage(file);
} catch (MalformedURLException e) {
- logger.log(Level.WARNING, "Couldn’t read from file '" + image + "'", e);
+ logger.log(Level.WARNING, "Couldn’t read from file '" + image + "'", e);
}
}
@@ -283,21 +342,21 @@ public void setImage(URL image) {
}
/**
- * showDialog sets this dialog as visible, and brings it to
- * the front.
+ * showDialog sets this dialog as visible, and brings it to the
+ * front.
*/
public void showDialog() {
setLocationRelativeTo(null);
- setVisible(true);
+ setVisible(true);
toFront();
}
-
+
/**
* init creates the components to use the dialog.
*/
private void createUI() {
GridBagConstraints gbc;
-
+
JPanel mainPanel = new JPanel(new GridBagLayout());
addWindowListener(new WindowAdapter() {
@@ -310,13 +369,13 @@ public void windowClosing(WindowEvent e) {
});
if (source.getIcons() != null) {
- safeSetIconImages( Arrays.asList((BufferedImage[]) source.getIcons()) );
+ safeSetIconImages(Arrays.asList((BufferedImage[]) source.getIcons()));
}
setTitle(MessageFormat.format(resourceBundle.getString("frame.title"), source.getTitle()));
-
+
// The buttons...
- JButton ok = new JButton(resourceBundle.getString("button.ok"));
+ JButton ok = new JButton(resourceBundle.getString("button.ok"));
JButton cancel = new JButton(resourceBundle.getString("button.cancel"));
icon = new JLabel(imageFile != null ? new ImageIcon(imageFile) : null);
@@ -330,8 +389,7 @@ public void keyPressed(KeyEvent e) {
setUserSelection(APPROVE_SELECTION);
dispose();
}
- }
- else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+ } else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
setUserSelection(CANCEL_SELECTION);
dispose();
}
@@ -357,10 +415,10 @@ public void actionPerformed(ActionEvent e) {
});
vsyncBox = new JCheckBox(resourceBundle.getString("checkbox.vsync"));
vsyncBox.setSelected(source.isVSync());
-
+
gammaBox = new JCheckBox(resourceBundle.getString("checkbox.gamma"));
gammaBox.setSelected(source.isGammaCorrection());
-
+
gbc = new GridBagConstraints();
gbc.weightx = 0.5;
gbc.gridx = 0;
@@ -370,20 +428,19 @@ public void actionPerformed(ActionEvent e) {
mainPanel.add(fullscreenBox, gbc);
gbc = new GridBagConstraints();
gbc.weightx = 0.5;
- // gbc.insets = new Insets(4, 16, 0, 4);
+ // gbc.insets = new Insets(4, 16, 0, 4);
gbc.gridx = 2;
- // gbc.gridwidth = 2;
+ // gbc.gridwidth = 2;
gbc.gridy = 1;
gbc.anchor = GridBagConstraints.EAST;
mainPanel.add(vsyncBox, gbc);
gbc = new GridBagConstraints();
gbc.weightx = 0.5;
gbc.gridx = 3;
- gbc.gridy = 1;
+ gbc.gridy = 1;
gbc.anchor = GridBagConstraints.WEST;
mainPanel.add(gammaBox, gbc);
-
gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
@@ -432,7 +489,7 @@ public void actionPerformed(ActionEvent e) {
gbc.gridy = 3;
gbc.anchor = GridBagConstraints.WEST;
mainPanel.add(antialiasCombo, gbc);
-
+
// Set the button action listeners. Cancel disposes without saving, OK
// saves.
ok.addActionListener(new ActionListener() {
@@ -442,10 +499,14 @@ public void actionPerformed(ActionEvent e) {
if (verifyAndSaveCurrentSelection()) {
setUserSelection(APPROVE_SELECTION);
dispose();
-
- // System.gc() should be called to prevent "X Error of failed request: RenderBadPicture (invalid Picture parameter)"
- // on Linux when using AWT/Swing + GLFW.
- // For more info see: https://github.com/LWJGL/lwjgl3/issues/149, https://hub.jmonkeyengine.org/t/experimenting-lwjgl3/37275
+
+ // System.gc() should be called to prevent "X Error of
+ // failed request: RenderBadPicture (invalid Picture
+ // parameter)"
+ // on Linux when using AWT/Swing + GLFW.
+ // For more info see:
+ // https://github.com/LWJGL/lwjgl3/issues/149,
+ // https://hub.jmonkeyengine.org/t/experimenting-lwjgl3/37275
System.gc();
System.gc();
}
@@ -466,7 +527,7 @@ public void actionPerformed(ActionEvent e) {
gbc.gridwidth = 2;
gbc.gridy = 4;
gbc.anchor = GridBagConstraints.EAST;
- mainPanel.add(ok, gbc);
+ mainPanel.add(ok, gbc);
gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 16, 4, 4);
gbc.gridx = 2;
@@ -484,35 +545,42 @@ public void actionPerformed(ActionEvent e) {
this.getContentPane().add(mainPanel);
pack();
-
+
mainPanel.getRootPane().setDefaultButton(ok);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
- // Fill in the combos once the window has opened so that the insets can be read.
- // The assumption is made that the settings window and the display window will have the
- // same insets as that is used to resize the "full screen windowed" mode appropriately.
+ // Fill in the combos once the window has opened so that the
+ // insets can be read.
+ // The assumption is made that the settings window and the
+ // display window will have the
+ // same insets as that is used to resize the "full screen
+ // windowed" mode appropriately.
updateResolutionChoices();
if (source.getWidth() != 0 && source.getHeight() != 0) {
- displayResCombo.setSelectedItem(source.getWidth() + " x "
- + source.getHeight());
+ displayResCombo.setSelectedItem(source.getWidth() + " x " + source.getHeight());
} else {
- displayResCombo.setSelectedIndex(displayResCombo.getItemCount()-1);
+ displayResCombo.setSelectedIndex(displayResCombo.getItemCount() - 1);
}
updateAntialiasChoices();
colorDepthCombo.setSelectedItem(source.getBitsPerPixel() + " bpp");
}
- });
-
+ });
+
}
- /* Access JDialog.setIconImages by reflection in case we're running on JRE < 1.6 */
+ /*
+ * Access JDialog.setIconImages by reflection in case we're running on JRE <
+ * 1.6
+ */
private void safeSetIconImages(List extends Image> icons) {
try {
- // Due to Java bug 6445278, we try to set icon on our shared owner frame first.
- // Otherwise, our alt-tab icon will be the Java default under Windows.
+ // Due to Java bug 6445278, we try to set icon on our shared owner
+ // frame first.
+ // Otherwise, our alt-tab icon will be the Java default under
+ // Windows.
Window owner = getOwner();
if (owner != null) {
Method setIconImages = owner.getClass().getMethod("setIconImages", List.class);
@@ -591,7 +659,7 @@ private boolean verifyAndSaveCurrentSelection() {
}
if (valid) {
- //use the AppSettings class to save it to backing store
+ // use the AppSettings class to save it to backing store
source.setWidth(width);
source.setHeight(height);
source.setBitsPerPixel(depth);
@@ -599,7 +667,7 @@ private boolean verifyAndSaveCurrentSelection() {
source.setFullscreen(fullscreen);
source.setVSync(vsync);
source.setGammaCorrection(gamma);
- //source.setRenderer(renderer);
+ // source.setRenderer(renderer);
source.setSamples(multisample);
String appTitle = source.getTitle();
@@ -607,13 +675,10 @@ private boolean verifyAndSaveCurrentSelection() {
try {
source.save(appTitle);
} catch (BackingStoreException ex) {
- logger.log(Level.WARNING,
- "Failed to save setting changes", ex);
+ logger.log(Level.WARNING, "Failed to save setting changes", ex);
}
} else {
- showError(
- this,
- resourceBundle.getString("error.unsupportedmode"));
+ showError(this, resourceBundle.getString("error.unsupportedmode"));
}
return valid;
@@ -623,7 +688,7 @@ private boolean verifyAndSaveCurrentSelection() {
* setUpChooser retrieves all available display modes and
* places them in a JComboBox. The resolution specified by
* AppSettings is used as the default value.
- *
+ *
* @return the combo box of display modes.
*/
private JComboBox setUpResolutionChooser() {
@@ -668,7 +733,7 @@ private void updateDisplayChoices() {
displayFreqCombo.setModel(new DefaultComboBoxModel<>(freqs));
// Try to reset freq
displayFreqCombo.setSelectedItem(displayFreq);
-
+
if (!displayFreqCombo.getSelectedItem().equals(displayFreq)) {
// Cannot find saved frequency in available frequencies.
// Choose the closest one to 60 Hz.
@@ -684,21 +749,17 @@ private void updateDisplayChoices() {
*/
private void updateResolutionChoices() {
if (!fullscreenBox.isSelected()) {
- displayResCombo.setModel(new DefaultComboBoxModel<>(
- getWindowedResolutions(windowModes)));
+ displayResCombo.setModel(new DefaultComboBoxModel<>(getWindowedResolutions(windowModes)));
if (displayResCombo.getItemCount() > 0) {
- displayResCombo.setSelectedIndex(displayResCombo.getItemCount()-1);
+ displayResCombo.setSelectedIndex(displayResCombo.getItemCount() - 1);
}
- colorDepthCombo.setModel(new DefaultComboBoxModel<>(new String[]{
- "24 bpp", "16 bpp"}));
- displayFreqCombo.setModel(new DefaultComboBoxModel<>(
- new String[]{resourceBundle.getString("refresh.na")}));
+ colorDepthCombo.setModel(new DefaultComboBoxModel<>(new String[] { "24 bpp", "16 bpp" }));
+ displayFreqCombo.setModel(new DefaultComboBoxModel<>(new String[] { resourceBundle.getString("refresh.na") }));
displayFreqCombo.setEnabled(false);
} else {
- displayResCombo.setModel(new DefaultComboBoxModel<>(
- getResolutions(modes, Integer.MAX_VALUE, Integer.MAX_VALUE)));
+ displayResCombo.setModel(new DefaultComboBoxModel<>(getResolutions(modes, Integer.MAX_VALUE, Integer.MAX_VALUE)));
if (displayResCombo.getItemCount() > 0) {
- displayResCombo.setSelectedIndex(displayResCombo.getItemCount()-1);
+ displayResCombo.setSelectedIndex(displayResCombo.getItemCount() - 1);
}
displayFreqCombo.setEnabled(true);
updateDisplayChoices();
@@ -708,9 +769,9 @@ private void updateResolutionChoices() {
private void updateAntialiasChoices() {
// maybe in the future will add support for determining this info
// through PBuffer
- String[] choices = new String[]{resourceBundle.getString("antialias.disabled"), "2x", "4x", "6x", "8x", "16x"};
+ String[] choices = new String[] { resourceBundle.getString("antialias.disabled"), "2x", "4x", "6x", "8x", "16x" };
antialiasCombo.setModel(new DefaultComboBoxModel<>(choices));
- antialiasCombo.setSelectedItem(choices[Math.min(source.getSamples()/2,5)]);
+ antialiasCombo.setSelectedItem(choices[Math.min(source.getSamples() / 2, 5)]);
}
//
@@ -732,19 +793,19 @@ private static URL getURL(String file) {
}
private static void showError(java.awt.Component parent, String message) {
- JOptionPane.showMessageDialog(parent, message, "Error",
- JOptionPane.ERROR_MESSAGE);
+ JOptionPane.showMessageDialog(parent, message, "Error", JOptionPane.ERROR_MESSAGE);
}
/**
- * Returns every unique resolution from an array of DisplayModes
- * where the resolution is greater than the configured minimums.
+ * Returns every unique resolution from an array of
+ * DisplayModes where the resolution is greater than the
+ * configured minimums.
*/
private String[] getResolutions(DisplayMode[] modes, int heightLimit, int widthLimit) {
Insets insets = getInsets();
heightLimit -= insets.top + insets.bottom;
widthLimit -= insets.left + insets.right;
-
+
Set resolutions = new LinkedHashSet<>(modes.length);
for (DisplayMode mode : modes) {
int height = mode.getHeight();
@@ -756,7 +817,7 @@ private String[] getResolutions(DisplayMode[] modes, int heightLimit, int widthL
if (width >= widthLimit) {
width = widthLimit;
}
-
+
String res = width + " x " + height;
resolutions.add(res);
}
@@ -764,16 +825,17 @@ private String[] getResolutions(DisplayMode[] modes, int heightLimit, int widthL
return resolutions.toArray(new String[0]);
}
-
+
/**
- * Returns every unique resolution from an array of DisplayModes
- * where the resolution is greater than the configured minimums and the height
- * is less than the current screen resolution.
+ * Returns every unique resolution from an array of
+ * DisplayModes where the resolution is greater than the
+ * configured minimums and the height is less than the current screen
+ * resolution.
*/
private String[] getWindowedResolutions(DisplayMode[] modes) {
int maxHeight = 0;
int maxWidth = 0;
-
+
for (DisplayMode mode : modes) {
if (maxHeight < mode.getHeight()) {
maxHeight = mode.getHeight();
@@ -813,7 +875,8 @@ private static String[] getDepths(String resolution, DisplayMode[] modes) {
}
if (depths.isEmpty()) {
- // add some default depths, possible system is multi-depth supporting
+ // add some default depths, possible system is multi-depth
+ // supporting
depths.add("24 bpp");
}
@@ -823,8 +886,7 @@ private static String[] getDepths(String resolution, DisplayMode[] modes) {
/**
* Returns every possible refresh rate for the given resolution.
*/
- private static String[] getFrequencies(String resolution,
- DisplayMode[] modes) {
+ private static String[] getFrequencies(String resolution, DisplayMode[] modes) {
List freqs = new ArrayList<>(4);
for (DisplayMode mode : modes) {
String res = mode.getWidth() + " x " + mode.getHeight();
@@ -841,13 +903,13 @@ private static String[] getFrequencies(String resolution,
return freqs.toArray(new String[0]);
}
-
+
/**
* Chooses the closest frequency to 60 Hz.
*
* @param resolution
* @param modes
- * @return
+ * @return
*/
private static String getBestFrequency(String resolution, DisplayMode[] modes) {
int closest = Integer.MAX_VALUE;
@@ -861,7 +923,7 @@ private static String getBestFrequency(String resolution, DisplayMode[] modes) {
}
}
}
-
+
if (closest != Integer.MAX_VALUE) {
return closest + " Hz";
} else {
@@ -870,8 +932,8 @@ private static String getBestFrequency(String resolution, DisplayMode[] modes) {
}
/**
- * Utility class for sorting DisplayModes. Sorts by
- * resolution, then bit depth, and then finally refresh rate.
+ * Utility class for sorting DisplayModes. Sorts by resolution,
+ * then bit depth, and then finally refresh rate.
*/
private class DisplayModeSorter implements Comparator {
diff --git a/jme3-awt-dialogs/src/main/java/com/jme3/system/JmeDialogsFactoryImpl.java b/jme3-awt-dialogs/src/main/java/com/jme3/system/JmeDialogsFactoryImpl.java
new file mode 100644
index 0000000000..7c5b12c97d
--- /dev/null
+++ b/jme3-awt-dialogs/src/main/java/com/jme3/system/JmeDialogsFactoryImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009-2022 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.system;
+
+import com.jme3.awt.AWTErrorDialog;
+import com.jme3.awt.AWTSettingsDialog;
+
+public class JmeDialogsFactoryImpl implements JmeDialogsFactory {
+
+ public boolean showSettingsDialog(AppSettings settings, boolean loadFromRegistry){
+ return AWTSettingsDialog.showDialog(settings,loadFromRegistry);
+ }
+
+ public void showErrorDialog(String message){
+ AWTErrorDialog.showDialog(message);
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java b/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java
index 6849a35edd..626dec4bfd 100644
--- a/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java
+++ b/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java
@@ -667,10 +667,10 @@ public void handleError(String errMsg, Throwable t) {
// Display error message on screen if not in headless mode
if (context.getType() != JmeContext.Type.Headless) {
if (t != null) {
- JmeSystem.showErrorDialog(errMsg + "\n" + t.getClass().getSimpleName()
+ JmeSystem.handleErrorMessage(errMsg + "\n" + t.getClass().getSimpleName()
+ (t.getMessage() != null ? ": " + t.getMessage() : ""));
} else {
- JmeSystem.showErrorDialog(errMsg);
+ JmeSystem.handleErrorMessage(errMsg);
}
}
diff --git a/jme3-core/src/main/java/com/jme3/system/JmeDialogsFactory.java b/jme3-core/src/main/java/com/jme3/system/JmeDialogsFactory.java
new file mode 100644
index 0000000000..63113c729d
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/system/JmeDialogsFactory.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009-2022 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.system;
+
+public interface JmeDialogsFactory {
+ /**
+ * Set a function to handler app settings.
+ * The default implementation shows a settings dialog if available.
+ * @param handler handler function that accepts as argument an instance of AppSettings
+ * to transform and a boolean with the value of true if the settings are expected to be loaded from
+ * the user registry. The handler function returns false if the configuration is interrupted (eg.the the dialog was closed)
+ * or true otherwise.
+ */
+ public boolean showSettingsDialog(AppSettings settings, boolean loadFromRegistry);
+
+ /**
+ * Set function to handle errors.
+ * The default implementation show a dialog if available.
+ * @param handler Consumer to which the error is passed as String
+ */
+ public void showErrorDialog(String message);
+}
diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java
index 561926a9e7..4a832916c8 100644
--- a/jme3-core/src/main/java/com/jme3/system/JmeSystem.java
+++ b/jme3-core/src/main/java/com/jme3/system/JmeSystem.java
@@ -34,6 +34,7 @@
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioRenderer;
import com.jme3.input.SoftTextDialogInput;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -41,6 +42,8 @@
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.ByteBuffer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -154,10 +157,7 @@ public static AssetManager newAssetManager() {
return systemDelegate.newAssetManager();
}
- public static boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) {
- checkDelegate();
- return systemDelegate.showSettingsDialog(sourceSettings, loadFromRegistry);
- }
+
/**
* Determine which Platform (operating system and architecture) the
@@ -190,14 +190,44 @@ public static URL getPlatformAssetConfigURL() {
* feels is appropriate. If this is a headless or an offscreen surface
* context, this method should do nothing.
*
+ * @deprecated Use JmeSystem.handleErrorMessage(String) instead
* @param message The error message to display. May contain new line
* characters.
*/
+ @Deprecated
public static void showErrorDialog(String message){
+ handleErrorMessage(message);
+ }
+
+ public static void handleErrorMessage(String message){
+ checkDelegate();
+ systemDelegate.handleErrorMessage(message);
+ }
+
+ public static void setErrorMessageHandler(Consumer handler){
+ checkDelegate();
+ systemDelegate.setErrorMessageHandler(handler);
+ }
+
+
+ public static void handleSettings(AppSettings sourceSettings, boolean loadFromRegistry){
+ checkDelegate();
+ systemDelegate.handleSettings(sourceSettings, loadFromRegistry);
+ }
+
+ public static void setSettingsHandler(BiFunction handler){
+ checkDelegate();
+ systemDelegate.setSettingsHandler(handler);
+ }
+
+
+ @Deprecated
+ public static boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) {
checkDelegate();
- systemDelegate.showErrorDialog(message);
+ return systemDelegate.showSettingsDialog(sourceSettings, loadFromRegistry);
}
+
public static void initialize(AppSettings settings) {
checkDelegate();
systemDelegate.initialize(settings);
diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
index 5e701f3a0f..35143fca4a 100644
--- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
+++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
@@ -35,14 +35,18 @@
import com.jme3.asset.DesktopAssetManager;
import com.jme3.audio.AudioRenderer;
import com.jme3.input.SoftTextDialogInput;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.EnumMap;
import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -58,6 +62,32 @@ public abstract class JmeSystemDelegate {
protected Map storageFolders = new EnumMap<>(JmeSystem.StorageFolderType.class);
protected SoftTextDialogInput softTextDialogInput = null;
+ protected Consumer errorMessageHandler = (message) -> {
+ JmeDialogsFactory dialogFactory = null;
+ try {
+ dialogFactory = (JmeDialogsFactory)Class.forName("com.jme3.system.JmeDialogsFactoryImpl").getConstructor().newInstance();
+ } catch(ClassNotFoundException e){
+ logger.warning("JmeDialogsFactory implementation not found.");
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ e.printStackTrace();
+ }
+ if(dialogFactory != null) dialogFactory.showErrorDialog(message);
+ else System.err.println(message);
+ };
+
+ protected BiFunction settingsHandler = (settings,loadFromRegistry) -> {
+ JmeDialogsFactory dialogFactory = null;
+ try {
+ dialogFactory = (JmeDialogsFactory)Class.forName("com.jme3.system.JmeDialogsFactoryImpl").getConstructor().newInstance();
+ } catch(ClassNotFoundException e){
+ logger.warning("JmeDialogsFactory implementation not found.");
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ e.printStackTrace();
+ }
+ if(dialogFactory != null) return dialogFactory.showSettingsDialog(settings, loadFromRegistry);
+ return true;
+ };
+
public synchronized File getStorageFolder(JmeSystem.StorageFolderType type) {
File storageFolder = null;
@@ -133,9 +163,56 @@ public final AssetManager newAssetManager() {
public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
- public abstract void showErrorDialog(String message);
+ /**
+ * Set function to handle errors.
+ * The default implementation show a dialog if available.
+ * @param handler Consumer to which the error is passed as String
+ */
+ public void setErrorMessageHandler(Consumer handler){
+ errorMessageHandler = handler;
+ }
+
+ /**
+ * Internal use only: submit an error to the error message handler
+ */
+ public void handleErrorMessage(String message){
+ if(errorMessageHandler != null) errorMessageHandler.accept(message);
+ }
+
+ /**
+ * Set a function to handler app settings.
+ * The default implementation shows a settings dialog if available.
+ * @param handler handler function that accepts as argument an instance of AppSettings
+ * to transform and a boolean with the value of true if the settings are expected to be loaded from
+ * the user registry. The handler function returns false if the configuration is interrupted (eg.the the dialog was closed)
+ * or true otherwise.
+ */
+ public void setSettingsHandler(BiFunction handler){
+ settingsHandler = handler;
+ }
+
+ /**
+ * Internal use only: summon the settings handler
+ */
+ public boolean handleSettings(AppSettings settings, boolean loadFromRegistry){
+ if(settingsHandler != null) return settingsHandler.apply(settings,loadFromRegistry);
+ return true;
+ }
+
+ /**
+ * @deprecated Use JmeSystemDelegate.handleErrorMessage(String) instead
+ * @param message
+ */
+ @Deprecated
+ public void showErrorDialog(String message){
+ handleErrorMessage(message);
+ }
+
+ @Deprecated
+ public boolean showSettingsDialog(AppSettings settings, boolean loadFromRegistry){
+ return handleSettings(settings, loadFromRegistry);
+ }
- public abstract boolean showSettingsDialog(AppSettings sourceSettings, boolean loadFromRegistry);
private boolean is64Bit(String arch) {
if (arch.equals("x86")) {
diff --git a/jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java b/jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java
index b9beac7f69..ca981877eb 100644
--- a/jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java
+++ b/jme3-core/src/test/java/com/jme3/system/MockJmeSystemDelegate.java
@@ -43,15 +43,6 @@ public class MockJmeSystemDelegate extends JmeSystemDelegate {
public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
}
- @Override
- public void showErrorDialog(String message) {
- }
-
- @Override
- public boolean showSettingsDialog(AppSettings sourceSettings, boolean loadFromRegistry) {
- return false;
- }
-
@Override
public URL getPlatformAssetConfigURL() {
return Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/General.cfg");
diff --git a/jme3-desktop/src/main/java/com/jme3/system/ErrorDialog.java b/jme3-desktop/src/main/java/com/jme3/system/ErrorDialog.java
deleted file mode 100644
index 26f85be4e0..0000000000
--- a/jme3-desktop/src/main/java/com/jme3/system/ErrorDialog.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.jme3.system;
-
-import java.awt.BorderLayout;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import javax.swing.AbstractAction;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-
-/**
- * Simple dialog for displaying error messages,
- *
- * @author kwando
- */
-public class ErrorDialog extends JDialog {
- public static String DEFAULT_TITLE = "Error in application";
- public static int PADDING = 8;
-
- /**
- * Create a new Dialog with a title and a message.
- *
- * @param message the message to display
- * @param title the title to display
- */
- public ErrorDialog(String message, String title) {
- setTitle(title);
- setSize(new Dimension(600, 400));
- setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- setLocationRelativeTo(null);
-
- Container container = getContentPane();
- container.setLayout(new BorderLayout());
-
- JTextArea textArea = new JTextArea();
- textArea.setText(message);
- textArea.setEditable(false);
- textArea.setMargin(new Insets(PADDING, PADDING, PADDING, PADDING));
- add(new JScrollPane(textArea), BorderLayout.CENTER);
-
- final JDialog dialog = this;
- JButton button = new JButton(new AbstractAction("OK"){
- @Override
- public void actionPerformed(ActionEvent e) {
- dialog.dispose();
- }
- });
- add(button, BorderLayout.SOUTH);
- }
-
- public ErrorDialog(String message){
- this(message, DEFAULT_TITLE);
- }
-
- /**
- * Show a dialog with the provided message.
- *
- * @param message the message to display
- */
- public static void showDialog(String message) {
- ErrorDialog dialog = new ErrorDialog(message);
- dialog.setVisible(true);
- }
-}
diff --git a/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java b/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java
index 215a301e73..3a2882a241 100644
--- a/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java
+++ b/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java
@@ -31,9 +31,6 @@
*/
package com.jme3.system;
-import com.jme3.app.SettingsDialog;
-import com.jme3.app.SettingsDialog.SelectionListener;
-import com.jme3.asset.AssetNotFoundException;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.openal.AL;
import com.jme3.audio.openal.ALAudioRenderer;
@@ -42,13 +39,16 @@
import com.jme3.system.JmeContext.Type;
import com.jme3.texture.Image;
import com.jme3.texture.image.ColorSpace;
-import com.jme3.util.Screenshots;
import jme3tools.converters.ImageToAwt;
-import java.awt.EventQueue;
-import java.awt.Graphics2D;
-import java.awt.GraphicsEnvironment;
-import java.awt.RenderingHints;
+import javax.imageio.IIOImage;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.MemoryCacheImageOutputStream;
+import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
@@ -57,17 +57,7 @@
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.ByteBuffer;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
-import javax.imageio.IIOImage;
-import javax.imageio.ImageIO;
-import javax.imageio.ImageWriteParam;
-import javax.imageio.ImageWriter;
-import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
-import javax.imageio.stream.ImageOutputStream;
-import javax.imageio.stream.MemoryCacheImageOutputStream;
-import javax.swing.SwingUtilities;
/**
*
@@ -75,6 +65,9 @@
*/
public class JmeDesktopSystem extends JmeSystemDelegate {
+ public JmeDesktopSystem() {
+ }
+
@Override
public URL getPlatformAssetConfigURL() {
return Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Desktop.cfg");
@@ -132,82 +125,6 @@ public void writeImageFile(OutputStream outStream, String format, ByteBuffer ima
}
}
- @Override
- public void showErrorDialog(String message) {
- if (!GraphicsEnvironment.isHeadless()) {
- final String msg = message;
- EventQueue.invokeLater(new Runnable() {
- @Override
- public void run() {
- ErrorDialog.showDialog(msg);
- }
- });
- } else {
- System.err.println("[JME ERROR] " + message);
- }
- }
-
- @Override
- public boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) {
- if (SwingUtilities.isEventDispatchThread()) {
- throw new IllegalStateException("Cannot run from EDT");
- }
- if (GraphicsEnvironment.isHeadless()) {
- throw new IllegalStateException("Cannot show dialog in headless environment");
- }
-
- final AppSettings settings = new AppSettings(false);
- settings.copyFrom(sourceSettings);
- String iconPath = sourceSettings.getSettingsDialogImage();
- if(iconPath == null){
- iconPath = "";
- }
- final URL iconUrl = JmeSystem.class.getResource(iconPath.startsWith("/") ? iconPath : "/" + iconPath);
- if (iconUrl == null) {
- throw new AssetNotFoundException(sourceSettings.getSettingsDialogImage());
- }
-
- final AtomicBoolean done = new AtomicBoolean();
- final AtomicInteger result = new AtomicInteger();
- final Object lock = new Object();
-
- final SelectionListener selectionListener = new SelectionListener() {
-
- @Override
- public void onSelection(int selection) {
- synchronized (lock) {
- done.set(true);
- result.set(selection);
- lock.notifyAll();
- }
- }
- };
- SwingUtilities.invokeLater(new Runnable() {
-
- @Override
- public void run() {
- synchronized (lock) {
- SettingsDialog dialog = new SettingsDialog(settings, iconUrl, loadFromRegistry);
- dialog.setSelectionListener(selectionListener);
- dialog.showDialog();
- }
- }
- });
-
- synchronized (lock) {
- while (!done.get()) {
- try {
- lock.wait();
- } catch (InterruptedException ex) {
- }
- }
- }
-
- sourceSettings.copyFrom(settings);
-
- return result.get() == SettingsDialog.APPROVE_SELECTION;
- }
-
@SuppressWarnings("unchecked")
private JmeContext newContextLwjgl(AppSettings settings, JmeContext.Type type) {
try {
diff --git a/jme3-examples/build.gradle b/jme3-examples/build.gradle
index a6e9888edf..fbed866b7d 100644
--- a/jme3-examples/build.gradle
+++ b/jme3-examples/build.gradle
@@ -25,6 +25,7 @@ dependencies {
implementation project(':jme3-niftygui')
implementation project(':jme3-plugins')
implementation project(':jme3-terrain')
+ implementation project(':jme3-awt-dialogs')
runtimeOnly project(':jme3-testdata')
}
diff --git a/jme3-ios/src/main/java/com/jme3/system/ios/JmeIosSystem.java b/jme3-ios/src/main/java/com/jme3/system/ios/JmeIosSystem.java
index 820e387e54..77f41c1f82 100644
--- a/jme3-ios/src/main/java/com/jme3/system/ios/JmeIosSystem.java
+++ b/jme3-ios/src/main/java/com/jme3/system/ios/JmeIosSystem.java
@@ -35,6 +35,7 @@
import com.jme3.system.JmeContext;
import com.jme3.system.JmeSystemDelegate;
import com.jme3.system.NullContext;
+import com.jme3.util.functional.VoidFunction;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.ios.IosAL;
import com.jme3.audio.ios.IosALC;
@@ -54,6 +55,13 @@
*/
public class JmeIosSystem extends JmeSystemDelegate {
+ public JmeIosSystem() {
+ setErrorMessageHandler((message) -> {
+ showDialog(message);
+ System.err.println("JME APPLICATION ERROR:" + message);
+ });
+ }
+
@Override
public URL getPlatformAssetConfigURL() {
return Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/IOS.cfg");
@@ -64,18 +72,11 @@ public void writeImageFile(OutputStream outStream, String format, ByteBuffer ima
throw new UnsupportedOperationException("Not supported yet.");
}
- @Override
- public void showErrorDialog(String message) {
- showDialog(message);
- System.err.println("JME APPLICATION ERROR:" + message);
- }
+
private native void showDialog(String message);
- @Override
- public boolean showSettingsDialog(AppSettings sourceSettings, boolean loadFromRegistry) {
- return true;
- }
+
@Override
public JmeContext newContext(AppSettings settings, JmeContext.Type contextType) {
diff --git a/jme3-vr/src/main/java/com/jme3/app/VRApplication.java b/jme3-vr/src/main/java/com/jme3/app/VRApplication.java
index 5d9be70c3f..02ab733230 100644
--- a/jme3-vr/src/main/java/com/jme3/app/VRApplication.java
+++ b/jme3-vr/src/main/java/com/jme3/app/VRApplication.java
@@ -465,10 +465,10 @@ public void handleError(String errMsg, Throwable t){
// Display error message on screen if not in headless mode
if (context.getType() != JmeContext.Type.Headless) {
if (t != null) {
- JmeSystem.showErrorDialog(errMsg + "\n" + t.getClass().getSimpleName() +
+ JmeSystem.handleErrorMessage(errMsg + "\n" + t.getClass().getSimpleName() +
(t.getMessage() != null ? ": " + t.getMessage() : ""));
} else {
- JmeSystem.showErrorDialog(errMsg);
+ JmeSystem.handleErrorMessage(errMsg);
}
}
@@ -706,40 +706,12 @@ public void start() {
logger.config("VR mode disabled.");
// not in VR, show settings dialog
- if( Platform.get() != Platform.MACOSX ) {
- if (!JmeSystem.showSettingsDialog(settings, loadSettings)) {
- logger.config("Starting application [SUCCESS]");
- return;
- }
- } else {
- // GLFW workaround on macs
- settings.setFrequency(defDev.getDisplayMode().getRefreshRate());
- settings.setDepthBits(24);
- settings.setVSync(true);
- // try and read resolution from file in local dir
- File resFile = new File("resolution.txt");
- if( resFile.exists() ) {
- try {
- BufferedReader br = new BufferedReader(new FileReader(resFile));
- settings.setWidth(Integer.parseInt(br.readLine()));
- settings.setHeight(Integer.parseInt(br.readLine()));
- try {
- settings.setFullscreen(br.readLine().toLowerCase(Locale.ENGLISH).contains("full"));
- } catch(Exception e) {
- settings.setFullscreen(false);
- }
- br.close();
- } catch(Exception e) {
- settings.setWidth(1280);
- settings.setHeight(720);
- }
- } else {
- settings.setWidth(1280);
- settings.setHeight(720);
- settings.setFullscreen(false);
- }
- settings.setResizable(false);
+ if (!JmeSystem.showSettingsDialog(settings, loadSettings)) {
+ logger.config("Starting application [SUCCESS]");
+ return;
}
+
+
settings.setSwapBuffers(true);
} else {
logger.config("VR mode enabled.");
diff --git a/settings.gradle b/settings.gradle
index 78341dfa85..3f6acceb8e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -33,6 +33,7 @@ include 'jme3-testdata'
// Example projects
include 'jme3-examples'
+include 'jme3-awt-dialogs'
if(buildAndroidExamples == "true"){
include 'jme3-android-examples'