Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dockable dialogs #420

Draft
wants to merge 26 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1bf5704
AAAAAAAA
2xsaiko Apr 25, 2020
4ad2602
Right align buttons
2xsaiko Apr 25, 2020
430065e
Implement more RPanel functionality
2xsaiko Apr 25, 2020
6f3b48c
Implement more RPanel functionality
2xsaiko Apr 25, 2020
4b0bfd0
Fix not repainting after adding/removing buttons
2xsaiko Apr 25, 2020
e1f4387
Window drag detection
2xsaiko Apr 26, 2020
9ded30c
Dialogs are now fully detachable
2xsaiko Apr 27, 2020
bb56d79
Add size for left panel
2xsaiko Apr 28, 2020
5a3a426
Convert multiplayer tabs to RPanel
2xsaiko May 22, 2020
379ce65
Add RPanel.setVisible
2xsaiko May 22, 2020
41726de
Hide buttons/panel when possible
2xsaiko May 23, 2020
73ce521
Fix rebase-related crashes
2xsaiko Jul 5, 2021
b8a9a27
Start implementing WorkspaceRPanelContainer
2xsaiko Jul 5, 2021
6fdf2e5
Fix RPanel.setTitle not working correctly
2xsaiko Jul 5, 2021
422ee9a
Try to fix title pane recognition for FlatLaf
2xsaiko Jul 5, 2021
289cfdd
Use direct initialization where possible
2xsaiko Jul 6, 2021
eb69f06
Begin making panels resizable inwards
2xsaiko Jul 6, 2021
fc749ba
Fix split panes
2xsaiko Jul 6, 2021
12f1887
Fix right panel being messed up
2xsaiko Jul 6, 2021
da0b495
Clean up Gui constructor
2xsaiko Jul 7, 2021
45f3851
Separate out code from Gui class
2xsaiko Jul 8, 2021
e7057fe
Separate out inheritance tree
2xsaiko Jul 8, 2021
6949cdb
Move methods from MouseListenerUtil to GuiUtil
2xsaiko Jul 8, 2021
cc4587d
Add methods to save and restore main window state
2xsaiko Jul 8, 2021
7a67481
Use MainWindow restore/saveState
2xsaiko Jul 8, 2021
348dd04
Start working on saving/loading panel state
2xsaiko Jul 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 38 additions & 79 deletions enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.nio.file.Path;
import java.util.Collection;
Expand All @@ -40,6 +39,8 @@
import cuchaz.enigma.gui.dialog.JavadocDialog;
import cuchaz.enigma.gui.dialog.SearchDialog;
import cuchaz.enigma.gui.elements.*;
import cuchaz.enigma.gui.elements.rpanel.RPanel;
import cuchaz.enigma.gui.elements.rpanel.WorkspaceRPanelContainer.DockPosition;
import cuchaz.enigma.gui.panels.*;
import cuchaz.enigma.gui.renderer.MessageListCellRenderer;
import cuchaz.enigma.gui.util.GuiUtil;
Expand All @@ -66,6 +67,9 @@ public class Gui {
private final Set<EditableType> editableTypes;
private boolean singleClassTree;

private final RPanel messagePanel = new RPanel("Messages");
private final RPanel userPanel = new RPanel("Users");

private final MenuBar menuBar;
private final ObfPanel obfPanel;
private final DeobfPanel deobfPanel;
Expand All @@ -77,20 +81,10 @@ public class Gui {

private final EditorTabbedPane editorTabbedPane;

private final JPanel classesPanel = new JPanel(new BorderLayout());
private final JSplitPane splitClasses;
private final JTabbedPane tabs = new JTabbedPane();
private final CollapsibleTabbedPane logTabs = new CollapsibleTabbedPane(JTabbedPane.BOTTOM);
private final JSplitPane logSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, tabs, logTabs);
private final JPanel centerPanel = new JPanel(new BorderLayout());
private final JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, this.logSplit);
private final JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, this.classesPanel, splitRight);

private final DefaultListModel<String> userModel = new DefaultListModel<>();
private final DefaultListModel<Message> messageModel = new DefaultListModel<>();
private final JList<String> users = new JList<>(userModel);
private final JList<Message> messages = new JList<>(messageModel);
private final JPanel messagePanel = new JPanel(new BorderLayout());
private final JScrollPane messageScrollPane = new JScrollPane(this.messages);
private final JTextField chatBox = new JTextField();

Expand All @@ -115,7 +109,6 @@ public Gui(EnigmaProfile profile, Set<EditableType> editableTypes) {
this.implementationsTree = new ImplementationsTree(this);
this.callsTree = new CallsTree(this);
this.editorTabbedPane = new EditorTabbedPane(this);
this.splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, this.obfPanel, this.deobfPanel);

this.setupUi();

Expand All @@ -137,22 +130,19 @@ private void setupUi() {

this.exportJarFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

this.splitClasses.setResizeWeight(0.3);
this.classesPanel.setPreferredSize(ScaleUtil.getDimension(250, 0));

// layout controls
Container workArea = this.mainWindow.workArea();
workArea.setLayout(new BorderLayout());
workArea.add(infoPanel.getUi(), BorderLayout.NORTH);
workArea.add(this.editorTabbedPane.getUi(), BorderLayout.CENTER);

centerPanel.add(infoPanel.getUi(), BorderLayout.NORTH);
centerPanel.add(this.editorTabbedPane.getUi(), BorderLayout.CENTER);
// left.getUi().setPreferredSize(ScaleUtil.getDimension(300, 0));
// right.getUi().setPreferredSize(ScaleUtil.getDimension(250, 0));

tabs.setPreferredSize(ScaleUtil.getDimension(250, 0));
tabs.addTab(I18n.translate("info_panel.tree.structure"), structurePanel.getPanel());
tabs.addTab(I18n.translate("info_panel.tree.inheritance"), inheritanceTree.getPanel());
tabs.addTab(I18n.translate("info_panel.tree.implementations"), implementationsTree.getPanel());
tabs.addTab(I18n.translate("info_panel.tree.calls"), callsTree.getPanel());
userPanel.getContentPane().setLayout(new BorderLayout());
userPanel.getContentPane().add(new JScrollPane(this.users));

messagePanel.getContentPane().setLayout(new BorderLayout());
messages.setCellRenderer(new MessageListCellRenderer());
JPanel chatPanel = new JPanel(new BorderLayout());
AbstractAction sendListener = new AbstractAction("Send") {
Expand All @@ -165,26 +155,17 @@ public void actionPerformed(ActionEvent e) {
JButton chatSendButton = new JButton(sendListener);
chatPanel.add(chatBox, BorderLayout.CENTER);
chatPanel.add(chatSendButton, BorderLayout.EAST);
messagePanel.add(messageScrollPane, BorderLayout.CENTER);
messagePanel.add(chatPanel, BorderLayout.SOUTH);
logTabs.addTab(I18n.translate("log_panel.users"), new JScrollPane(this.users));
logTabs.addTab(I18n.translate("log_panel.messages"), messagePanel);
logSplit.setResizeWeight(0.5);
logSplit.resetToPreferredSizes();
splitRight.setResizeWeight(1); // let the left side take all the slack
splitRight.resetToPreferredSizes();
splitCenter.setResizeWeight(0); // let the right side take all the slack

workArea.add(splitCenter, BorderLayout.CENTER);

// restore state
int[] layout = UiConfig.getLayout();
if (layout.length >= 4) {
this.splitClasses.setDividerLocation(layout[0]);
this.splitCenter.setDividerLocation(layout[1]);
this.splitRight.setDividerLocation(layout[2]);
this.logSplit.setDividerLocation(layout[3]);
}
messagePanel.getContentPane().add(messageScrollPane, BorderLayout.CENTER);
messagePanel.getContentPane().add(chatPanel, BorderLayout.SOUTH);

this.mainWindow.addPanel(DockPosition.RIGHT_TOP, structurePanel.getPanel());
this.mainWindow.addPanel(DockPosition.RIGHT_TOP, inheritanceTree.getPanel());
this.mainWindow.addPanel(DockPosition.RIGHT_TOP, implementationsTree.getPanel());
this.mainWindow.addPanel(DockPosition.RIGHT_TOP, callsTree.getPanel());
this.mainWindow.addPanel(DockPosition.LEFT_TOP, obfPanel.getPanel());
this.mainWindow.addPanel(DockPosition.LEFT_BOTTOM, deobfPanel.getPanel());
this.mainWindow.addPanel(DockPosition.RIGHT_TOP, messagePanel);
this.mainWindow.addPanel(DockPosition.RIGHT_BOTTOM, userPanel);

this.mainWindow.statusBar().addPermanentComponent(this.connectionStatusLabel);

Expand All @@ -195,16 +176,9 @@ public void actionPerformed(ActionEvent e) {
JFrame frame = this.mainWindow.frame();
frame.addWindowListener(GuiUtil.onWindowClose(e -> this.close()));

frame.setSize(UiConfig.getWindowSize("Main Window", ScaleUtil.getDimension(1024, 576)));
frame.setMinimumSize(ScaleUtil.getDimension(640, 480));
frame.setSize(ScaleUtil.getDimension(1024, 576));
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);

Point windowPos = UiConfig.getWindowPos("Main Window", null);
if (windowPos != null) {
frame.setLocation(windowPos);
} else {
frame.setLocationRelativeTo(null);
}
UiConfig.restoreWindowState(this.mainWindow);

this.retranslateUi();
}
Expand All @@ -223,8 +197,8 @@ public GuiController getController() {

public void setSingleClassTree(boolean singleClassTree) {
this.singleClassTree = singleClassTree;
this.classesPanel.removeAll();
this.classesPanel.add(isSingleClassTree() ? deobfPanel : splitClasses);
// this.classesPanel.removeAll();
// this.classesPanel.add(isSingleClassTree() ? deobfPanel : splitClasses);
getController().refreshClasses();
retranslateUi();
}
Expand All @@ -234,15 +208,15 @@ public boolean isSingleClassTree() {
}

public void onStartOpenJar() {
this.classesPanel.removeAll();
// this.classesPanel.removeAll();
redraw();
}

public void onFinishOpenJar(String jarName) {
// update gui
this.mainWindow.setTitle(Enigma.NAME + " - " + jarName);
this.classesPanel.removeAll();
this.classesPanel.add(isSingleClassTree() ? deobfPanel : splitClasses);
// this.classesPanel.removeAll();
// this.classesPanel.add(isSingleClassTree() ? deobfPanel : splitClasses);
this.editorTabbedPane.closeAllEditorTabs();

// update menu
Expand All @@ -258,7 +232,7 @@ public void onCloseJar() {
setObfClasses(null);
setDeobfClasses(null);
this.editorTabbedPane.closeAllEditorTabs();
this.classesPanel.removeAll();
// this.classesPanel.removeAll();

// update menu
isJarOpen = false;
Expand Down Expand Up @@ -352,23 +326,20 @@ public void showInheritance(EditorPanel editor) {
if (cursorReference == null) return;

this.inheritanceTree.display(cursorReference.entry);
tabs.setSelectedIndex(1);
}

public void showImplementations(EditorPanel editor) {
EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference();
if (cursorReference == null) return;

this.implementationsTree.display(cursorReference.entry);
tabs.setSelectedIndex(2);
}

public void showCalls(EditorPanel editor, boolean recurse) {
EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference();
if (cursorReference == null) return;

this.callsTree.showCalls(cursorReference.entry, recurse);
tabs.setSelectedIndex(3);
}

public void toggleMapping(EditorPanel editor) {
Expand Down Expand Up @@ -427,13 +398,7 @@ public void close() {
}

private void exit() {
UiConfig.setWindowPos("Main Window", this.mainWindow.frame().getLocationOnScreen());
UiConfig.setWindowSize("Main Window", this.mainWindow.frame().getSize());
UiConfig.setLayout(
this.splitClasses.getDividerLocation(),
this.splitCenter.getDividerLocation(),
this.splitRight.getDividerLocation(),
this.logSplit.getDividerLocation());
UiConfig.saveWindowState(this.mainWindow);
UiConfig.save();

if (searchDialog != null) {
Expand Down Expand Up @@ -574,25 +539,19 @@ public void updateUiState() {
connectionStatusLabel.setText(I18n.translate(connectionState == ConnectionState.NOT_CONNECTED ? "status.disconnected" : "status.connected"));

if (connectionState == ConnectionState.NOT_CONNECTED) {
logSplit.setLeftComponent(null);
splitRight.setRightComponent(tabs);
userPanel.setVisible(false);
messagePanel.setVisible(false);
} else {
splitRight.setRightComponent(logSplit);
logSplit.setLeftComponent(tabs);
userPanel.setVisible(true);
messagePanel.setVisible(true);
}

splitRight.setDividerLocation(splitRight.getDividerLocation());
}

public void retranslateUi() {
this.jarFileChooser.setDialogTitle(I18n.translate("menu.file.jar.open"));
this.exportJarFileChooser.setDialogTitle(I18n.translate("menu.file.export.jar"));
this.tabs.setTitleAt(0, I18n.translate("info_panel.tree.structure"));
this.tabs.setTitleAt(1, I18n.translate("info_panel.tree.inheritance"));
this.tabs.setTitleAt(2, I18n.translate("info_panel.tree.implementations"));
this.tabs.setTitleAt(3, I18n.translate("info_panel.tree.calls"));
this.logTabs.setTitleAt(0, I18n.translate("log_panel.users"));
this.logTabs.setTitleAt(1, I18n.translate("log_panel.messages"));
this.userPanel.setTitle(I18n.translate("log_panel.users"));
this.messagePanel.setTitle(I18n.translate("log_panel.messages"));
this.connectionStatusLabel.setText(I18n.translate(connectionState == ConnectionState.NOT_CONNECTED ? "status.disconnected" : "status.connected"));

this.updateUiState();
Expand Down
72 changes: 7 additions & 65 deletions enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package cuchaz.enigma.gui.config;

import java.awt.*;
import java.awt.Color;
import java.awt.Font;
import java.util.Optional;
import java.util.OptionalInt;

import cuchaz.enigma.config.ConfigContainer;
import cuchaz.enigma.config.ConfigSection;
import cuchaz.enigma.gui.elements.MainWindow;
import cuchaz.enigma.gui.util.ScaleUtil;
import cuchaz.enigma.utils.I18n;

Expand Down Expand Up @@ -68,27 +69,6 @@ public static void setScaleFactor(float scale) {
swing.data().section("General").setDouble("Scale Factor", scale);
}

/**
* Gets the dimensions of the different panels of the GUI.
* <p>These dimensions are used to determine the location of the separators between these panels.</p>
*
* <ul>
* <li>[0] - The height of the obfuscated classes panel</li>
* <li>[1] - The width of the classes panel</li>
* <li>[2] - The width of the center panel</li>
* <li>[3] - The height of the tabs panel. Only used if the logs panel should appear</li>
* </ul>
*
* @return an integer array composed of these 4 dimensions
*/
public static int[] getLayout() {
return swing.data().section("Main Window").getIntArray("Layout").orElseGet(() -> new int[] { -1, -1, -1, -1 });
}

public static void setLayout(int leftV, int left, int right, int rightH) {
swing.data().section("Main Window").setIntArray("Layout", new int[] { leftV, left, right, rightH });
}

public static LookAndFeel getLookAndFeel() {
return swing.data().section("Themes").setIfAbsentEnum(LookAndFeel::valueOf, "Current", LookAndFeel.NONE);
}
Expand Down Expand Up @@ -282,50 +262,12 @@ public static String encodeFont(Font font) {
return String.format("%s-%s-%s", font.getName(), s, font.getSize());
}

public static Dimension getWindowSize(String window, Dimension fallback) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
ConfigSection section = swing.data().section(window);
OptionalInt width = section.getInt(String.format("Width %s", screenSize.width));
OptionalInt height = section.getInt(String.format("Height %s", screenSize.height));
if (width.isPresent() && height.isPresent()) {
return new Dimension(width.getAsInt(), height.getAsInt());
} else {
return fallback;
}
}

public static void setWindowSize(String window, Dimension dim) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
ConfigSection section = swing.data().section(window);
section.setInt(String.format("Width %s", screenSize.width), dim.width);
section.setInt(String.format("Height %s", screenSize.height), dim.height);
}

public static Point getWindowPos(String window, Point fallback) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
ConfigSection section = swing.data().section(window);
OptionalInt x = section.getInt(String.format("X %s", screenSize.width));
OptionalInt y = section.getInt(String.format("Y %s", screenSize.height));
if (x.isPresent() && y.isPresent()) {
int ix = x.getAsInt();
int iy = y.getAsInt();

// Ensure that the position is on the screen.
if (ix < 0 || iy < 0 || ix > screenSize.width || iy > screenSize.height) {
return fallback;
}

return new Point(ix, iy);
} else {
return fallback;
}
public static void saveWindowState(MainWindow win) {
win.saveState(swing.data().section("Main Window"));
}

public static void setWindowPos(String window, Point rect) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
ConfigSection section = swing.data().section(window);
section.setInt(String.format("X %s", screenSize.width), rect.x);
section.setInt(String.format("Y %s", screenSize.height), rect.y);
public static void restoreWindowState(MainWindow win) {
win.restoreState(swing.data().section("Main Window"));
}

public static String getLastSelectedDir() {
Expand Down
Loading