Using resizable and minimizable frames for controls in the map editor.

This commit is contained in:
Stian Grenborgen 2024-01-06 12:48:25 +01:00
parent 9d36d7ef4a
commit b77b15dce5
13 changed files with 391 additions and 168 deletions

View File

@ -3588,7 +3588,11 @@ indianSettlementPanel.highlyWanted=This settlement is very interested in trading
indianSettlementPanel.otherWanted=Other goods that can be traded at this settlement are:
indianSettlementPanel.mostHated=The most hated nation at this settlement:
# MiniMapPanel
minimapPanel.title=Minimap
# InfoPanel
infoPanel.title=Information
infoPanel.defenseBonus=Defense %bonus%%
infoPanel.endTurn=Press enter in order to end the turn.
infoPanel.movementCost=Movement %cost%
@ -3608,6 +3612,7 @@ loadingSavegameDialog.name=Loading Save game
mapEditor.loadedWithMods=You have started the map editor with active mods that contain specification changes. Please note that the same mods need to be manually activated by every user that loads maps that are using anything new from a mod.\n\nYou can go back to the main menu and deactivate any mods through the Preferences if this was not intentional.
# MapEditorTransformPanel
mapEditorTransformPanel.title=Paint
mapEditorTransformPanel.chooseResource=Choose resource
mapEditorTransformPanel.majorRiver=Major river
mapEditorTransformPanel.minorRiver=Minor river

View File

@ -51,10 +51,13 @@ import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenuBar;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import javax.swing.plaf.basic.BasicInternalFrameUI;
import net.sf.freecol.client.ClientOptions;
@ -69,9 +72,11 @@ import net.sf.freecol.client.gui.menu.MapEditorMenuBar;
import net.sf.freecol.client.gui.menu.MenuMouseMotionListener;
// Special case panels, TODO: can we move these to Widgets?
import net.sf.freecol.client.gui.panel.FreeColPanel;
import net.sf.freecol.client.gui.panel.InfoPanel;
import net.sf.freecol.client.gui.panel.MainPanel;
import net.sf.freecol.client.gui.panel.MapControls;
import net.sf.freecol.client.gui.panel.MapEditorTransformPanel;
import net.sf.freecol.client.gui.panel.MiniMapFreeColPanel;
import net.sf.freecol.client.gui.panel.Utility;
import net.sf.freecol.client.gui.video.VideoComponent;
import net.sf.freecol.client.gui.video.VideoListener;
@ -467,7 +472,11 @@ public final class Canvas extends JDesktopPane {
final boolean fullscreenPanel;
if (comp instanceof FreeColPanel) {
fullscreenPanel = ((FreeColPanel) comp).isFullscreen();
final FreeColPanel freeColPanel = (FreeColPanel) comp;
fullscreenPanel = freeColPanel.isFullscreen();
if (popupPosition == null) {
popupPosition = freeColPanel.getFramePopupPosition();
}
} else {
fullscreenPanel = false;
}
@ -483,18 +492,27 @@ public final class Canvas extends JDesktopPane {
c.setBorder(null);
}
if (comp instanceof FreeColPanel
&& ((FreeColPanel) comp).getFrameBorder() != null) {
f.setBorder(((FreeColPanel) comp).getFrameBorder());
} else if (comp.getBorder() != null) {
if (comp.getBorder() instanceof EmptyBorder) {
f.setBorder(Utility.blankBorder(10, 10, 10, 10));
if (!toolBox) {
if (comp instanceof FreeColPanel
&& ((FreeColPanel) comp).getFrameBorder() != null) {
f.setBorder(((FreeColPanel) comp).getFrameBorder());
} else if (comp.getBorder() != null) {
if (comp.getBorder() instanceof EmptyBorder) {
f.setBorder(Utility.blankBorder(10, 10, 10, 10));
} else {
f.setBorder(comp.getBorder());
comp.setBorder(Utility.blankBorder(5, 5, 5, 5));
}
} else {
f.setBorder(comp.getBorder());
comp.setBorder(Utility.blankBorder(5, 5, 5, 5));
f.setBorder(null);
}
}
if (comp instanceof FreeColPanel) {
final FreeColPanel panel = (FreeColPanel) comp;
final String title = panel.getFrameTitle();
if (title != null) {
f.setTitle(panel.getFrameTitle());
}
} else {
f.setBorder(null);
}
if (!fullscreenPanel) {
@ -503,18 +521,30 @@ public final class Canvas extends JDesktopPane {
comp.addMouseListener(fml);
}
if (f.getUI() instanceof BasicInternalFrameUI) {
if (!toolBox && f.getUI() instanceof BasicInternalFrameUI) {
f.getRootPane().setWindowDecorationStyle(JRootPane.NONE);
BasicInternalFrameUI biu = (BasicInternalFrameUI) f.getUI();
biu.setNorthPane(null);
biu.setSouthPane(null);
biu.setWestPane(null);
biu.setEastPane(null);
} else {
f.setMaximizable(true);
f.setClosable(true);
f.setIconifiable(true);
}
f.addInternalFrameListener(new InternalFrameAdapter() {
@Override
public void internalFrameClosing(InternalFrameEvent e) {
savePositionAndSize(comp, f);
}
});
f.getContentPane().add(comp);
f.setOpaque(false);
f.pack();
final Dimension size;
if (fullscreenPanel) {
size = getSize();
@ -528,6 +558,7 @@ public final class Canvas extends JDesktopPane {
} else {
final Point p = chooseLocation(comp, size.width, size.height, popupPosition);
final Point adjustedP = adjustLocationForClearSpace(p, size.width, size.height);
if (popupPosition == PopupPosition.CENTERED_FORCED || p.equals(adjustedP)) {
f.setLocation(p);
f.putClientProperty(PROPERTY_POPUP_POSITION, popupPosition);
@ -662,6 +693,19 @@ public final class Canvas extends JDesktopPane {
x = ((getWidth() - width) * 3) / 4;
y = (getHeight() - height) / 2;
break;
case LOWER_LEFT:
x = 0;
y = getHeight() - height;
break;
case LOWER_RIGHT:
x = getWidth() - width;
y = getHeight() - height;
break;
case UPPER_RIGHT:
x = getWidth() - width;
y = 0;
break;
case UPPER_LEFT:
case ORIGIN:
x = y = 0;
break;
@ -874,13 +918,25 @@ public final class Canvas extends JDesktopPane {
*/
private void notifyClose(Component c, JInternalFrame jif) {
if (c instanceof FreeColPanel) {
FreeColPanel fcp = (FreeColPanel)c;
FreeColPanel fcp = (FreeColPanel) c;
fcp.firePropertyChange("closing", false, true);
if (nothingShowing()
// These are added/removed as a part of "updateMenuBar"
&& !(c instanceof InfoPanel) && !(c instanceof MiniMapFreeColPanel)) {
updateMenuBar();
}
}
}
private void savePositionAndSize(Component c, JInternalFrame jif) {
if (c instanceof FreeColPanel) {
FreeColPanel fcp = (FreeColPanel) c;
if (fcp.isFullscreen()) {
return;
}
savePosition(fcp, jif.getLocation());
saveSize(fcp, fcp.getSize());
if (nothingShowing()) updateMenuBar();
}
}
@ -896,6 +952,15 @@ public final class Canvas extends JDesktopPane {
// remove listeners, they will be added when launching the new game...
removeKeyAndMouseListeners();
for (JInternalFrame f : getAllFrames()) {
final FreeColPanel fcp = getFreeColPanel(f);
if (fcp != null) {
removeFromCanvas(fcp);
} else {
removeFromCanvas(f);
}
}
for (Component c : getComponents()) {
if (c instanceof CanvasMapViewer) {
continue;
@ -965,6 +1030,10 @@ public final class Canvas extends JDesktopPane {
* @param d The {@code Dimension} to use as default.
*/
public void restoreSavedSize(Component comp, Dimension d) {
if (comp instanceof FreeColPanel && ((FreeColPanel) comp).isFullscreen()) {
return;
}
final Dimension pref = comp.getPreferredSize();
final Dimension sugg = (d == null) ? pref : d;
boolean save = false;
@ -1030,10 +1099,11 @@ public final class Canvas extends JDesktopPane {
if (panel.endsWith("Panel")) {
for (Component c1 : getComponents()) {
if (c1 instanceof JInternalFrame) {
for (Component c2 : ((JInternalFrame)c1).getContentPane()
.getComponents()) {
final JInternalFrame jif = (JInternalFrame) c1;
for (Component c2 : jif.getContentPane().getComponents()) {
if (panel.equals(c2.getClass().getName())) {
notifyClose(c2, (JInternalFrame)c1);
savePositionAndSize(c2, jif);
notifyClose(c2, jif);
return;
}
}
@ -1117,6 +1187,22 @@ public final class Canvas extends JDesktopPane {
}
return null;
}
public boolean isAddedAsPanelFrameOrIcon(Component component) {
for (JInternalFrame f : getAllFrames()) {
for (Component c2 : f.getContentPane().getComponents()) {
if (component == c2) {
return true;
}
}
}
for (Component c1 : getComponents()) {
if (component == c1) {
return true;
}
}
return false;
}
/**
* Gets any currently displayed component matching a predicate.
@ -1167,6 +1253,10 @@ public final class Canvas extends JDesktopPane {
final Rectangle updateBounds = comp.getBounds();
final JInternalFrame jif = getInternalFrame(comp);
if (jif != null) {
savePositionAndSize(comp, jif);
}
if (jif != null && jif != comp) {
jif.dispose();
} else {
@ -1303,14 +1393,31 @@ public final class Canvas extends JDesktopPane {
* @return True if any were added.
*/
public boolean addMapControls() {
if (this.mapControls == null) return false;
List<Component> components
= this.mapControls.getComponentsToAdd(this.oldSize);
for (Component c : components) {
addToCanvas(c, JLayeredPane.MODAL_LAYER);
if (this.mapControls == null) {
return false;
}
final List<JComponent> components = this.mapControls.getComponentsToAdd(this.oldSize);
if (hasAtLeastOneMapControlFrom(components)) {
return false;
}
for (JComponent c : components) {
if (freeColClient.isMapEditor()) {
addAsFrame(c, true, null, true);
} else {
addToCanvas(c, JLayeredPane.MODAL_LAYER);
}
}
return !components.isEmpty();
}
private boolean hasAtLeastOneMapControlFrom(List<JComponent> components) {
for (JComponent c : components) {
if (isAddedAsPanelFrameOrIcon(c)) {
return true;
}
}
return false;
}
/**
* Remove the map controls.
@ -1321,7 +1428,7 @@ public final class Canvas extends JDesktopPane {
if (mapControls == null) {
return false;
}
final List<Component> components = mapControls.getComponentsPresent();
final List<JComponent> components = mapControls.getComponentsPresent();
boolean ret = false;
for (Component c : components) {
removeFromCanvas(c);
@ -1340,6 +1447,7 @@ public final class Canvas extends JDesktopPane {
public void closeMenus() {
for (JInternalFrame jif : getAllFrames()) {
for (Component c : jif.getContentPane().getComponents()) {
savePositionAndSize(c, jif);
notifyClose(c, jif);
}
jif.dispose();
@ -1531,11 +1639,8 @@ public final class Canvas extends JDesktopPane {
* Display the map editor transform panel.
*/
public void showMapEditorTransformPanel() {
MapEditorTransformPanel panel
= new MapEditorTransformPanel(this.freeColClient);
JInternalFrame f = addAsFrame(panel, true, PopupPosition.CENTERED,
false);
f.setLocation(f.getX(), 50); // move up to near the top
final MapEditorTransformPanel panel = new MapEditorTransformPanel(this.freeColClient);
addAsFrame(panel, true, null, true);
repaint();
}

View File

@ -141,6 +141,10 @@ public class SwingGUI extends GUI {
CENTERED,
CENTERED_LEFT,
CENTERED_RIGHT,
LOWER_LEFT,
LOWER_RIGHT,
UPPER_LEFT,
UPPER_RIGHT,
/**
* Places centered even this means overlapping components.

View File

@ -48,7 +48,7 @@ public abstract class MapboardAction extends FreeColAction {
@Override
protected boolean shouldBeEnabled() {
return super.shouldBeEnabled()
&& !getGUI().isPanelShowing()
&& (!getGUI().isPanelShowing() || freeColClient.isMapEditor())
&& (getGame() == null
|| freeColClient.isMapEditor()
|| freeColClient.currentPlayerIsMyPlayer());

View File

@ -19,7 +19,6 @@
package net.sf.freecol.client.gui.panel;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
@ -35,8 +34,8 @@ import java.util.stream.Collectors;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
import net.miginfocom.swing.MigLayout;
import net.sf.freecol.client.ClientOptions;
import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.client.gui.ImageLibrary;
@ -84,15 +83,19 @@ public final class CornerMapControls extends MapControls {
private Image miniMapSkin;
private MiniMapPanelSkin miniMapPanelSkin;
private boolean oldUseSkin = false;
private boolean forceUpdate = false;
/**
* The basic constructor.
*
* @param freeColClient The {@code FreeColClient} for the game.
*/
public CornerMapControls(final FreeColClient freeColClient) {
super(freeColClient, true);
super(freeColClient);
this.lib = freeColClient.getGUI().getFixedImageLibrary();
this.compassRose = this.lib.getCompassRose();
@ -116,15 +119,7 @@ public final class CornerMapControls extends MapControls {
}
});
this.miniMapPanel = new JPanel();
this.miniMapPanel.setFocusable(false);
/**
* In order to make the setLocation setup work, we need to set
* the layout to null first, then set the size of the minimap,
* and then its location.
*/
this.miniMapPanel.setLayout(null);
this.miniMapPanel = new MiniMapFreeColPanel(freeColClient);
this.miniMapPanelSkin = new MiniMapPanelSkin();
// Add buttons:
@ -148,42 +143,57 @@ public final class CornerMapControls extends MapControls {
public void updateLayoutIfNeeded() {
super.updateLayoutIfNeeded();
final BufferedImage newMinimapSkin = this.lib.getMiniMapSkin();
if (this.miniMapSkin == newMinimapSkin) {
BufferedImage newMinimapSkin = this.lib.getMiniMapSkin();
if (!forceUpdate && oldUseSkin == isUseSkin() && (!oldUseSkin || this.miniMapSkin == newMinimapSkin)) {
// No update necessary.
return;
} else if (!isUseSkin()) {
newMinimapSkin = null;
final MigLayout layout = new MigLayout("ins 0 0 0 0, gap 0 0");
this.miniMapPanel.setLayout(layout);
layout.addLayoutComponent(this.miniMap, "newline, grow, shrink, span, w 100%, h 100%");
} else {
this.miniMapPanel.setLayout(null);
}
this.oldUseSkin = isUseSkin();
this.miniMapSkin = newMinimapSkin;
this.forceUpdate = false;
int width = this.lib.scaleInt(MINI_MAP_WIDTH),
height = this.lib.scaleInt(MINI_MAP_HEIGHT);
this.miniMap.setSize(width, height);
int width = this.lib.scaleInt(MINI_MAP_WIDTH);
int height = this.lib.scaleInt(MINI_MAP_HEIGHT);
this.miniMap.setSize(new Dimension(width, height));
if (this.miniMapSkin != null) {
width = this.miniMapSkin.getWidth(null);
height = this.miniMapSkin.getHeight(null);
this.miniMapPanel.setBorder(null);
//this.miniMapPanel.setBorder(null);
this.miniMapPanel.setSize(width, height);
this.miniMapPanelSkin.setLocation(0, 0);
this.miniMapPanelSkin.setSize(width, height);
this.miniMapPanel.setOpaque(false);
} else {
this.miniMapPanel.setOpaque(true);
this.miniMap.setBorder(new BevelBorder(BevelBorder.RAISED));
//this.miniMap.setBorder(new BevelBorder(BevelBorder.RAISED));
}
final PropertyList pl = ResourceManager.getPropertyList("image.skin.MiniMap.properties");
this.miniMap.setLocation(
this.lib.scaleInt(pl.getInt("minimap.x")),
this.lib.scaleInt(pl.getInt("minimap.y")));
this.miniMap.setSize(
this.lib.scaleInt(pl.getInt("minimap.width")),
this.lib.scaleInt(pl.getInt("minimap.height")));
centerComponentOnCoordinate(miniMapToggleBorders, pl, "politicalButton");
centerComponentOnCoordinate(miniMapToggleFogOfWarButton, pl, "fogOfWarButton");
centerComponentOnCoordinate(miniMapZoomInButton, pl, "zoomInButton");
centerComponentOnCoordinate(miniMapZoomOutButton, pl, "zoomOutButton");
if (isUseSkin()) {
final PropertyList pl = ResourceManager.getPropertyList("image.skin.MiniMap.properties");
this.miniMap.setLocation(
this.lib.scaleInt(pl.getInt("minimap.x")),
this.lib.scaleInt(pl.getInt("minimap.y")));
this.miniMap.setSize(
this.lib.scaleInt(pl.getInt("minimap.width")),
this.lib.scaleInt(pl.getInt("minimap.height")));
centerComponentOnCoordinate(miniMapToggleBorders, pl, "politicalButton");
centerComponentOnCoordinate(miniMapToggleFogOfWarButton, pl, "fogOfWarButton");
centerComponentOnCoordinate(miniMapZoomInButton, pl, "zoomInButton");
centerComponentOnCoordinate(miniMapZoomOutButton, pl, "zoomOutButton");
} else {
this.miniMapPanel.setPreferredSize(new Dimension(width, height));
getGUI().restoreSavedSize(this.miniMapPanel, new Dimension(width, height));
}
miniMapPanel.revalidate();
miniMapPanel.repaint();
@ -199,55 +209,58 @@ public final class CornerMapControls extends MapControls {
* {@inheritDoc}
*/
@Override
public List<Component> getComponentsToAdd(Dimension newSize) {
List<Component> ret = new ArrayList<>();
public List<JComponent> getComponentsToAdd(Dimension newSize) {
List<JComponent> ret = new ArrayList<>();
if (getGame() == null) return ret;
final int cw = newSize.width;
final int ch = newSize.height;
if (!this.infoPanel.isShowing()) {
this.infoPanel.setLocation(cw - this.infoPanel.getWidth(),
ch - this.infoPanel.getHeight());
if (!this.infoPanel.isShowing() && !this.miniMapPanel.isShowing()) {
forceUpdate = true;
updateLayoutIfNeeded();
if (!this.getFreeColClient().isMapEditor()) {
this.infoPanel.setLocation(cw - this.infoPanel.getWidth(), ch - this.infoPanel.getHeight());
this.miniMapPanel.setLocation(0, ch - this.miniMapPanel.getHeight());
}
this.infoPanel.refresh();
ret.add(this.infoPanel);
}
if (!this.miniMapPanel.isShowing()) {
this.miniMapPanel.setLocation(0, ch - this.miniMapPanel.getHeight());
ret.add(this.miniMapPanel);
}
final boolean rose = getClientOptions()
.getBoolean(ClientOptions.DISPLAY_COMPASS_ROSE);
if (rose && !this.compassRose.isShowing()) {
this.compassRose.setLocation(cw - this.compassRose.getWidth() - 20, 20);
ret.add(this.compassRose);
}
ret.addAll(this.unitButtons.stream().filter(b -> !b.isShowing()).collect(Collectors.toList()));
if (!this.unitButtons.isEmpty() && !this.getFreeColClient().isMapEditor()) {
final int UNSCALED_SPACE_BETWEEN_BUTTONS = 5;
final int spaceBetweenButtons = lib.scaleInt(UNSCALED_SPACE_BETWEEN_BUTTONS);
final Dimension buttonsDimension = calculateTotalDimension(unitButtons, spaceBetweenButtons);
if (!this.getFreeColClient().isMapEditor()) {
final boolean rose = getClientOptions()
.getBoolean(ClientOptions.DISPLAY_COMPASS_ROSE);
if (rose && !this.compassRose.isShowing()) {
this.compassRose.setLocation(cw - this.compassRose.getWidth() - 20, 20);
ret.add(this.compassRose);
}
final int totalWidth = buttonsDimension.width + this.miniMapPanel.getWidth() + this.infoPanel.getWidth();
if (totalWidth < newSize.width) {
final Point firstButtonPoint = calculateFirstPosition(newSize, unitButtons, spaceBetweenButtons, buttonsDimension);
layoutUnitButtons(unitButtons, buttonsDimension, firstButtonPoint, spaceBetweenButtons);
} else {
final int numberInTopRow = this.unitButtons.size() / 2;
ret.addAll(this.unitButtons.stream().filter(b -> !b.isShowing()).collect(Collectors.toList()));
if (!this.unitButtons.isEmpty()) {
final int UNSCALED_SPACE_BETWEEN_BUTTONS = 5;
final int spaceBetweenButtons = lib.scaleInt(UNSCALED_SPACE_BETWEEN_BUTTONS);
final Dimension buttonsDimension = calculateTotalDimension(unitButtons, spaceBetweenButtons);
final List<UnitButton> bottomRowButtons = unitButtons.subList(numberInTopRow, unitButtons.size());
final Dimension buttonsBottomRowDimension = calculateTotalDimension(bottomRowButtons, spaceBetweenButtons);
final Point firstButtonBottomRowPoint = calculateFirstPosition(newSize, bottomRowButtons, spaceBetweenButtons, buttonsBottomRowDimension);
layoutUnitButtons(bottomRowButtons,buttonsDimension, firstButtonBottomRowPoint, spaceBetweenButtons);
final List<UnitButton> topRowButtons = unitButtons.subList(0, numberInTopRow);
final Dimension buttonsTopRowDimension = calculateTotalDimension(topRowButtons, spaceBetweenButtons);
final Point firstButtonTopRowPoint = calculateFirstPosition(newSize, bottomRowButtons, spaceBetweenButtons, buttonsTopRowDimension);
layoutUnitButtons(topRowButtons, buttonsDimension, new Point(firstButtonTopRowPoint.x, firstButtonBottomRowPoint.y - buttonsTopRowDimension.height - spaceBetweenButtons), spaceBetweenButtons);
final int totalWidth = buttonsDimension.width + this.miniMapPanel.getWidth() + this.infoPanel.getWidth();
if (totalWidth < newSize.width) {
final Point firstButtonPoint = calculateFirstPosition(newSize, unitButtons, spaceBetweenButtons, buttonsDimension);
layoutUnitButtons(unitButtons, buttonsDimension, firstButtonPoint, spaceBetweenButtons);
} else {
final int numberInTopRow = this.unitButtons.size() / 2;
final List<UnitButton> bottomRowButtons = unitButtons.subList(numberInTopRow, unitButtons.size());
final Dimension buttonsBottomRowDimension = calculateTotalDimension(bottomRowButtons, spaceBetweenButtons);
final Point firstButtonBottomRowPoint = calculateFirstPosition(newSize, bottomRowButtons, spaceBetweenButtons, buttonsBottomRowDimension);
layoutUnitButtons(bottomRowButtons,buttonsDimension, firstButtonBottomRowPoint, spaceBetweenButtons);
final List<UnitButton> topRowButtons = unitButtons.subList(0, numberInTopRow);
final Dimension buttonsTopRowDimension = calculateTotalDimension(topRowButtons, spaceBetweenButtons);
final Point firstButtonTopRowPoint = calculateFirstPosition(newSize, bottomRowButtons, spaceBetweenButtons, buttonsTopRowDimension);
layoutUnitButtons(topRowButtons, buttonsDimension, new Point(firstButtonTopRowPoint.x, firstButtonBottomRowPoint.y - buttonsTopRowDimension.height - spaceBetweenButtons), spaceBetweenButtons);
}
}
}
return ret;
@ -286,10 +299,10 @@ public final class CornerMapControls extends MapControls {
* {@inheritDoc}
*/
@Override
public List<Component> getComponentsPresent() {
List<Component> ret = new ArrayList<>();
if (this.infoPanel.isShowing()) ret.add(this.infoPanel);
if (this.miniMapPanel.isShowing()) ret.add(this.miniMapPanel);
public List<JComponent> getComponentsPresent() {
List<JComponent> ret = new ArrayList<>();
ret.add(this.infoPanel);
ret.add(this.miniMapPanel);
final boolean rose = getClientOptions()
.getBoolean(ClientOptions.DISPLAY_COMPASS_ROSE);
if (rose && this.compassRose.isShowing()) ret.add(this.compassRose);

View File

@ -24,15 +24,12 @@ import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
@ -44,6 +41,7 @@ import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.client.control.InGameController;
import net.sf.freecol.client.gui.GUI;
import net.sf.freecol.client.gui.ImageLibrary;
import net.sf.freecol.client.gui.SwingGUI.PopupPosition;
import net.sf.freecol.client.gui.panel.FreeColButton.ButtonStyle;
import net.sf.freecol.common.model.AbstractUnit;
import net.sf.freecol.common.model.Colony;
@ -295,6 +293,22 @@ public abstract class FreeColPanel extends MigPanel implements ActionListener {
public boolean isFullscreen() {
return false;
}
/**
* Allows subclasses to define a frame title.
* @return The title, if defined by a subclass.
*/
public String getFrameTitle() {
return null;
}
/**
* Allows subclasses to define a default frame popup position.
* @return The title, if defined by a subclass.
*/
public PopupPosition getFramePopupPosition() {
return null;
}
// Interface ActionListener
@ -314,31 +328,6 @@ public abstract class FreeColPanel extends MigPanel implements ActionListener {
// Override Component
/**
* {@inheritDoc}
*/
@Override
public void removeNotify() {
super.removeNotify();
// removeNotify gets called when a JPanel has no parent any
// more, that is the best opportunity available for JPanels
// to be given a chance to remove leak generating references.
if (okButton == null) return; // Been here before
// We need to make sure the layout is cleared because some
// versions of MigLayout are leaky.
setLayout(null);
okButton.removeActionListener(this);
okButton = null;
for (MouseListener listener : getMouseListeners()) {
removeMouseListener(listener);
}
}
/**
* {@inheritDoc}
*/

View File

@ -34,9 +34,11 @@ import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
@ -46,6 +48,7 @@ import net.miginfocom.swing.MigLayout;
import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.client.control.MapTransform;
import net.sf.freecol.client.gui.ImageLibrary;
import net.sf.freecol.client.gui.SwingGUI.PopupPosition;
import net.sf.freecol.client.gui.action.EndTurnAction;
import net.sf.freecol.common.i18n.Messages;
import net.sf.freecol.common.model.AbstractGoods;
@ -85,7 +88,7 @@ public final class InfoPanel extends FreeColPanel
private static final int PRODUCTION = 4;
/** Preferred size for non-skinned panel. */
public static final Dimension PREFERRED_SIZE = new Dimension(260, 130);
public static final Dimension PREFERRED_SIZE = new Dimension(250, 138);
/** The image library to use for the font. */
private final ImageLibrary lib;
@ -150,19 +153,19 @@ public final class InfoPanel extends FreeColPanel
};
}
public void updateLayoutIfNeeded() {
public void updateLayoutIfNeeded(boolean newUseSkin) {
final Font newFont = this.lib.getScaledFont("normal-plain-tiny", null);
final Image newSkin = (useSkin) ? this.lib.getScaledImage("image.skin.InfoPanel")
final Image newSkin = (newUseSkin) ? this.lib.getScaledImage("image.skin.InfoPanel")
: null;
if (newFont == font && newSkin == skin) {
if (useSkin == newUseSkin && newFont == font && newSkin == skin) {
// No change.
return;
}
this.font = newFont;
this.skin = newSkin;
this.useSkin = newUseSkin;
if (this.skin != null) {
setBorder(null);
@ -170,6 +173,10 @@ public final class InfoPanel extends FreeColPanel
// skin is output in overridden paintComponent(), which calls
// its parent, which will display panels added here
setOpaque(false);
} else if (!useSkin) {
setSize(this.lib.scale(PREFERRED_SIZE));
setBorder(BorderFactory.createEmptyBorder());
setOpaque(true);
} else {
setSize(this.lib.scale(PREFERRED_SIZE));
setBorder(FreeColImageBorder.panelWithoutShadowBorder);
@ -203,9 +210,10 @@ public final class InfoPanel extends FreeColPanel
panel.setLocation(lib.scaleInt(pl.getInt("panel.x")), lib.scaleInt(pl.getInt("panel.y")));
panel.setSize(lib.scaleInt(pl.getInt("panel.width")), lib.scaleInt(pl.getInt("panel.height")));
} else {
final int y = (this.getHeight() - panel.getHeight()/2) / 2;
final int y = (this.getHeight() - panel.getHeight()) / 2;
final int x = (this.getWidth() - panel.getWidth()) / 2;
panel.setLocation(x, y);
panel.setSize(lib.scale(PREFERRED_SIZE));
panel.setLocation(0, 0);
}
this.removeAll();
@ -473,14 +481,21 @@ public final class InfoPanel extends FreeColPanel
* Update this {@code InfoPanel} to end turn mode.
*/
public void update() {
boolean updated = false;
InfoPanelMode oldMode = changeMode(InfoPanelMode.END);
if (oldMode != InfoPanelMode.END) {
fillEndPanel();
updated = true;
if (getFreeColClient().isMapEditor()) {
changeMode(InfoPanelMode.NONE);
removeAll();
revalidate();
repaint();
} else {
boolean updated = false;
InfoPanelMode oldMode = changeMode(InfoPanelMode.END);
if (oldMode != InfoPanelMode.END) {
fillEndPanel();
updated = true;
}
logger.info("InfoPanel " + ((updated) ? "updated " : "maintained ")
+ oldMode + " -> " + this.mode);
}
logger.info("InfoPanel " + ((updated) ? "updated " : "maintained ")
+ oldMode + " -> " + this.mode);
}
/**
@ -575,6 +590,15 @@ public final class InfoPanel extends FreeColPanel
}
}
@Override
public PopupPosition getFramePopupPosition() {
return PopupPosition.LOWER_RIGHT;
}
@Override
public String getFrameTitle() {
return Messages.message("infoPanel.title");
}
// Override JComponent

View File

@ -19,23 +19,20 @@
package net.sf.freecol.client.gui.panel;
import static net.sf.freecol.common.util.StringUtils.lastPart;
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.freecol.client.ClientOptions;
import javax.swing.JComponent;
import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.client.control.FreeColClientHolder;
import net.sf.freecol.client.gui.GUI;
import net.sf.freecol.client.gui.action.ActionManager;
import net.sf.freecol.common.model.Tile;
import net.sf.freecol.common.model.Unit;
import net.sf.freecol.common.util.Introspector;
/**
@ -64,6 +61,7 @@ public abstract class MapControls extends FreeColClientHolder {
/** The buttons to control unit actions. */
protected final List<UnitButton> unitButtons = new ArrayList<>();
private boolean useSkin;
/**
* The basic constructor.
@ -71,9 +69,10 @@ public abstract class MapControls extends FreeColClientHolder {
* @param freeColClient The {@code FreeColClient} for the game.
* @param useSkin Use a skin or not in the info panel.
*/
protected MapControls(final FreeColClient freeColClient, boolean useSkin) {
protected MapControls(final FreeColClient freeColClient) {
super(freeColClient);
this.useSkin = !this.getFreeColClient().isMapEditor();
this.infoPanel = new InfoPanel(freeColClient, useSkin);
this.infoPanel.setFocusable(false);
@ -89,12 +88,17 @@ public abstract class MapControls extends FreeColClientHolder {
this.miniMapZoomInButton = miniButtons.remove(0);
}
public boolean isUseSkin() {
return useSkin;
}
/**
* Updates the layout with possibly a new skin and/or size.
*/
public void updateLayoutIfNeeded() {
infoPanel.updateLayoutIfNeeded();
this.useSkin = !this.getFreeColClient().isMapEditor();
infoPanel.updateLayoutIfNeeded(this.useSkin);
}
/**
@ -122,7 +126,7 @@ public abstract class MapControls extends FreeColClientHolder {
* @param size The {@code Dimension} of the canvas.
* @return A list of {@code Component}s to add to the canvas.
*/
public abstract List<Component> getComponentsToAdd(Dimension size);
public abstract List<JComponent> getComponentsToAdd(Dimension size);
/**
* Prepare and return a list of map controls components to remove
@ -130,7 +134,7 @@ public abstract class MapControls extends FreeColClientHolder {
*
* @return A list of {@code Component}s to remove from the canvas.
*/
public abstract List<Component> getComponentsPresent();
public abstract List<JComponent> getComponentsPresent();
// Simple public routines

View File

@ -26,7 +26,6 @@ import static net.sf.freecol.common.util.CollectionUtils.transform;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
@ -34,6 +33,7 @@ import java.util.List;
import java.util.function.Function;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
@ -46,6 +46,9 @@ import net.sf.freecol.client.control.MapEditorController;
import net.sf.freecol.client.control.MapTransform;
import net.sf.freecol.client.gui.ChoiceItem;
import net.sf.freecol.client.gui.ImageLibrary;
import net.sf.freecol.client.gui.SwingGUI.PopupPosition;
import net.sf.freecol.client.gui.panel.WrapLayout.HorizontalAlignment;
import net.sf.freecol.client.gui.panel.WrapLayout.HorizontalGap;
import net.sf.freecol.common.i18n.Messages;
import net.sf.freecol.common.model.Direction;
import net.sf.freecol.common.model.IndianNationType;
@ -272,7 +275,11 @@ public final class MapEditorTransformPanel extends FreeColPanel {
public MapEditorTransformPanel(FreeColClient freeColClient) {
super(freeColClient, null, new BorderLayout());
listPanel = new JPanel(new GridLayout(2, 0));
final Dimension terrainSize = ImageLibrary.scaleDimension(getImageLibrary().scale(ImageLibrary.TILE_OVERLAY_SIZE), ImageLibrary.SMALLER_SCALE);
listPanel = new JPanel(new WrapLayout()
.withForceComponentSize(terrainSize)
.withHorizontalAlignment(HorizontalAlignment.LEFT)
.withHorizontalGap(HorizontalGap.AUTO));
group = new ButtonGroup();
//Add an invisible, move button to de-select all others
@ -281,12 +288,25 @@ public final class MapEditorTransformPanel extends FreeColPanel {
JScrollPane sl = new JScrollPane(listPanel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
sl.getViewport().setOpaque(false);
add(sl);
listPanel.setSize(new Dimension(terrainSize.width * 3, 0));
add(sl, BorderLayout.CENTER);
setBorder(BorderFactory.createEmptyBorder());
revalidate();
repaint();
}
@Override
public String getFrameTitle() {
return Messages.message("mapEditorTransformPanel.title");
}
@Override
public PopupPosition getFramePopupPosition() {
return PopupPosition.UPPER_RIGHT;
}
/**
* Get the last used native nation.
*
@ -314,10 +334,10 @@ public final class MapEditorTransformPanel extends FreeColPanel {
private void buildList() {
final Specification spec = getSpecification();
final Dimension terrainSize = ImageLibrary
.scaleDimension(ImageLibrary.TILE_OVERLAY_SIZE,
.scaleDimension(getImageLibrary().scale(ImageLibrary.TILE_OVERLAY_SIZE),
ImageLibrary.SMALLER_SCALE);
final Dimension riverSize = ImageLibrary
.scaleDimension(ImageLibrary.TILE_SIZE,
.scaleDimension(getImageLibrary().scale(ImageLibrary.TILE_SIZE),
ImageLibrary.SMALLER_SCALE);
for (TileType type : spec.getTileTypeList()) {

View File

@ -99,6 +99,7 @@ public final class MiniMap extends JPanel implements MouseInputListener {
addMouseMotionListener(this);
minimapPainterThread.start();
minimapPainterThread.setPriority(Thread.NORM_PRIORITY - 1);
setOpaque(false);
}
/**

View File

@ -0,0 +1,46 @@
/**
* Copyright (C) 2002-2024 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* FreeCol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.client.gui.panel;
import javax.swing.BorderFactory;
import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.client.gui.SwingGUI.PopupPosition;
import net.sf.freecol.common.i18n.Messages;
public class MiniMapFreeColPanel extends FreeColPanel {
public MiniMapFreeColPanel(FreeColClient freeColClient) {
super(freeColClient, null, null);
setFocusable(false);
setBorder(BorderFactory.createEmptyBorder());
}
@Override
public PopupPosition getFramePopupPosition() {
return PopupPosition.UPPER_LEFT;
}
@Override
public String getFrameTitle() {
return Messages.message("minimapPanel.title");
}
}

View File

@ -19,6 +19,7 @@
package net.sf.freecol.client.gui.panel;
import java.awt.Dimension;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Logger;
@ -90,6 +91,8 @@ public final class UnitButton extends FreeColButton {
if (bi != null) {
setSize(bi.getIconWidth(), bi.getIconHeight());
setPreferredSize(new Dimension(bi.getIconWidth(), bi.getIconHeight()));
setMinimumSize(new Dimension(bi.getIconWidth(), bi.getIconHeight()));
} else {
logger.warning("Action " + a + " has no BUTTON_IMAGE");
}
@ -127,7 +130,9 @@ public final class UnitButton extends FreeColButton {
final ImageIcon bi = (ImageIcon) e.getNewValue();
button.setIcon(bi);
if (bi != null) {
button.setSize(bi.getIconWidth(), bi.getIconHeight());
button.setSize(new Dimension(bi.getIconWidth(), bi.getIconHeight()));
button.setMinimumSize(new Dimension(bi.getIconWidth(), bi.getIconHeight()));
button.setPreferredSize(new Dimension(bi.getIconWidth(), bi.getIconHeight()));
}
button.repaint();
} else if (FreeColAction.BUTTON_ROLLOVER_IMAGE.equals(e.getPropertyName())) {

View File

@ -31,6 +31,7 @@ import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.metal.DefaultMetalTheme;
import javax.swing.plaf.metal.MetalIconFactory;
import javax.swing.plaf.metal.MetalLookAndFeel;
import net.sf.freecol.client.gui.ImageLibrary;
@ -223,7 +224,7 @@ public class FreeColLookAndFeel extends MetalLookAndFeel {
// TODO: We might want to allow overriding font colors for the menu:
//u.put("Menu.foreground", java.awt.Color.WHITE);
return u;
}
@ -265,6 +266,12 @@ public class FreeColLookAndFeel extends MetalLookAndFeel {
final UIDefaults u = UIManager.getLookAndFeelDefaults();
final int scrollbarWidth = (int) (17 * scaleFactor);
u.put("ScrollBar.width", scrollbarWidth);
int internalFrameIconSize = (int) (16 * scaleFactor);
u.put("InternalFrame.closeIcon", (LazyValue) t -> MetalIconFactory.getInternalFrameCloseIcon(internalFrameIconSize));
u.put("InternalFrame.maximizeIcon", (LazyValue) t -> MetalIconFactory. getInternalFrameMaximizeIcon(internalFrameIconSize));
u.put("InternalFrame.iconifyIcon", (LazyValue) t -> MetalIconFactory.getInternalFrameMinimizeIcon(internalFrameIconSize));
u.put("InternalFrame.minimizeIcon", (LazyValue) t -> MetalIconFactory.getInternalFrameAltMaximizeIcon(internalFrameIconSize));
}
public static float getScaleFactor() {