mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Remember window size/position between sessions
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -13094,6 +13094,7 @@ res/defaults/gauntlet/LOCKED_DotP[!!-~]Preconstructed.dat -text
|
||||
res/defaults/gauntlet/LOCKED_Swimming[!!-~]With[!!-~]Sharks.dat -text
|
||||
res/defaults/home.xml svneol=native#text/xml
|
||||
res/defaults/match.xml svneol=native#text/xml
|
||||
res/defaults/window.xml -text
|
||||
res/draft/cube_juzamjedi.draft -text
|
||||
res/draft/cube_skiera.draft -text
|
||||
res/draft/rankings.txt -text
|
||||
|
||||
@@ -8,6 +8,12 @@ Forge Beta: 0#-##-2013 ver 1.4.6
|
||||
Release Notes
|
||||
-------------
|
||||
|
||||
- Window size/position now remembered between sessions -
|
||||
Works with multiple monitors.
|
||||
Remembers whether the window was maximized or un-maximized.
|
||||
Remembers last un-maximized size even if the window is currently maximized such that, if you un-maximize the window, it will restore to that size at the center of the current monitor.
|
||||
Window will be made accessible even if monitor setup or screen resolution is different between sessions.
|
||||
|
||||
- Zoomer Updates -
|
||||
Split cards (name contains "//") are now rotated 90 degrees for easier viewing.
|
||||
|
||||
|
||||
2
res/defaults/window.xml
Normal file
2
res/defaults/window.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0"?>
|
||||
<layout x="0" y="0" w="800" h="600" state="6"></layout>
|
||||
@@ -185,12 +185,18 @@ public enum FControl {
|
||||
Singletons.getModel().getQuest().load(QuestDataIO.loadData(data));
|
||||
}
|
||||
|
||||
// Handles resizing in null layouts of layers in JLayeredPane.
|
||||
// Handles resizing in null layouts of layers in JLayeredPane as well as saving window layout
|
||||
Singletons.getView().getFrame().addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(final ComponentEvent e) {
|
||||
sizeChildren();
|
||||
}
|
||||
@Override
|
||||
public void componentResized(final ComponentEvent e) {
|
||||
sizeChildren();
|
||||
SLayoutIO.saveWindowLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(final ComponentEvent e) {
|
||||
SLayoutIO.saveWindowLayout();
|
||||
}
|
||||
});
|
||||
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().addMouseListener(SOverflowUtil.getHideOverflowListener());
|
||||
|
||||
@@ -2,7 +2,12 @@ package forge.gui.framework;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@@ -105,4 +110,18 @@ public class SDisplayUtil {
|
||||
};
|
||||
FThreads.invokeInEdtLater(showTabRoutine);
|
||||
}
|
||||
|
||||
public static Rectangle getScreenBoundsForPoint(Point point) {
|
||||
Rectangle bounds;
|
||||
for (GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
|
||||
for (GraphicsConfiguration config : device.getConfigurations()) {
|
||||
bounds = config.getBounds();
|
||||
if (bounds.contains(point)) {
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
//return bounds of default monitor if point not on any screen
|
||||
return GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package forge.gui.framework;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -12,6 +16,7 @@ import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.xml.stream.XMLEventFactory;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
@@ -41,7 +46,6 @@ import forge.view.FView;
|
||||
* <br><br><i>(S at beginning of class name denotes a static factory.)</i>
|
||||
*/
|
||||
public final class SLayoutIO {
|
||||
/** Each cell must save these elements of its display. */
|
||||
private static class Property {
|
||||
public final static String x = "x";
|
||||
public final static String y = "y";
|
||||
@@ -49,12 +53,204 @@ public final class SLayoutIO {
|
||||
public final static String h = "h";
|
||||
public final static String sel = "sel";
|
||||
public final static String doc = "doc";
|
||||
public final static String state = "state";
|
||||
}
|
||||
|
||||
private static final XMLEventFactory EF = XMLEventFactory.newInstance();
|
||||
private static final XMLEvent NEWLINE = EF.createDTD("\n");
|
||||
private static final XMLEvent TAB = EF.createDTD("\t");
|
||||
|
||||
private static int normalWindowWidth, normalWindowHeight;
|
||||
private final static AtomicBoolean saveWindowRequested = new AtomicBoolean(false);
|
||||
|
||||
public static void saveWindowLayout() {
|
||||
if (saveWindowRequested.getAndSet(true)) { return; }
|
||||
FThreads.delay(500, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finishSaveWindowLayout();
|
||||
saveWindowRequested.set(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized static void finishSaveWindowLayout() {
|
||||
final JFrame window = FView.SINGLETON_INSTANCE.getFrame();
|
||||
final int state = window.getExtendedState();
|
||||
if (state == Frame.ICONIFIED) { return; } //don't update saved layout if minimized
|
||||
|
||||
final Rectangle bounds = window.getBounds();
|
||||
final int x = bounds.x;
|
||||
final int y = bounds.y;
|
||||
if ((state & Frame.MAXIMIZED_HORIZ) != Frame.MAXIMIZED_HORIZ) { //only modify saved width if not maximized horizontally
|
||||
normalWindowWidth = bounds.width;
|
||||
}
|
||||
else if (normalWindowWidth == 0) {
|
||||
normalWindowWidth = window.getMinimumSize().width;
|
||||
}
|
||||
if ((state & Frame.MAXIMIZED_VERT) != Frame.MAXIMIZED_VERT) { //only modify saved width if not maximized vertically
|
||||
normalWindowHeight = bounds.height;
|
||||
}
|
||||
else if (normalWindowHeight == 0) {
|
||||
normalWindowHeight = window.getMinimumSize().height;
|
||||
}
|
||||
|
||||
final FileLocation file = NewConstants.WINDOW_LAYOUT_FILE;
|
||||
final String fWriteTo = file.userPrefLoc;
|
||||
final XMLOutputFactory out = XMLOutputFactory.newInstance();
|
||||
FileOutputStream fos = null;
|
||||
XMLEventWriter writer = null;
|
||||
try {
|
||||
fos = new FileOutputStream(fWriteTo);
|
||||
writer = out.createXMLEventWriter(fos);
|
||||
|
||||
writer.add(EF.createStartDocument());
|
||||
writer.add(NEWLINE);
|
||||
writer.add(EF.createStartElement("", "", "layout"));
|
||||
writer.add(EF.createAttribute(Property.x, String.valueOf(x)));
|
||||
writer.add(EF.createAttribute(Property.y, String.valueOf(y)));
|
||||
writer.add(EF.createAttribute(Property.w, String.valueOf(normalWindowWidth)));
|
||||
writer.add(EF.createAttribute(Property.h, String.valueOf(normalWindowHeight)));
|
||||
writer.add(EF.createAttribute(Property.state, String.valueOf(state)));
|
||||
writer.add(EF.createEndElement("", "", "layout"));
|
||||
writer.flush();
|
||||
writer.add(EF.createEndDocument());
|
||||
} catch (FileNotFoundException e) {
|
||||
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
} catch (XMLStreamException e) {
|
||||
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (writer != null ) {
|
||||
try { writer.close(); } catch (XMLStreamException e) {}
|
||||
}
|
||||
if ( fos != null ) {
|
||||
try { fos.close(); } catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadWindowLayout() {
|
||||
final JFrame window = FView.SINGLETON_INSTANCE.getFrame();
|
||||
final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
|
||||
final FileLocation file = NewConstants.WINDOW_LAYOUT_FILE;
|
||||
boolean usedCustomPrefsFile = false;
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
File userSetting = new File(file.userPrefLoc);
|
||||
if (userSetting.exists()) {
|
||||
usedCustomPrefsFile = true;
|
||||
fis = new FileInputStream(userSetting);
|
||||
}
|
||||
else {
|
||||
fis = new FileInputStream(file.defaultLoc);
|
||||
}
|
||||
|
||||
XMLEventReader reader = null;
|
||||
try {
|
||||
XMLEvent event;
|
||||
StartElement element;
|
||||
Iterator<?> attributes;
|
||||
Attribute attribute;
|
||||
reader = inputFactory.createXMLEventReader(fis);
|
||||
|
||||
while (reader != null && reader.hasNext()) {
|
||||
event = reader.nextEvent();
|
||||
|
||||
if (event.isStartElement()) {
|
||||
element = event.asStartElement();
|
||||
|
||||
if (element.getName().getLocalPart().equals("layout")) {
|
||||
attributes = element.getAttributes();
|
||||
Dimension minSize = window.getMinimumSize();
|
||||
int x = 0, y = 0, w = minSize.width, h = minSize.height, state = Frame.MAXIMIZED_BOTH;
|
||||
while (attributes.hasNext()) {
|
||||
attribute = (Attribute) attributes.next();
|
||||
switch (attribute.getName().toString()) {
|
||||
case Property.x: x = Integer.parseInt(attribute.getValue()); break;
|
||||
case Property.y: y = Integer.parseInt(attribute.getValue()); break;
|
||||
case Property.w: w = Integer.parseInt(attribute.getValue()); break;
|
||||
case Property.h: h = Integer.parseInt(attribute.getValue()); break;
|
||||
case Property.state: state = Integer.parseInt(attribute.getValue()); break;
|
||||
}
|
||||
}
|
||||
|
||||
//set normal size to loaded size
|
||||
normalWindowWidth = w;
|
||||
normalWindowHeight = h;
|
||||
|
||||
//update x and y if needed such that window is centered on that axis
|
||||
//when un-maximized if starting out maximized on that axis
|
||||
int centerX = x + w / 2;
|
||||
int centerY = y + h / 2;
|
||||
Rectangle screenBounds = SDisplayUtil.getScreenBoundsForPoint(new Point(centerX, centerY));
|
||||
if ((state & Frame.MAXIMIZED_HORIZ) == Frame.MAXIMIZED_HORIZ) {
|
||||
x = screenBounds.x + (screenBounds.width - w) / 2;
|
||||
}
|
||||
else { //ensure the window is accessible
|
||||
if (centerX < screenBounds.x) {
|
||||
x = screenBounds.x;
|
||||
}
|
||||
else if (centerX > screenBounds.x + screenBounds.width) {
|
||||
x = screenBounds.x + screenBounds.width - w;
|
||||
if (x < screenBounds.x) {
|
||||
x = screenBounds.x;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((state & Frame.MAXIMIZED_VERT) == Frame.MAXIMIZED_VERT) {
|
||||
y = screenBounds.y + (screenBounds.height - h) / 2;
|
||||
}
|
||||
else { //ensure the window is accessible
|
||||
if (centerY < screenBounds.y) {
|
||||
y = screenBounds.y;
|
||||
}
|
||||
else if (centerY > screenBounds.y + screenBounds.height) {
|
||||
y = screenBounds.y + screenBounds.height - h;
|
||||
if (y < screenBounds.y) {
|
||||
y = screenBounds.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.setBounds(x, y, w, h);
|
||||
window.setExtendedState(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (final Exception e) {
|
||||
try {
|
||||
if (reader != null) { reader.close(); };
|
||||
}
|
||||
catch (final XMLStreamException x) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
e.printStackTrace();
|
||||
if (usedCustomPrefsFile) {
|
||||
throw new InvalidLayoutFileException();
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
finally {
|
||||
if (fis != null ) {
|
||||
try {
|
||||
fis.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets preferred layout file corresponding to current state of UI.
|
||||
* @return {@link java.lang.String}
|
||||
|
||||
@@ -86,6 +86,7 @@ public final class NewConstants {
|
||||
// data that has defaults in the program dir but overrides/additions in the user dir
|
||||
private static final String _DEFAULTS_DIR = _RES_ROOT + "defaults/";
|
||||
public static final FileLocation EDITOR_PREFERENCES_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "editor.preferences");
|
||||
public static final FileLocation WINDOW_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "window.xml");
|
||||
public static final FileLocation HOME_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "home.xml");
|
||||
public static final FileLocation MATCH_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "match.xml");
|
||||
public static final FileLocation EDITOR_LAYOUT_FILE = new FileLocation(_DEFAULTS_DIR, USER_PREFS_DIR, "editor.xml");
|
||||
|
||||
@@ -4,7 +4,6 @@ import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
@@ -42,6 +41,7 @@ import forge.gui.deckeditor.VDeckEditorUI;
|
||||
import forge.gui.framework.DragCell;
|
||||
import forge.gui.framework.EDocID;
|
||||
import forge.gui.framework.SLayoutConstants;
|
||||
import forge.gui.framework.SLayoutIO;
|
||||
import forge.gui.home.VHomeUI;
|
||||
import forge.gui.match.TargetingOverlay;
|
||||
import forge.gui.match.VMatchUI;
|
||||
@@ -95,7 +95,6 @@ public enum FView {
|
||||
// Frame styling
|
||||
frmDocument.setMinimumSize(new Dimension(800, 600));
|
||||
frmDocument.setLocationRelativeTo(null);
|
||||
frmDocument.setExtendedState(frmDocument.getExtendedState() | Frame.MAXIMIZED_BOTH);
|
||||
frmDocument.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
frmDocument.setIconImage(FSkin.getIcon(FSkin.InterfaceIcons.ICO_FAVICON).getImage());
|
||||
frmDocument.setTitle("Forge: " + BuildInfo.getVersionString());
|
||||
@@ -142,8 +141,7 @@ public enum FView {
|
||||
FView.this.frmSplash.dispose();
|
||||
FView.this.frmSplash = null;
|
||||
|
||||
// Allow OS to set location. Hopefully this doesn't cause issues
|
||||
frmDocument.setLocationByPlatform(true);
|
||||
SLayoutIO.loadWindowLayout();
|
||||
frmDocument.setVisible(true);
|
||||
|
||||
// remove this once our userbase has been migrated to the profile layout
|
||||
|
||||
Reference in New Issue
Block a user