Skip to content

Commit

Permalink
feat(gui): use Swing to create the tray menu
Browse files Browse the repository at this point in the history
  • Loading branch information
Zmax0 committed Apr 25, 2024
1 parent 8f64ed1 commit aaa204d
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 143 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,25 @@
import java.awt.*;
import java.awt.TrayIcon.MessageType;

import com.urbanspork.client.gui.tray.TrayIcon;
import javafx.application.Platform;

public class Tray {

private static final boolean IS_SUPPORTED = SystemTray.isSupported();

private static final PopupMenu menu = new PopupMenu();

private static final JPopupMenu menu = new JPopupMenu();
private static final ImageIcon icon = new ImageIcon(Resource.TRAY_ICON);

private static final TrayIcon trayIcon = IS_SUPPORTED ? new TrayIcon(icon.getImage(), I18N.getString(I18N.PROGRAM_TITLE), menu) : null;

private static TrayIcon trayIcon;
private static Console console;

private Tray() {}

public static void init(Console console) {
Tray.console = console;
start();
if (IS_SUPPORTED) {
trayIcon = new TrayIcon(icon.getImage(), I18N.getString(I18N.PROGRAM_TITLE), () -> Platform.runLater(console::show), menu);
start();
}
}

public static void displayMessage(String caption, String text, MessageType messageType) {
Expand All @@ -54,28 +56,31 @@ public static void exit() {
}

private static void start() {
if (IS_SUPPORTED) {
// ==============================
// tray icon
// ==============================
SystemTray tray = SystemTray.getSystemTray();
trayIcon.setImageAutoSize(true);
try {
tray.add(trayIcon);
} catch (AWTException e) {
displayMessage("Error", e.getMessage(), MessageType.ERROR);
}
// ==============================
// tray menu
// ==============================
menu.add(new ServersMenuItem(console).build());
menu.addSeparator();
menu.add(new ConsoleMenuItem(console).build());
menu.addSeparator();
menu.add(new LanguageMenuItem().build());
menu.addSeparator();
menu.add(new ExitMenuItem().build());
// ==============================
// tray icon
// ==============================
SystemTray tray = SystemTray.getSystemTray();
trayIcon.setImageAutoSize(true);
try {
tray.add(trayIcon);
} catch (AWTException e) {
displayMessage("Error", e.getMessage(), MessageType.ERROR);
}
// ==============================
// tray menu
// ==============================
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ignore) {
// ignore
}
SwingUtilities.updateComponentTreeUI(menu);
menu.add(new ServersMenuItem(console).build());
menu.addSeparator();
menu.add(new ConsoleMenuItem(console).build());
menu.addSeparator();
menu.add(new LanguageMenuItem().build());
menu.addSeparator();
menu.add(new ExitMenuItem().build());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.urbanspork.client.gui.tray;

import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Arrays;

public class TrayIcon extends java.awt.TrayIcon {
private JDialog dialog;

public TrayIcon(Image image, String tooltip, Runnable onLeftClick, JPopupMenu popup) {
super(image, tooltip);
setImageAutoSize(true);
// add mouse listener
addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1 && onLeftClick != null) {
onLeftClick.run();
}
if (e.getButton() == MouseEvent.BUTTON3 && e.isPopupTrigger()) {
dialog.setLocation(adjustLocation(e.getPoint(), popup.getPreferredSize().getHeight()));
dialog.setVisible(true);
popup.show(dialog, 0, 0);
}
}
});
// add property change listener
SystemTray.getSystemTray().addPropertyChangeListener("trayIcons", e -> {
java.awt.TrayIcon[] oldArray = (java.awt.TrayIcon[]) e.getOldValue();
java.awt.TrayIcon[] newArray = (java.awt.TrayIcon[]) e.getNewValue();
if (contains(oldArray, this) && !contains(newArray, this)) {
dialog.dispose();
}
if (!contains(oldArray, this) && contains(newArray, this)) {
dialog = new JDialog();
dialog.setUndecorated(true);
}
});
// add popup menu listener
popup.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
// should do nothing
}

@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
dialog.setVisible(false);
}

@Override
public void popupMenuCanceled(PopupMenuEvent e) {
dialog.setVisible(false);
}
});
}

private static Point adjustLocation(Point p, double menuHeight) {
GraphicsDevice screenDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0];
Rectangle bounds = screenDevice.getDefaultConfiguration().getBounds();
if (bounds.contains(p)) {
return p;
} else {
double scale = screenDevice.getDisplayMode().getWidth() / bounds.getWidth();
int x = (int) (p.getX() / scale);
int y = (int) (p.getY() / scale - menuHeight);
return new Point(x, y);
}
}

private boolean contains(Object[] arr, Object obj) {
if (arr == null || arr.length == 0) {
return false;
}
return Arrays.asList(arr).contains(obj);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.urbanspork.client.gui.i18n.I18N;
import javafx.application.Platform;

import java.awt.*;
import java.awt.event.ActionListener;

public class ConsoleMenuItem implements TrayMenuItemBuilder {
Expand All @@ -15,11 +14,6 @@ public ConsoleMenuItem(Console console) {
this.console = console;
}

@Override
public Menu getMenuItem() {
return null;
}

@Override
public String getLabel() {
return I18N.getString(I18N.TRAY_MENU_CONSOLE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,9 @@
import com.urbanspork.client.gui.i18n.I18N;
import javafx.application.Platform;

import java.awt.*;
import java.awt.event.ActionListener;

public class ExitMenuItem implements TrayMenuItemBuilder {

@Override
public MenuItem getMenuItem() {
return null;
}

@Override
public String getLabel() {
return I18N.getString(I18N.TRAY_EXIT);
Expand All @@ -28,5 +21,4 @@ public ActionListener getActionListener() {
Proxy.exit();
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,44 @@
import com.urbanspork.common.config.ClientConfig;
import com.urbanspork.common.config.ConfigHandler;

import java.awt.*;
import javax.swing.*;
import java.awt.TrayIcon.MessageType;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class LanguageMenuItem implements TrayMenuItemBuilder {

@Override
public MenuItem getMenuItem() {
Menu menu = new Menu(getLabel());
public class LanguageMenuItem {
public JMenuItem build() {
JMenu menu = new JMenu(getLabel());
ClientConfig config = Resource.config();
String language = config.getLanguage();
final Locale configLanguage = Locale.of(language);
Locale[] languages = I18N.languages();
List<CheckboxMenuItem> items = new ArrayList<>(languages.length);
ButtonGroup group = new ButtonGroup();
for (Locale locale : languages) {
CheckboxMenuItem item = new CheckboxMenuItem();
JRadioButtonMenuItem item = new JRadioButtonMenuItem();
item.setName(locale.getLanguage());
item.setLabel(locale.getDisplayLanguage(configLanguage));
item.setText(locale.getDisplayLanguage(configLanguage));
if (locale.equals(configLanguage)) {
item.setState(true);
item.setSelected(true);
}
item.addItemListener(l -> itemStateChanged(config, items, item));
items.add(item);
item.addActionListener(evt -> {
if (item.isSelected()) {
config.setLanguage(item.getName());
try {
ConfigHandler.DEFAULT.save(config);
} catch (Exception e) {
Tray.displayMessage("Error", "Save file error, cause: " + e.getMessage(), MessageType.ERROR);
return;
}
Tray.displayMessage("Config is saved", "Take effect after restart", MessageType.INFO);
}
});
group.add(item);
menu.add(item);
}
return menu;
}

private void itemStateChanged(ClientConfig config, List<CheckboxMenuItem> items, CheckboxMenuItem item) {
if (item.getState()) {
config.setLanguage(item.getName());
try {
ConfigHandler.DEFAULT.save(config);
} catch (Exception e) {
Tray.displayMessage("Error", "Save file error, cause: " + e.getMessage(), MessageType.ERROR);
return;
}
Tray.displayMessage("Config is saved", "Take effect after restart", MessageType.INFO);
for (CheckboxMenuItem i : items) {
if (!i.equals(item) && i.getState()) {
i.setState(false);
}
}
} else {
item.setState(true);
}
}

@Override
public String getLabel() {
private String getLabel() {
return I18N.getString(I18N.TRAY_MENU_LANGUAGE);
}

@Override
public ActionListener getActionListener() {
return null;
}

}
Loading

0 comments on commit aaa204d

Please sign in to comment.