From 7e95c9f999d8c13f212c1ae4458454887761a76f Mon Sep 17 00:00:00 2001 From: Eiren Rain Date: Thu, 2 Sep 2021 11:33:27 +0300 Subject: [PATCH] Remember window size and position between restarts Added window and taskbar icons --- .../eiren/gui/AbstractComponentListener.java | 24 +++++++ .../io/eiren/gui/AbstractWindowListener.java | 35 ++++++++++ src/main/java/io/eiren/gui/VRServerGUI.java | 60 ++++++++++++++++-- src/main/java/io/eiren/vr/Main.java | 8 ++- src/main/resources/icon128.png | Bin 0 -> 3660 bytes src/main/resources/icon16.png | Bin 0 -> 429 bytes src/main/resources/icon256.png | Bin 0 -> 9490 bytes src/main/resources/icon32.png | Bin 0 -> 689 bytes src/main/resources/icon48.png | Bin 0 -> 1140 bytes src/main/resources/icon64.png | Bin 0 -> 1274 bytes 10 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 src/main/java/io/eiren/gui/AbstractComponentListener.java create mode 100644 src/main/java/io/eiren/gui/AbstractWindowListener.java create mode 100644 src/main/resources/icon128.png create mode 100644 src/main/resources/icon16.png create mode 100644 src/main/resources/icon256.png create mode 100644 src/main/resources/icon32.png create mode 100644 src/main/resources/icon48.png create mode 100644 src/main/resources/icon64.png diff --git a/src/main/java/io/eiren/gui/AbstractComponentListener.java b/src/main/java/io/eiren/gui/AbstractComponentListener.java new file mode 100644 index 0000000000..f0b5e34456 --- /dev/null +++ b/src/main/java/io/eiren/gui/AbstractComponentListener.java @@ -0,0 +1,24 @@ +package io.eiren.gui; + +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; + +public abstract class AbstractComponentListener implements ComponentListener { + + @Override + public void componentResized(ComponentEvent e) { + } + + @Override + public void componentMoved(ComponentEvent e) { + } + + @Override + public void componentShown(ComponentEvent e) { + } + + @Override + public void componentHidden(ComponentEvent e) { + } + +} \ No newline at end of file diff --git a/src/main/java/io/eiren/gui/AbstractWindowListener.java b/src/main/java/io/eiren/gui/AbstractWindowListener.java new file mode 100644 index 0000000000..0377688685 --- /dev/null +++ b/src/main/java/io/eiren/gui/AbstractWindowListener.java @@ -0,0 +1,35 @@ +package io.eiren.gui; + +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +public abstract class AbstractWindowListener implements WindowListener { + + @Override + public void windowOpened(WindowEvent e) { + } + + @Override + public void windowClosing(WindowEvent e) { + } + + @Override + public void windowClosed(WindowEvent e) { + } + + @Override + public void windowIconified(WindowEvent e) { + } + + @Override + public void windowDeiconified(WindowEvent e) { + } + + @Override + public void windowActivated(WindowEvent e) { + } + + @Override + public void windowDeactivated(WindowEvent e) { + } +} \ No newline at end of file diff --git a/src/main/java/io/eiren/gui/VRServerGUI.java b/src/main/java/io/eiren/gui/VRServerGUI.java index e4f528cd55..97fa954e86 100644 --- a/src/main/java/io/eiren/gui/VRServerGUI.java +++ b/src/main/java/io/eiren/gui/VRServerGUI.java @@ -1,9 +1,12 @@ package io.eiren.gui; +import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.event.MouseInputAdapter; +import io.eiren.util.MacOSX; +import io.eiren.util.OperatingSystem; import io.eiren.util.StringUtils; import io.eiren.util.ann.AWTThread; import io.eiren.vr.Main; @@ -13,15 +16,24 @@ import java.awt.Container; import java.awt.Dimension; import java.awt.Font; +import java.awt.GraphicsConfiguration; +import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ComponentEvent; import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import static javax.swing.BoxLayout.PAGE_AXIS; import static javax.swing.BoxLayout.LINE_AXIS; public class VRServerGUI extends JFrame { + public static final String TITLE = "SlimeVR Server (" + Main.VERSION + ")"; + public final VRServer server; private final TrackersList trackersList; private final SkeletonList skeletonList; @@ -34,13 +46,29 @@ public class VRServerGUI extends JFrame { @AWTThread public VRServerGUI(VRServer server) { - super("SlimeVR Server (" + Main.VERSION + ")"); + super(TITLE); try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception e) { e.printStackTrace(); } - //increaseFontSize(); + if(OperatingSystem.getCurrentPlatform() == OperatingSystem.OSX) + MacOSX.setTitle(TITLE); + try { + List images = new ArrayList(6); + images.add(ImageIO.read(VRServerGUI.class.getResource("/icon16.png"))); + images.add(ImageIO.read(VRServerGUI.class.getResource("/icon32.png"))); + images.add(ImageIO.read(VRServerGUI.class.getResource("/icon48.png"))); + images.add(ImageIO.read(VRServerGUI.class.getResource("/icon64.png"))); + images.add(ImageIO.read(VRServerGUI.class.getResource("/icon128.png"))); + images.add(ImageIO.read(VRServerGUI.class.getResource("/icon256.png"))); + setIconImages(images); + if(OperatingSystem.getCurrentPlatform() == OperatingSystem.OSX) { + MacOSX.setIcons(images); + } + } catch(IOException e1) { + e1.printStackTrace(); + } this.server = server; @@ -56,12 +84,37 @@ public VRServerGUI(VRServer server) { this.skeletonList = new SkeletonList(server, this); add(scroll = new JScrollPane(pane = new EJBox(PAGE_AXIS), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED)); + GraphicsConfiguration gc = getGraphicsConfiguration(); + Rectangle screenBounds = gc.getBounds(); + setMinimumSize(new Dimension(100, 100)); + setSize(Math.min(server.config.getInt("window.width", 800), screenBounds.width), Math.min(server.config.getInt("window.height", 800), screenBounds.height)); + setLocation(server.config.getInt("window.posx", screenBounds.x + (screenBounds.width - getSize().width) / 2), screenBounds.y + server.config.getInt("window.posy", (screenBounds.height - getSize().height) / 2)); - setMinimumSize(new Dimension(1280, 1080)); + // Resize and close listeners to save position and size betwen launcher starts + addComponentListener(new AbstractComponentListener() { + @Override + public void componentResized(ComponentEvent e) { + saveFrameInfo(); + } + + @Override + public void componentMoved(ComponentEvent e) { + saveFrameInfo(); + } + }); build(); } + protected void saveFrameInfo() { + Rectangle b = getBounds(); + server.config.setProperty("window.width", b.width); + server.config.setProperty("window.height", b.height); + server.config.setProperty("window.posx", b.x); + server.config.setProperty("window.posy", b.y); + server.saveConfig(); + } + public float getZoom() { return this.zoom; } @@ -196,7 +249,6 @@ public void actionPerformed(ActionEvent e) { }}); refresh(); - setLocationRelativeTo(null); server.addOnTick(trackersList::updateTrackers); server.addOnTick(skeletonList::updateBones); diff --git a/src/main/java/io/eiren/vr/Main.java b/src/main/java/io/eiren/vr/Main.java index 6d2d4fbe74..1a729ac115 100644 --- a/src/main/java/io/eiren/vr/Main.java +++ b/src/main/java/io/eiren/vr/Main.java @@ -7,7 +7,7 @@ public class Main { - public static String VERSION = "0.0.17"; + public static String VERSION = "0.0.18"; public static VRServer vrServer; @@ -29,6 +29,12 @@ public static void main(String[] args) { new VRServerGUI(vrServer); } catch(Throwable e) { e.printStackTrace(); + try { + Thread.sleep(2000L); + } catch(InterruptedException e2) { + e.printStackTrace(); + } + System.exit(1); // Exit in case error happened on init and window not appeared, but some thread started } finally { try { Thread.sleep(2000L); diff --git a/src/main/resources/icon128.png b/src/main/resources/icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..193cc8d89d892f86934d497ddecdb0733f7ac1ac GIT binary patch literal 3660 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 X)@TVjlIC7T00000NkvXXu0mjfR5-S3 literal 0 HcmV?d00001 diff --git a/src/main/resources/icon256.png b/src/main/resources/icon256.png new file mode 100644 index 0000000000000000000000000000000000000000..75263586903c7e97aa0e877416408752086680e1 GIT binary patch literal 9490 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 XI20Q$0hgtS00000NkvXXu0mjfYxGuQ literal 0 HcmV?d00001 diff --git a/src/main/resources/icon48.png b/src/main/resources/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..be39973faa58c58b73913d0b8263c04e0d2bd392 GIT binary patch literal 1140 zcmV-)1dIELP)Px#1ZP1_K>z@;j|==^1poj7Jy1+kMP@UZXEmB{KA&zrpJz0haYCT3lgY!c*Q12N zdQPW$O{Ut-=Kufy_VfAI%H@h=v1~h?ies^+h{NF3>ihcq^6vMAT&-p_nSfTR&%fXN z`~A+p-*iT!X*ZjPU$5ui@AL5YoqfJ&HJXK8uHV(_xuVf@Mxt^9w5AYB-$t^!d=h->s3z{{H@vY_{y>@@_qza6q4{kH^-? z2^t^ z)5YS6VX(`&+?8^;!mieBJe|I%)2E8WaY3MJIh-_+{s-Fp8 z^5fd<;@Rxz;PC9`^7!`q{{H{*?DpT(>5gf%bVZ`XvDm4M#+P)u@$B{2%jL0_%b$L~ zlyJCWU>`lei{G(010qNS#tmY4#WTe4#WYKD-Ig~ z00F>BL_t(YOJf)XqkwLJk%^fF$|Mf3vaxe;GD11T04{DGUOs*(hZrCrC?qT*Dkcu) z5(OkArKDw`Y&3xGKUo0~$s#AOpoq=qO3Es#YEU*9sB36yfoO4U9!YFg=;-R{8yG@4 zKwxAnWnyXsVwss+Sb~L6fR(Pbjjg_&J(SDf;OOM+V(sb%WU`pLdq4z{fTx$YkFTG9 zKp@ym28N(ug%HM2?XYkzASWWy3nGdD;!)8NF$@f`aq$Td0d?EBSfI74iAg|CvQr8~ z6bYoJrGu!9OeHXvfguab&rSe^R8DRlOqe*3na=}q8S$W?kf#XBBo3$-^OQiD!~y0~ z9?WpX2g=GLE1*ntAkLs9P^qr&S5*xa0E3Jg_gW|u0$8f*>KhuHnp;}i+TD4;K&qp& ztDCJ+E;AdLeSB5j*`P`xpr^O5UvvTw&qR~3Nt5NLOr4rCZMwn?DIT7gvu4|B X` zFLFLqDFiH7$Ro9IQTO5{OPA&7NGxBmV&$sUa%R*PzyJX899}eU$!nDW0000Px#1ZP1_K>z@;j|==^1poj7Pf$!$MP@UZdrzm9bGd?9tZX}-sf@+{|NrXb@voH0 zZ$F>7q0r#g>wQwFgV?(!}9uIGc4xqv+xA{{H`) zdc9{gns!K}j%c*~{QczH?P@ukgIlff?e@E+(rP%HnRmPR_4=cP!e=y@(7@l3Y_@<_ zs_*Ia#ir6W;B_6QK;KA+{>?d#<7e^jcXgTdR+=W|7(YB-#{rPBWW{=%-;azmlf z!{PV!`jc^7Ub-Lo&?0HS5Z9JaGwA#0y&u~DX*2(0KXtSAi zyRMVT&Ar}*T&|60v&gpEhFz}r^!oh!{i~42Xf>Mj@c4O5rF>AR`uO{dWwO)6;d4Zx zn0C6Ke!p}^qTki(wVcgsIh^k4^w`Vg{QUiCH=Dt&)_hQ>ua(N6fWMr2y{L=DiD9s^ zn9I7O(fj%Qz^c`7K%aC)qIO85cS)rB`257M*KtCjhF-6mdAzNX$iAr5=iu+~>h;#h zkvf0M8+0@12 z<=yW3`TX$f^~}57pn<@9PN#7}prL`lxS-F&uh;hU`RU>C(81uOhQpF=wt`r!azvqh zQK*Y#vbdkm(!=2Dm00009 za7bBm000ie000ie0hKEb8vpiV-A$AQ3@CjS&se zU?hT~K_ZHPir9#tC>pT_LETkNrmz4zY#Ff+UNU|=_T&b;Wu{$A$0cXsAwW|nC* z8qL3MGNlZfWP|6V`rcmf1 zl}0u!4d&sLRi%%}$fOu%WY(x`Ii-vS#>i3CSPL+&_i0Z0FQ`Sm2r_FVh#GFyeihJ_AKFXSv`mrUo~=#Dh7db1|<>uIB^ga#Eh_S0{UxIN8!=FfNxGD}Wj)C^)@vtmL7#5Oq?ATeZ4=&Dzjd>PEvl-dOL0 zmyb%;SlhAz*O&op1RH0-XbSKJAhV-Vs-+x z6veaw?G(k70UZ>@?6P4uMKRI!*h5iF{9f#%7>S+PGxs0pJlI)mXi>gA-60&N*h{wQ z$kAiRPk7xY9Xb35D)F5%pAMWkd+vPq<*9NZKrzgP){B=ai#)VSMX=y<&6NuNX=sCL zX-zn1LigJIEXP&zwZ`jpfg3k-y|>(5O%1nc3U}__yZ_*!4UcG9n8%^%Cr_WnJb&>r z&cI*aZ>CqT-?Y7b_ueP%k>?1)_JO9teEif=p8Cf(;{W`mq$|kxuw_L4r~QTh>$mUC kKcaq8snKXO{|&}|0XKGPLr96w-~a#s07*qoM6N<$g198h`v3p{ literal 0 HcmV?d00001