mirror of
https://github.com/array-in-a-matrix/brainwine.git
synced 2025-04-02 11:11:58 -04:00
User interface makeover
This commit is contained in:
parent
0d5023da59
commit
20df62398e
7 changed files with 193 additions and 56 deletions
|
@ -89,9 +89,10 @@ public class Bootstrap {
|
|||
UIManager.put("Brainwine.powerIcon", new ImageIcon(getClass().getResource("/powerIcon16x.png")));
|
||||
UIManager.put("Brainwine.consoleFont", new Font("Consolas", Font.PLAIN, 12));
|
||||
UIManager.put("Spinner.editorAlignment", JTextField.LEFT);
|
||||
UIManager.put("TitlePane.unifiedBackground", false);
|
||||
UIManager.put("Button.foreground", UIManager.get("MenuBar.foreground"));
|
||||
SwingUtils.setDefaultFontSize(Math.min(28, Math.max(10, GuiPreferences.getInt(GuiPreferences.FONT_SIZE_KEY, 14))));
|
||||
SwingUtils.setMenuBarEmbedded(GuiPreferences.getBoolean(GuiPreferences.EMBED_MENU_BAR_KEY, true));
|
||||
GuiPreferences.createPropertyListeners();
|
||||
|
||||
// Create view
|
||||
mainView = new MainView(this);
|
||||
|
|
|
@ -2,21 +2,32 @@ package brainwine.gui;
|
|||
|
||||
import static brainwine.gui.GuiConstants.DEEPWORLD_ASSEMBLY_PATH;
|
||||
import static brainwine.gui.GuiConstants.DEEPWORLD_PLAYERPREFS;
|
||||
import static brainwine.gui.GuiConstants.GUI_MARKER;
|
||||
import static brainwine.gui.GuiConstants.HTTP_COMMUNITY_HUB_URL;
|
||||
import static brainwine.gui.GuiConstants.HTTP_STEAM_DOWNLOAD_URL;
|
||||
import static brainwine.gui.GuiConstants.STEAM_COMMUNITY_HUB_URL;
|
||||
import static brainwine.gui.GuiConstants.STEAM_REGISTRY_LOCATION;
|
||||
import static brainwine.gui.GuiConstants.STEAM_RUN_GAME_URL;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.LinearGradientPaint;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import brainwine.gui.component.ImagePanel;
|
||||
import brainwine.util.DesktopUtils;
|
||||
import brainwine.util.ProcessResult;
|
||||
import brainwine.util.RegistryKey;
|
||||
|
@ -24,8 +35,11 @@ import brainwine.util.RegistryUtils;
|
|||
import brainwine.util.SwingUtils;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class GamePanel extends JPanel {
|
||||
public class GamePanel extends ImagePanel {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
private final LinearGradientPaint gradientPaint = new LinearGradientPaint(0, 0, 0, 15,
|
||||
new float[] {0.0F, 1.0F}, new Color[] {Color.BLACK, new Color(0, 0, 0, 0)});
|
||||
private final JButton startGameButton;
|
||||
private final JButton communityHubButton;
|
||||
|
||||
|
@ -46,12 +60,34 @@ public class GamePanel extends JPanel {
|
|||
|
||||
// Button panel
|
||||
JPanel buttonPanel = new JPanel(new GridBagLayout());
|
||||
buttonPanel.setOpaque(false);
|
||||
|
||||
JPanel topPanel = new JPanel(new GridLayout(1, 2));
|
||||
topPanel.setOpaque(false);
|
||||
topPanel.add(hostSettingsButton);
|
||||
topPanel.add(communityHubButton);
|
||||
buttonPanel.add(topPanel, SwingUtils.createConstraints(0, 0));
|
||||
buttonPanel.add(startGameButton, SwingUtils.createConstraints(0, 1, 2, 1));
|
||||
add(buttonPanel);
|
||||
|
||||
// Load & set background image
|
||||
try {
|
||||
setImage(ImageIO.read(getClass().getResourceAsStream("/background.jpg")));
|
||||
} catch (IllegalArgumentException | IOException e) {
|
||||
logger.error(GUI_MARKER, "Could not load background image", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics graphics) {
|
||||
super.paintComponent(graphics);
|
||||
|
||||
// Draw shadow gradient below the title bar if this panel has a background image
|
||||
if(getImage() != null) {
|
||||
Graphics2D g2d = (Graphics2D)graphics;
|
||||
g2d.setPaint(gradientPaint);
|
||||
g2d.fillRect(0, 0, getWidth(), 15);
|
||||
}
|
||||
}
|
||||
|
||||
private void startGame() {
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
package brainwine.gui;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.prefs.BackingStoreException;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import brainwine.util.SwingUtils;
|
||||
|
||||
public class GuiPreferences {
|
||||
|
||||
public static final String ROOT_KEY = "brainwine";
|
||||
public static final String THEME_KEY = "theme";
|
||||
public static final String TAB_PLACEMENT_KEY = "tabPlacement";
|
||||
public static final String FONT_SIZE_KEY = "fontSize";
|
||||
public static final String EMBED_MENU_BAR_KEY = "embedMenuBar";
|
||||
public static final String GATEWAY_HOST_KEY = "gatewayHost";
|
||||
|
@ -27,29 +22,6 @@ public class GuiPreferences {
|
|||
return preferences;
|
||||
}
|
||||
|
||||
public static void createPropertyListeners() {
|
||||
UIManager.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent event) {
|
||||
if(event.getPropertyName().equals("lookAndFeel")) {
|
||||
setString(THEME_KEY, UIManager.getLookAndFeel().getClass().getName());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
UIManager.getDefaults().addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent event) {
|
||||
String name = event.getPropertyName();
|
||||
|
||||
switch(name) {
|
||||
case "defaultFont": setInt(FONT_SIZE_KEY, SwingUtils.getDefaultFontSize()); break;
|
||||
case "TitlePane.menuBarEmbedded": setBoolean(EMBED_MENU_BAR_KEY, SwingUtils.isMenuBarEmbedded()); break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setString(String key, String value) {
|
||||
get().put(key, value);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package brainwine.gui;
|
|||
|
||||
import static brainwine.gui.GuiConstants.DEEPWORLD_PLAYERPREFS;
|
||||
import static brainwine.gui.GuiConstants.GITHUB_REPOSITORY_URL;
|
||||
import static brainwine.gui.GuiConstants.GUI_MARKER;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
|
@ -15,12 +16,12 @@ import javax.swing.JMenu;
|
|||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
|
||||
import com.formdev.flatlaf.extras.components.FlatTabbedPane;
|
||||
import com.formdev.flatlaf.extras.components.FlatTabbedPane.TabAlignment;
|
||||
|
||||
|
@ -42,25 +43,23 @@ public class MainView {
|
|||
private final SettingsPanel settingsPanel;
|
||||
|
||||
public MainView(Bootstrap bootstrap) {
|
||||
logger.info("Creating main view ...");
|
||||
logger.info(GUI_MARKER, "Creating main view ...");
|
||||
|
||||
// Panels
|
||||
// Panel
|
||||
panel = new JPanel(new BorderLayout());
|
||||
serverPanel = new ServerPanel(bootstrap);
|
||||
settingsPanel = new SettingsPanel();
|
||||
|
||||
// Tabs
|
||||
tabbedPane = new FlatTabbedPane();
|
||||
tabbedPane.setShowContentSeparators(true);
|
||||
tabbedPane.setTabPlacement(JTabbedPane.LEFT);
|
||||
tabbedPane.setTabAlignment(TabAlignment.leading);
|
||||
setTabPlacement(GuiPreferences.getInt(GuiPreferences.TAB_PLACEMENT_KEY, 1), false);
|
||||
|
||||
if(OperatingSystem.isWindows()) {
|
||||
tabbedPane.addTab("Play Game", UIManager.getIcon("Brainwine.playIcon"), new GamePanel(this));
|
||||
}
|
||||
|
||||
tabbedPane.addTab("Server", UIManager.getIcon("Brainwine.serverIcon"), serverPanel);
|
||||
tabbedPane.addTab("Settings", UIManager.getIcon("Brainwine.settingsIcon"), settingsPanel);
|
||||
tabbedPane.addTab("Server", UIManager.getIcon("Brainwine.serverIcon"), serverPanel = new ServerPanel(bootstrap));
|
||||
tabbedPane.addTab("Settings", UIManager.getIcon("Brainwine.settingsIcon"), settingsPanel = new SettingsPanel(this));
|
||||
panel.add(tabbedPane);
|
||||
|
||||
// Menu
|
||||
|
@ -87,7 +86,7 @@ public class MainView {
|
|||
}
|
||||
});
|
||||
frame.setJMenuBar(menuBar);
|
||||
frame.setMinimumSize(new Dimension(848, 480));
|
||||
frame.setMinimumSize(new Dimension(848, 520));
|
||||
frame.setFocusable(true);
|
||||
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
frame.add(panel);
|
||||
|
@ -96,6 +95,26 @@ public class MainView {
|
|||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
public void setTabPlacement(int tabPlacement) {
|
||||
setTabPlacement(tabPlacement, true);
|
||||
}
|
||||
|
||||
public void setTabPlacement(int tabPlacement, boolean animateChange) {
|
||||
if(animateChange) {
|
||||
FlatAnimatedLafChange.showSnapshot();
|
||||
}
|
||||
|
||||
tabbedPane.setTabPlacement(Math.min(4, Math.max(1, tabPlacement)));
|
||||
|
||||
if(animateChange) {
|
||||
FlatAnimatedLafChange.hideSnapshotWithAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTabPlacement() {
|
||||
return tabbedPane.getTabPlacement();
|
||||
}
|
||||
|
||||
public void showHostSettings() {
|
||||
tabbedPane.setSelectedComponent(settingsPanel);
|
||||
settingsPanel.focusHostSettings();
|
||||
|
|
|
@ -13,7 +13,6 @@ import javax.swing.JComboBox;
|
|||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
@ -34,13 +33,17 @@ import brainwine.util.SwingUtils;
|
|||
@SuppressWarnings("serial")
|
||||
public class SettingsPanel extends JPanel {
|
||||
|
||||
private final MainView mainView;
|
||||
private JComboBox<Theme> themeBox;
|
||||
private JComboBox<String> tabPlacementBox;
|
||||
private JSpinner fontSizeSpinner;
|
||||
private JCheckBox embedMenuBarCheckox;
|
||||
private JCheckBox embedMenuBarCheckbox;
|
||||
private FlatTextField gatewayHostField;
|
||||
private FlatTextField apiHostField;
|
||||
|
||||
public SettingsPanel() {
|
||||
public SettingsPanel(MainView mainView) {
|
||||
this.mainView = mainView;
|
||||
|
||||
// Reset Button
|
||||
JButton resetButton = new JButton("Reset to Defaults");
|
||||
resetButton.addActionListener(event -> resetSettings(true));
|
||||
|
@ -51,6 +54,7 @@ public class SettingsPanel extends JPanel {
|
|||
|
||||
// Button Panel
|
||||
JPanel buttonPanel = new JPanel(new GridLayout(1, 2));
|
||||
buttonPanel.setBorder(createCategoryBorder("Reset Settings"));
|
||||
buttonPanel.add(resetButton);
|
||||
buttonPanel.add(clearButton);
|
||||
|
||||
|
@ -62,8 +66,7 @@ public class SettingsPanel extends JPanel {
|
|||
settingsPanel.add(createGameSettingsPanel(), SwingUtils.createConstraints(0, 1));
|
||||
}
|
||||
|
||||
settingsPanel.add(new JSeparator(), SwingUtils.createConstraints(0, 2));
|
||||
settingsPanel.add(buttonPanel, SwingUtils.createConstraints(0, 3));
|
||||
settingsPanel.add(buttonPanel, SwingUtils.createConstraints(0, 2));
|
||||
|
||||
// Scroll pane (TODO doesn't actually scroll)
|
||||
FlatScrollPane scrollPane = new FlatScrollPane();
|
||||
|
@ -79,26 +82,33 @@ public class SettingsPanel extends JPanel {
|
|||
themeBox = new JComboBox<>();
|
||||
ThemeManager.getThemes().forEach(themeBox::addItem);
|
||||
themeBox.setSelectedItem(ThemeManager.getCurrentTheme());
|
||||
themeBox.addItemListener(item -> SwingUtilities.invokeLater(() -> ThemeManager.setTheme((Theme)item.getItem())));
|
||||
themeBox.addActionListener(event -> setThemePreference((Theme)themeBox.getSelectedItem()));
|
||||
|
||||
// Tabbed pane orientation box
|
||||
tabPlacementBox = new JComboBox<>(new String[] {"Top", "Left", "Bottom", "Right"});
|
||||
tabPlacementBox.setSelectedIndex(mainView.getTabPlacement() - 1);
|
||||
tabPlacementBox.addActionListener(event -> setTabPlacementPreference(tabPlacementBox.getSelectedIndex() + 1));
|
||||
|
||||
// Font size changer
|
||||
fontSizeSpinner = new JSpinner(new SpinnerNumberModel(SwingUtils.getDefaultFontSize(), 10, 28, 1));
|
||||
fontSizeSpinner.addChangeListener(event -> SwingUtils.setDefaultFontSize((int)fontSizeSpinner.getValue()));
|
||||
|
||||
fontSizeSpinner.addChangeListener(event -> setFontSizePreference((int)fontSizeSpinner.getValue()));
|
||||
|
||||
// Menu bar embed checkbox
|
||||
embedMenuBarCheckox = new JCheckBox();
|
||||
embedMenuBarCheckox.setSelected(SwingUtils.isMenuBarEmbedded());
|
||||
embedMenuBarCheckox.addChangeListener(event -> SwingUtils.setMenuBarEmbedded(embedMenuBarCheckox.isSelected()));
|
||||
embedMenuBarCheckbox = new JCheckBox();
|
||||
embedMenuBarCheckbox.setSelected(SwingUtils.isMenuBarEmbedded());
|
||||
embedMenuBarCheckbox.addChangeListener(event -> setEmbedMenuBarPreference(embedMenuBarCheckbox.isSelected()));
|
||||
|
||||
// Panel
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
panel.setBorder(createCategoryBorder("Visual Settings"));
|
||||
panel.add(new JLabel("Theme"), SwingUtils.createConstraints(0, 0));
|
||||
panel.add(themeBox, SwingUtils.createConstraints(1, 0));
|
||||
panel.add(new JLabel("Font Size"), SwingUtils.createConstraints(0, 1));
|
||||
panel.add(fontSizeSpinner, SwingUtils.createConstraints(1, 1));
|
||||
panel.add(new JLabel("Embed Menu Bar"), SwingUtils.createConstraints(0, 2));
|
||||
panel.add(embedMenuBarCheckox, SwingUtils.createConstraints(1, 2));
|
||||
panel.add(new JLabel("Tab Placement"), SwingUtils.createConstraints(0, 1));
|
||||
panel.add(tabPlacementBox, SwingUtils.createConstraints(1, 1));
|
||||
panel.add(new JLabel("Font Size"), SwingUtils.createConstraints(0, 2));
|
||||
panel.add(fontSizeSpinner, SwingUtils.createConstraints(1, 2));
|
||||
panel.add(new JLabel("Embed Menu Bar"), SwingUtils.createConstraints(0, 3));
|
||||
panel.add(embedMenuBarCheckbox, SwingUtils.createConstraints(1, 3));
|
||||
return panel;
|
||||
}
|
||||
|
||||
|
@ -149,13 +159,40 @@ public class SettingsPanel extends JPanel {
|
|||
gatewayHostField.requestFocus();
|
||||
}
|
||||
|
||||
private void setThemePreference(Theme theme) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
ThemeManager.setTheme(theme);
|
||||
});
|
||||
|
||||
GuiPreferences.setString(GuiPreferences.THEME_KEY, theme.getClassName());
|
||||
}
|
||||
|
||||
private void setTabPlacementPreference(int tabPlacement) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
mainView.setTabPlacement(tabPlacement);
|
||||
});
|
||||
|
||||
GuiPreferences.setInt(GuiPreferences.TAB_PLACEMENT_KEY, tabPlacement);
|
||||
}
|
||||
|
||||
private void setFontSizePreference(int fontSize) {
|
||||
SwingUtils.setDefaultFontSize(fontSize);
|
||||
GuiPreferences.setInt(GuiPreferences.FONT_SIZE_KEY, fontSize);
|
||||
}
|
||||
|
||||
private void setEmbedMenuBarPreference(boolean embedMenuBar) {
|
||||
SwingUtils.setMenuBarEmbedded(embedMenuBar);
|
||||
GuiPreferences.setBoolean(GuiPreferences.EMBED_MENU_BAR_KEY, embedMenuBar);
|
||||
}
|
||||
|
||||
private void resetSettings(boolean showPrompt) {
|
||||
if(!showPrompt || JOptionPane.showConfirmDialog(getRootPane(),
|
||||
"Are you sure you want to reset all settings to their default values?",
|
||||
"Confirmation", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
|
||||
themeBox.setSelectedItem(ThemeManager.getTheme(FlatMaterialDarkerIJTheme.class));
|
||||
tabPlacementBox.setSelectedIndex(0);
|
||||
fontSizeSpinner.setValue(14);
|
||||
embedMenuBarCheckox.setSelected(true);
|
||||
embedMenuBarCheckbox.setSelected(true);
|
||||
|
||||
if(OperatingSystem.isWindows()) {
|
||||
gatewayHostField.setText("local");
|
||||
|
|
72
src/main/java/brainwine/gui/component/ImagePanel.java
Normal file
72
src/main/java/brainwine/gui/component/ImagePanel.java
Normal file
|
@ -0,0 +1,72 @@
|
|||
package brainwine.gui.component;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
* A {@link JPanel} with a scaling and extending background image that always maintains its aspect ratio.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ImagePanel extends JPanel {
|
||||
|
||||
private Image image;
|
||||
|
||||
public ImagePanel() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ImagePanel(Image image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics graphics) {
|
||||
super.paintComponent(graphics);
|
||||
|
||||
if(image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Can this be simpler?
|
||||
// Probably. Who knows. Don't really care.
|
||||
int containerWidth = getWidth();
|
||||
int containerHeight = getHeight();
|
||||
int drawWidth = containerWidth;
|
||||
int drawHeight = containerHeight;
|
||||
float targetRatio = image.getWidth(this) / (float)image.getHeight(this);
|
||||
float aspectRatio = drawWidth / (float)drawHeight;
|
||||
float inverseTargetRatio = 1.0F / targetRatio;
|
||||
|
||||
if(aspectRatio > targetRatio) {
|
||||
drawWidth = Math.round(drawHeight * targetRatio);
|
||||
} else if(aspectRatio < targetRatio) {
|
||||
drawHeight = Math.round(drawWidth * inverseTargetRatio);
|
||||
}
|
||||
|
||||
if(drawWidth < containerWidth) {
|
||||
drawHeight += (containerWidth - drawWidth) / targetRatio;
|
||||
drawWidth = containerWidth;
|
||||
} else if(drawHeight < containerHeight) {
|
||||
drawWidth += (containerHeight - drawHeight) / inverseTargetRatio;
|
||||
drawHeight = containerHeight;
|
||||
}
|
||||
|
||||
int x = (containerWidth - drawWidth) / 2;
|
||||
int y = (containerHeight - drawHeight) / 2;
|
||||
Graphics2D g2d = (Graphics2D)graphics;
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2d.drawImage(image, x, y, drawWidth, drawHeight, this);
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public Image getImage() {
|
||||
return image;
|
||||
}
|
||||
}
|
BIN
src/main/resources/background.jpg
Normal file
BIN
src/main/resources/background.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 245 KiB |
Loading…
Add table
Reference in a new issue