mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
Make chat window movable and resizable
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
package forge.gui;
|
package forge.gui;
|
||||||
|
|
||||||
import java.awt.Graphics;
|
import java.awt.Component;
|
||||||
|
import java.awt.Point;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@@ -13,29 +15,58 @@ import net.miginfocom.swing.MigLayout;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import forge.Singletons;
|
||||||
|
import forge.gui.framework.SDisplayUtil;
|
||||||
import forge.model.FModel;
|
import forge.model.FModel;
|
||||||
import forge.net.game.IRemote;
|
import forge.net.game.IRemote;
|
||||||
import forge.net.game.MessageEvent;
|
import forge.net.game.MessageEvent;
|
||||||
|
import forge.properties.ForgePreferences;
|
||||||
import forge.properties.ForgePreferences.FPref;
|
import forge.properties.ForgePreferences.FPref;
|
||||||
import forge.toolbox.FLabel;
|
import forge.toolbox.FLabel;
|
||||||
|
import forge.toolbox.FMouseAdapter;
|
||||||
import forge.toolbox.FScrollPane;
|
import forge.toolbox.FScrollPane;
|
||||||
import forge.toolbox.FSkin;
|
import forge.toolbox.FSkin;
|
||||||
import forge.toolbox.FSkin.SkinnedPanel;
|
|
||||||
import forge.toolbox.FTextArea;
|
import forge.toolbox.FTextArea;
|
||||||
import forge.toolbox.FTextField;
|
import forge.toolbox.FTextField;
|
||||||
import forge.toolbox.SmartScroller;
|
import forge.toolbox.SmartScroller;
|
||||||
|
import forge.view.FDialog;
|
||||||
|
import forge.view.FFrame;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: Write javadoc for this type.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public enum FNetOverlay {
|
public enum FNetOverlay {
|
||||||
SINGLETON_INSTANCE;
|
SINGLETON_INSTANCE;
|
||||||
|
|
||||||
private final OverlayPanel pnl = new OverlayPanel();
|
private final String COORD_DELIM = ",";
|
||||||
/** @return {@link javax.swing.JPanel} */
|
private final ForgePreferences prefs = FModel.getPreferences();
|
||||||
public SkinnedPanel getPanel() {
|
private boolean hasBeenShown, locLoaded;
|
||||||
return this.pnl;
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
private final FDialog window = new FDialog(false, true, "0") {
|
||||||
|
@Override
|
||||||
|
public void setLocationRelativeTo(Component c) {
|
||||||
|
//don't change location this way if dialog has already been shown or location was loaded from preferences
|
||||||
|
if (hasBeenShown || locLoaded) { return; }
|
||||||
|
super.setLocationRelativeTo(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVisible(boolean b0) {
|
||||||
|
if (isVisible() == b0) { return; }
|
||||||
|
if (!b0 && hasBeenShown) {
|
||||||
|
//update preference before hiding window, as otherwise its location will be 0,0
|
||||||
|
prefs.setPref(FPref.CHAT_WINDOW_LOC,
|
||||||
|
getX() + COORD_DELIM + getY() + COORD_DELIM +
|
||||||
|
getWidth() + COORD_DELIM + getHeight());
|
||||||
|
prefs.save();
|
||||||
|
}
|
||||||
|
super.setVisible(b0);
|
||||||
|
if (b0) {
|
||||||
|
hasBeenShown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public FDialog getWindow() {
|
||||||
|
return this.window;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final FTextArea txtLog = new FTextArea();
|
private final FTextArea txtLog = new FTextArea();
|
||||||
@@ -43,7 +74,7 @@ public enum FNetOverlay {
|
|||||||
private final FLabel cmdSend = new FLabel.ButtonBuilder().text("Send").build();
|
private final FLabel cmdSend = new FLabel.ButtonBuilder().text("Send").build();
|
||||||
|
|
||||||
//private boolean minimized = false;
|
//private boolean minimized = false;
|
||||||
private int height = 120;
|
private int height = 140;
|
||||||
private int width = 400;
|
private int width = 400;
|
||||||
|
|
||||||
private IRemote remote = null;
|
private IRemote remote = null;
|
||||||
@@ -72,13 +103,13 @@ public enum FNetOverlay {
|
|||||||
* Semi-transparent overlay panel. Should be used with layered panes.
|
* Semi-transparent overlay panel. Should be used with layered panes.
|
||||||
*/
|
*/
|
||||||
private FNetOverlay() {
|
private FNetOverlay() {
|
||||||
pnl.setOpaque(false);
|
window.setTitle("Chat");
|
||||||
pnl.setVisible(false);
|
window.setVisible(false);
|
||||||
pnl.setBackground(FSkin.getColor(FSkin.Colors.CLR_ZEBRA));
|
window.setBackground(FSkin.getColor(FSkin.Colors.CLR_ZEBRA));
|
||||||
pnl.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS)));
|
window.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS)));
|
||||||
|
|
||||||
pnl.setLayout(new MigLayout("insets 0, gap 0, ax center, wrap 2"));
|
window.setLayout(new MigLayout("insets 0, gap 0, ax center, wrap 2"));
|
||||||
// pnl.add(new FLabel.Builder().text("Loading new game...").fontSize(22).build(), "h 40px!, align center");
|
// window.add(new FLabel.Builder().text("Loading new game...").fontSize(22).build(), "h 40px!, align center");
|
||||||
|
|
||||||
// Block all input events below the overlay
|
// Block all input events below the overlay
|
||||||
|
|
||||||
@@ -89,50 +120,82 @@ public enum FNetOverlay {
|
|||||||
FScrollPane _operationLogScroller = new FScrollPane(txtLog, false);
|
FScrollPane _operationLogScroller = new FScrollPane(txtLog, false);
|
||||||
_operationLogScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
|
_operationLogScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
|
||||||
new SmartScroller(_operationLogScroller);
|
new SmartScroller(_operationLogScroller);
|
||||||
pnl.add(_operationLogScroller, "pushx, hmin 24, pushy, growy, growx, gap 2px 2px 2px 0, sx 2");
|
window.add(_operationLogScroller, "pushx, hmin 24, pushy, growy, growx, gap 2px 2px 2px 0, sx 2");
|
||||||
|
|
||||||
txtInput.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS)));
|
//txtInput.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS)));
|
||||||
pnl.add(txtInput, "pushx, growx, h 26px!, gap 2px 2px 2px 0");
|
window.add(txtInput, "pushx, growx, h 26px!, gap 2px 2px 2px 0");
|
||||||
pnl.add(cmdSend, "w 60px!, h 28px!, gap 0 0 2px 0");
|
window.add(cmdSend, "w 60px!, h 28px!, gap 0 0 2px 0");
|
||||||
|
|
||||||
txtInput.addActionListener(onSend);
|
txtInput.addActionListener(onSend);
|
||||||
cmdSend.setCommand(new Runnable() { @Override public void run() { onSend.actionPerformed(null); } });
|
cmdSend.setCommand(new Runnable() { @Override public void run() { onSend.actionPerformed(null); } });
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showUp(String message) {
|
public void showUp(String message) {
|
||||||
txtLog.setText(message);
|
if (!hasBeenShown) {
|
||||||
pnl.setVisible(true);
|
hasBeenShown = true;
|
||||||
}
|
loadLocation();
|
||||||
|
window.getTitleBar().addMouseListener(new FMouseAdapter() {
|
||||||
private class OverlayPanel extends SkinnedPanel {
|
@Override
|
||||||
private static final long serialVersionUID = -5056220798272120558L;
|
public void onLeftDoubleClick(MouseEvent e) {
|
||||||
|
window.setVisible(false); //hide window if titlebar double-clicked
|
||||||
/**
|
}
|
||||||
* For some reason, the alpha channel background doesn't work properly on
|
});
|
||||||
* Windows 7, so the paintComponent override is required for a
|
|
||||||
* semi-transparent overlay.
|
|
||||||
*
|
|
||||||
* @param g
|
|
||||||
*   Graphics object
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void paintComponent(final Graphics g) {
|
|
||||||
super.paintComponent(g);
|
|
||||||
g.setColor(this.getBackground());
|
|
||||||
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
|
||||||
}
|
}
|
||||||
|
txtLog.setText(message);
|
||||||
|
window.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void loadLocation() {
|
||||||
* TODO: Write javadoc for this method.
|
String value = prefs.getPref(FPref.CHAT_WINDOW_LOC);
|
||||||
* @param mainBounds
|
if (value.length() > 0) {
|
||||||
*/
|
String[] coords = value.split(COORD_DELIM);
|
||||||
public void containerResized(Rectangle mainBounds) {
|
if (coords.length == 4) {
|
||||||
int w = Math.max(width, (int)(mainBounds.width * 0.25f));
|
try {
|
||||||
int x = mainBounds.width - w;
|
int x = Integer.parseInt(coords[0]);
|
||||||
int y = mainBounds.height - height;
|
int y = Integer.parseInt(coords[1]);
|
||||||
getPanel().setBounds(x, y, w, height);
|
int w = Integer.parseInt(coords[2]);
|
||||||
getPanel().validate();
|
int h = Integer.parseInt(coords[3]);
|
||||||
|
|
||||||
|
//ensure the window is accessible
|
||||||
|
int centerX = x + w / 2;
|
||||||
|
int centerY = y + h / 2;
|
||||||
|
Rectangle screenBounds = SDisplayUtil.getScreenBoundsForPoint(new Point(centerX, centerY));
|
||||||
|
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 (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);
|
||||||
|
locLoaded = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefs.setPref(FPref.CHAT_WINDOW_LOC, ""); //clear value if invalid
|
||||||
|
prefs.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
//fallback default size
|
||||||
|
FFrame mainFrame = Singletons.getView().getFrame();
|
||||||
|
int w = Math.max(width, (int)(mainFrame.getWidth() * 0.25f));
|
||||||
|
int x = mainFrame.getWidth() - w;
|
||||||
|
int y = mainFrame.getHeight() - height;
|
||||||
|
window.setBounds(x, y, w, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static SimpleDateFormat inFormat = new SimpleDateFormat("HH:mm:ss");
|
private final static SimpleDateFormat inFormat = new SimpleDateFormat("HH:mm:ss");
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package forge.gui.framework;
|
package forge.gui.framework;
|
||||||
|
|
||||||
import forge.gui.FNetOverlay;
|
|
||||||
import forge.gui.MouseUtil;
|
import forge.gui.MouseUtil;
|
||||||
import forge.toolbox.FAbsolutePositioner;
|
import forge.toolbox.FAbsolutePositioner;
|
||||||
import forge.toolbox.FOverlay;
|
import forge.toolbox.FOverlay;
|
||||||
@@ -126,7 +125,6 @@ public final class SResizingUtil {
|
|||||||
|
|
||||||
FAbsolutePositioner.SINGLETON_INSTANCE.containerResized(mainBounds);
|
FAbsolutePositioner.SINGLETON_INSTANCE.containerResized(mainBounds);
|
||||||
FOverlay.SINGLETON_INSTANCE.getPanel().setBounds(mainBounds);
|
FOverlay.SINGLETON_INSTANCE.getPanel().setBounds(mainBounds);
|
||||||
FNetOverlay.SINGLETON_INSTANCE.containerResized(mainBounds);
|
|
||||||
|
|
||||||
pnlInsets.setBounds(mainBounds);
|
pnlInsets.setBounds(mainBounds);
|
||||||
pnlInsets.validate();
|
pnlInsets.validate();
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public enum CHomeUI implements ICDoc, IMenuProvider {
|
|||||||
VHomeUI.SINGLETON_INSTANCE.getLblStopServer().setEnabled(false);
|
VHomeUI.SINGLETON_INSTANCE.getLblStopServer().setEnabled(false);
|
||||||
VHomeUI.SINGLETON_INSTANCE.getLblStartServer().setEnabled(true);
|
VHomeUI.SINGLETON_INSTANCE.getLblStartServer().setEnabled(true);
|
||||||
|
|
||||||
FNetOverlay.SINGLETON_INSTANCE.getPanel().setVisible(false);
|
FNetOverlay.SINGLETON_INSTANCE.getWindow().setVisible(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import com.google.common.collect.Lists;
|
|||||||
import forge.Singletons;
|
import forge.Singletons;
|
||||||
import forge.assets.FSkinProp;
|
import forge.assets.FSkinProp;
|
||||||
import forge.control.RestartUtil;
|
import forge.control.RestartUtil;
|
||||||
import forge.gui.FNetOverlay;
|
|
||||||
import forge.gui.ImportDialog;
|
import forge.gui.ImportDialog;
|
||||||
import forge.gui.SOverlayUtils;
|
import forge.gui.SOverlayUtils;
|
||||||
import forge.gui.framework.DragCell;
|
import forge.gui.framework.DragCell;
|
||||||
@@ -123,7 +122,6 @@ public enum FView {
|
|||||||
// Note: when adding new panels here, keep in mind that the layered pane
|
// Note: when adding new panels here, keep in mind that the layered pane
|
||||||
// has a null layout, so new components will be W0 x H0 pixels - gotcha!
|
// has a null layout, so new components will be W0 x H0 pixels - gotcha!
|
||||||
// FControl has a method called "sizeComponents" which will fix this.
|
// FControl has a method called "sizeComponents" which will fix this.
|
||||||
lpnDocument.add(FNetOverlay.SINGLETON_INSTANCE.getPanel(), TARGETING_LAYER);
|
|
||||||
|
|
||||||
pnlInsets.add(pnlContent, BorderLayout.CENTER);
|
pnlInsets.add(pnlContent, BorderLayout.CENTER);
|
||||||
pnlInsets.setBackgroundTexture(FSkin.getIcon(FSkinProp.BG_TEXTURE));
|
pnlInsets.setBackgroundTexture(FSkin.getIcon(FSkinProp.BG_TEXTURE));
|
||||||
|
|||||||
@@ -144,6 +144,8 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
|
|||||||
ZONE_LOC_AI_EXILE(""),
|
ZONE_LOC_AI_EXILE(""),
|
||||||
ZONE_LOC_AI_FLASHBACK(""),
|
ZONE_LOC_AI_FLASHBACK(""),
|
||||||
|
|
||||||
|
CHAT_WINDOW_LOC(""),
|
||||||
|
|
||||||
SHORTCUT_SHOWSTACK ("83"),
|
SHORTCUT_SHOWSTACK ("83"),
|
||||||
SHORTCUT_SHOWCOMBAT ("67"),
|
SHORTCUT_SHOWCOMBAT ("67"),
|
||||||
SHORTCUT_SHOWCONSOLE ("76"),
|
SHORTCUT_SHOWCONSOLE ("76"),
|
||||||
|
|||||||
Reference in New Issue
Block a user