From: Brett L. <wak...@us...> - 2012-01-07 19:05:33
|
LocalisedText.properties | 2 data/Properties.xml | 1 rails/ui/swing/GameStatus.java | 18 rails/ui/swing/MapPanel.java | 4 rails/ui/swing/ORPanel.java | 55 + rails/ui/swing/ORUIManager.java | 19 rails/ui/swing/StartRoundWindow.java | 10 rails/ui/swing/hexmap/GUIHex.java | 201 ++++-- rails/ui/swing/hexmap/HexHighlightMouseListener.java | 214 +++++++ rails/ui/swing/hexmap/HexMap.java | 561 ++++++++++++++----- rails/ui/swing/hexmap/HexMapImage.java | 48 - 11 files changed, 881 insertions(+), 252 deletions(-) New commits: commit a979db3b904deb6cec88268a5debf39674829c96 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 7 19:38:45 2012 +0100 Added handling of concurrent hex map paints The key blocks / methods are now synchronized on the hex map (acting as the monitor). This became necessary after observing very rare paintComponent calls with invalid clip rectangles (out of JComponent bounds), leading to out-of-bounds paints of the background map. After this addition, no further occurrence of this symptom could be observed. diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index 1cce585..e1be54b 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -62,7 +62,7 @@ public class MapPanel extends JPanel { if (mmgr.isMapImageUsed()) { mapImage = new HexMapImage (); - mapImage.init(mmgr); + mapImage.init(mmgr,map); mapImage.setPreferredSize(originalMapSize); mapImage.setBounds(0, 0, originalMapSize.width, originalMapSize.height); layeredPane.add(mapImage, -1); diff --git a/rails/ui/swing/hexmap/HexHighlightMouseListener.java b/rails/ui/swing/hexmap/HexHighlightMouseListener.java index 2627357..7cc2a96 100644 --- a/rails/ui/swing/hexmap/HexHighlightMouseListener.java +++ b/rails/ui/swing/hexmap/HexHighlightMouseListener.java @@ -13,7 +13,6 @@ import rails.game.Portfolio; import rails.game.PrivateCompanyI; import rails.game.PublicCompanyI; import rails.game.StartItem; -import rails.game.TokenI; import rails.game.special.LocatedBonus; import rails.game.special.SellBonusToken; import rails.game.special.SpecialPropertyI; diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index f5cbdb8..0dc3c1a 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -23,7 +23,10 @@ import rails.util.Util; * Base class that stores common info for HexMap independant of Hex * orientations. * The hex map manages several layers. Content is seperated in layers in order to ensure - * good performance in case of only some aspects of the map need to be redrawn. + * good performance in case of only some aspects of the map need to be redrawn. + * + * In order to avert race conditions during layer drawing, the critical code is + * synchronized on the hex map instance as monitor object. */ public abstract class HexMap implements MouseListener, MouseMotionListener { @@ -44,51 +47,53 @@ public abstract class HexMap implements MouseListener, final public void paintComponent(Graphics g) { super.paintComponents(g); - // Abort if called too early. - Rectangle rectClip = g.getClipBounds(); - if (rectClip == null) { - return; - } - - //ensure that image buffer of this layer is valid - if (bufferedImage == null - || bufferedImage.getWidth() != getWidth() - || bufferedImage.getHeight() != getHeight() ) { - //create new buffer image - bufferedImage = new BufferedImage(getWidth(), getHeight(),BufferedImage.TYPE_INT_ARGB); - isBufferDirty = true; - - //since the buffered image is empty, it has to be completely redrawn - rectClip = new Rectangle (0, 0, getWidth(), getHeight()); - } - - if (isBufferDirty) { - //buffer redraw is necessary - Graphics2D imageGraphics = (Graphics2D)bufferedImage.getGraphics(); - - //apply the clip of the component's repaint to its image buffer - imageGraphics.setClip(rectClip.x, rectClip.y, rectClip.width, rectClip.height); - - //set the background to transparent so that only drawn parts of the - //buffer will be taken over - imageGraphics.setBackground(new Color(0,0,0,0)); - imageGraphics.setColor(Color.BLACK); - - //clear the clip (for a non-virtual graphic, this would have been - //done by super.paintComponent) - imageGraphics.clearRect(rectClip.x, rectClip.y, rectClip.width, rectClip.height); + //avoid that paintComponent is processed concurrently + synchronized (HexLayer.this) { + + // Abort if called too early or if bounds are invalid. + Rectangle rectClip = g.getClipBounds(); + if (rectClip == null) return; - //paint within the buffer - paintImage(imageGraphics); + //ensure that image buffer of this layer is valid + if (bufferedImage == null + || bufferedImage.getWidth() != getWidth() + || bufferedImage.getHeight() != getHeight() ) { + //create new buffer image + bufferedImage = new BufferedImage(getWidth(), getHeight(),BufferedImage.TYPE_INT_ARGB); + isBufferDirty = true; + + //since the buffered image is empty, it has to be completely redrawn + rectClip = new Rectangle (0, 0, getWidth(), getHeight()); + } - imageGraphics.dispose(); - isBufferDirty = false; + if (isBufferDirty) { + //buffer redraw is necessary + Graphics2D imageGraphics = (Graphics2D)bufferedImage.getGraphics(); + + //apply the clip of the component's repaint to its image buffer + imageGraphics.setClip(rectClip.x, rectClip.y, rectClip.width, rectClip.height); + + //set the background to transparent so that only drawn parts of the + //buffer will be taken over + imageGraphics.setBackground(new Color(0,0,0,0)); + imageGraphics.setColor(Color.BLACK); + + //clear the clip (for a non-virtual graphic, this would have been + //done by super.paintComponent) + imageGraphics.clearRect(rectClip.x, rectClip.y, rectClip.width, rectClip.height); + + //paint within the buffer + paintImage(imageGraphics); + + imageGraphics.dispose(); + isBufferDirty = false; + } + + //buffer is valid and can be used + BufferedImage bufferedRect = bufferedImage.getSubimage( + rectClip.x, rectClip.y, rectClip.width, rectClip.height); + g.drawImage(bufferedRect, rectClip.x, rectClip.y, null); } - - //buffer is valid and can be used - BufferedImage bufferedRect = bufferedImage.getSubimage( - rectClip.x, rectClip.y, rectClip.width, rectClip.height); - g.drawImage(bufferedRect, rectClip.x, rectClip.y, null); } } @@ -812,7 +817,7 @@ public abstract class HexMap implements MouseListener, * Mouse Listener methods (hexMap offers listener for all layers) */ - public void mouseClicked(MouseEvent arg0) { + public synchronized void mouseClicked(MouseEvent arg0) { Point point = arg0.getPoint(); GUIHex clickedHex = getHexContainingPoint(point); @@ -821,7 +826,7 @@ public abstract class HexMap implements MouseListener, public void mouseDragged(MouseEvent arg0) {} - public void mouseMoved(MouseEvent arg0) { + public synchronized void mouseMoved(MouseEvent arg0) { Point point = arg0.getPoint(); GUIHex newHex = getHexContainingPoint(point); @@ -840,7 +845,13 @@ public abstract class HexMap implements MouseListener, public void mouseEntered(MouseEvent arg0) {} - public void mouseExited(MouseEvent arg0) {} + public synchronized void mouseExited(MouseEvent arg0) { + //provide for hex highlighting + if (hexAtMousePosition != null) { + hexAtMousePosition.removeHighlightRequest(); + hexAtMousePosition = null; + } + } public void mousePressed(MouseEvent arg0) {} @@ -852,26 +863,26 @@ public abstract class HexMap implements MouseListener, * - only apply for a specified area */ - public void repaintTiles (Rectangle r) { + public synchronized void repaintTiles (Rectangle r) { tilesLayer.repaint(r); } - private void repaintRoutes (Rectangle r) { + private synchronized void repaintRoutes (Rectangle r) { routesLayer.repaint(r); } - public void repaintMarks (Rectangle r) { + public synchronized void repaintMarks (Rectangle r) { marksLayer.repaint(r); } - public void repaintTokens (Rectangle r) { + public synchronized void repaintTokens (Rectangle r) { tokensTextsLayer.repaint(r); } /** * Do only call this method if you are sure that a complete repaint is needed! */ - public void repaintAll (Rectangle r) { + public synchronized void repaintAll (Rectangle r) { for (JComponent l : layers ) { l.repaint(r); } diff --git a/rails/ui/swing/hexmap/HexMapImage.java b/rails/ui/swing/hexmap/HexMapImage.java index 5ad44af..06a7af5 100644 --- a/rails/ui/swing/hexmap/HexMapImage.java +++ b/rails/ui/swing/hexmap/HexMapImage.java @@ -30,14 +30,15 @@ public final class HexMapImage extends JSVGCanvas { Logger.getLogger(HexMapImage.class.getPackage().getName()); private MapManager mapManager; - private AffineTransform initialTransform; + private HexMap hexMap; private double zoomFactor = 1; // defined dynamically if zoomStep changed private int zoomStep = 10; // default value, can be overwritten in config private boolean initialized = false; - public void init(MapManager mapManager) { + public void init(MapManager mapManager,HexMap hexMap) { this.mapManager = mapManager; + this.hexMap = hexMap; this.setRecenterOnResize(false); @@ -127,38 +128,17 @@ public final class HexMapImage extends JSVGCanvas { public int getZoomStep () { return zoomStep; } - - public void mouseClicked(MouseEvent arg0) { - Point point = arg0.getPoint(); - //GUIHex clickedHex = getHexContainingPoint(point); - - //orUIManager.hexClicked(clickedHex, selectedHex); - } - - /* - * (non-Javadoc) - * - * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) - */ - public void mouseDragged(MouseEvent arg0) {} - - /* - * (non-Javadoc) - * - * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) + + /** + * paint component synchronized with hex map in order to ensure that + * - painting background image is not affected by concurrent changes in the hexmap + * (such glitches were observed in the past) */ - public void mouseMoved(MouseEvent arg0) { - Point point = arg0.getPoint(); - //GUIHex hex = getHexContainingPoint(point); - //setToolTipText(hex != null ? hex.getToolTip() : ""); + @Override + public void paintComponent(Graphics g) { + synchronized (hexMap) { + super.paintComponent(g); + } } - - public void mouseEntered(MouseEvent arg0) {} - - public void mouseExited(MouseEvent arg0) {} - - public void mousePressed(MouseEvent arg0) {} - - public void mouseReleased(MouseEvent arg0) {} - + } commit 8655633be785451a5f2cf5da68fd99fe183c1ce5 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 7 14:40:26 2012 +0100 Added dirty region handling for hexmap's routes layer Changes to the train routes do not lead to a redraw of the complete layered pane any more. This has been achieved by adding logic for determining the region affected by train route changes. Apart from further performance gains, this also fixes prior issue that routes were not correctly refreshed. diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index 50cb6aa..f5cbdb8 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -33,7 +33,7 @@ public abstract class HexMap implements MouseListener, private BufferedImage bufferedImage; private boolean isBufferDirty = false; protected abstract void paintImage(Graphics g); - public void repaint() { + final public void repaint() { isBufferDirty = true; super.repaint(); } @@ -131,6 +131,35 @@ public abstract class HexMap implements MouseListener, */ private class RoutesLayer extends HexLayer { private static final long serialVersionUID = 1L; + + public Rectangle getRoutesBounds(List<GeneralPath> p1,List<GeneralPath> p2) { + int margin = (int)Math.ceil(strokeWidth * zoomFactor); + + List<Rectangle> pathRects = new ArrayList<Rectangle>(); + if (p1 != null) { + for (GeneralPath p : p1 ) pathRects.add(p.getBounds()); + } + if (p2 != null) { + for (GeneralPath p : p2 ) pathRects.add(p.getBounds()); + } + + Rectangle r = null; + for (Rectangle pathRect : pathRects ) { + //enlarge path rectangle with margin + Rectangle pathMarginRect = new Rectangle( + pathRect.x - margin, + pathRect.y - margin, + pathRect.width + margin * 2, + pathRect.y + margin * 2); + if (r == null) { + r = pathMarginRect; + } else { + r.add(pathMarginRect); + } + } + return r; + }; + @Override public void paintImage(Graphics g) { try { @@ -740,8 +769,11 @@ public abstract class HexMap implements MouseListener, } public void setTrainPaths(List<GeneralPath> trainPaths) { + Rectangle dirtyRect = routesLayer.getRoutesBounds(this.trainPaths, trainPaths); this.trainPaths = trainPaths; - repaintRoutes(); + + //only repaint if routes existed before or exist now + if (dirtyRect != null) repaintRoutes(dirtyRect); } /** @@ -824,8 +856,8 @@ public abstract class HexMap implements MouseListener, tilesLayer.repaint(r); } - public void repaintRoutes () { - routesLayer.repaint(); + private void repaintRoutes (Rectangle r) { + routesLayer.repaint(r); } public void repaintMarks (Rectangle r) { commit 0b92c862c534981fa3b6d31f2b926ab8cd7a9e22 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 7 13:16:53 2012 +0100 Added hex highlighting on mouse position and fixed tooltips Added a new layer on top-most z-order for tool tips. By this means, tool tips are available again (they were not displayed any more after having introduced layered off-screen buffers). Provided for highlighting of the hex under the mouse pointer. diff --git a/rails/ui/swing/GameStatus.java b/rails/ui/swing/GameStatus.java index 3e3e033..bab6fb0 100644 --- a/rails/ui/swing/GameStatus.java +++ b/rails/ui/swing/GameStatus.java @@ -330,8 +330,9 @@ public class GameStatus extends GridPanel implements ActionListener { f.setForeground(c.getFgColour()); f.setBackground(c.getBgColour()); HexHighlightMouseListener.addMouseListener(f, - gameUIManager.getORUIManager(),(PublicCompanyI)c,false); + gameUIManager.getORUIManager(),c,false); f.addMouseListener(companyCaptionMouseClickListener); + f.setToolTipText(LocalText.getText("NetworkInfoDialogTitle",c.getName())); addField(f, 0, certPerPlayerYOffset + i, 1, 1, WIDE_RIGHT, visible); for (int j = 0; j < np; j++) { @@ -454,8 +455,9 @@ public class GameStatus extends GridPanel implements ActionListener { f.setForeground(c.getFgColour()); f.setBackground(c.getBgColour()); HexHighlightMouseListener.addMouseListener(f, - gameUIManager.getORUIManager(),(PublicCompanyI)c,false); + gameUIManager.getORUIManager(),c,false); f.addMouseListener(companyCaptionMouseClickListener); + f.setToolTipText(LocalText.getText("NetworkInfoDialogTitle",c.getName())); addField(f, rightCompCaptionXOffset, certPerPlayerYOffset + i, 1, 1, WIDE_LEFT, visible); } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index ba24299..03bbc19 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -458,6 +458,7 @@ implements ActionListener, KeyListener, RevenueListener { HexHighlightMouseListener.addMouseListener(f, orUIManager,(PublicCompanyI)c,false); f.addMouseListener(companyCaptionMouseClickListener); + f.setToolTipText(LocalText.getText("NetworkInfoDialogTitle",c.getName())); addField(f, leftCompNameXOffset, leftCompNameYOffset + i, 1, 1, WIDE_RIGHT, visible); @@ -550,6 +551,7 @@ implements ActionListener, KeyListener, RevenueListener { HexHighlightMouseListener.addMouseListener(f, orUIManager,(PublicCompanyI)c,false); f.addMouseListener(companyCaptionMouseClickListener); + f.setToolTipText(LocalText.getText("NetworkInfoDialogTitle",c.getName())); addField(f, rightCompNameXOffset, rightCompNameYOffset + i, 1, 1, 0, visible); } diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index 6750115..50cb6aa 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -266,11 +266,19 @@ public abstract class HexMap implements MouseListener, } } + /** + * The only "real" (=swing managed) layer that is used for tool tips + */ + private class ToolTipsLayer extends JComponent { + private static final long serialVersionUID = 1L; + } + private TilesLayer tilesLayer; private RoutesLayer routesLayer; private MarksLayer marksLayer; - private TokensTextsLayer tokensTextsLayer; - private List<HexLayer> hexLayers; + private TokensTextsLayer tokensTextsLayer; + private ToolTipsLayer toolTipsLayer; + private List<JComponent> layers; protected static Logger log = Logger.getLogger(HexMap.class.getPackage().getName()); @@ -297,6 +305,11 @@ public abstract class HexMap implements MouseListener, protected int minX, minY, maxX, maxY; protected int minCol, maxCol, minRow, maxRow; + /** + * The hex over which the mouse pointer is currently situated + */ + private GUIHex hexAtMousePosition = null; + /** A list of all allowed tile lays */ /* (may be redundant) */ protected List<LayTile> allowedTileLays = null; @@ -369,15 +382,17 @@ public abstract class HexMap implements MouseListener, //the following order of instantiation and list-adding defines the layering //from the top to the bottom - hexLayers = new ArrayList<HexLayer>(); + layers = new ArrayList<JComponent>(); + toolTipsLayer = new ToolTipsLayer(); + layers.add(toolTipsLayer); tokensTextsLayer = new TokensTextsLayer(); - hexLayers.add(tokensTextsLayer); + layers.add(tokensTextsLayer); marksLayer = new MarksLayer(); - hexLayers.add(marksLayer); + layers.add(marksLayer); routesLayer = new RoutesLayer(); - hexLayers.add(routesLayer); + layers.add(routesLayer); tilesLayer = new TilesLayer(); - hexLayers.add(tilesLayer); + layers.add(tilesLayer); setScale(); setupHexes(); @@ -412,7 +427,7 @@ public abstract class HexMap implements MouseListener, public void addLayers (JLayeredPane p, int startingZOffset) { int z = startingZOffset; - for (HexLayer l : hexLayers ) { + for (JComponent l : layers ) { p.add(l, z++); } } @@ -776,8 +791,19 @@ public abstract class HexMap implements MouseListener, public void mouseMoved(MouseEvent arg0) { Point point = arg0.getPoint(); - GUIHex hex = getHexContainingPoint(point); - setToolTipText(hex != null ? hex.getToolTip() : ""); + GUIHex newHex = getHexContainingPoint(point); + + //ignore if mouse has not entered a new hex + if (hexAtMousePosition == newHex) return; + + //provide for hex highlighting + if (hexAtMousePosition != null) hexAtMousePosition.removeHighlightRequest(); + if (newHex != null) newHex.addHighlightRequest(); + + //display tool tip + setToolTipText(newHex != null ? newHex.getToolTip() : ""); + + hexAtMousePosition = newHex; } public void mouseEntered(MouseEvent arg0) {} @@ -814,7 +840,7 @@ public abstract class HexMap implements MouseListener, * Do only call this method if you are sure that a complete repaint is needed! */ public void repaintAll (Rectangle r) { - for (HexLayer l : hexLayers ) { + for (JComponent l : layers ) { l.repaint(r); } } @@ -824,35 +850,34 @@ public abstract class HexMap implements MouseListener, */ public void setBounds (int x, int y, int width, int height) { - for (HexLayer l : hexLayers) { + for (JComponent l : layers) { l.setBounds(x, y, width, height); } } private void setPreferredSize (Dimension size) { - for (HexLayer l : hexLayers) { + for (JComponent l : layers) { l.setPreferredSize(size); } } private void setToolTipText (String text) { - //set tool tip on top-most layer (so that it is always visible) - hexLayers.get(hexLayers.size()-1).setToolTipText(text); + toolTipsLayer.setToolTipText(text); } public Dimension getSize () { //get size from top-most layer (all layers have the same size anyways) - return hexLayers.get(hexLayers.size()-1).getSize(); + return layers.get(layers.size()-1).getSize(); } private void addMouseListener (MouseListener ml) { - for (HexLayer l : hexLayers) { + for (JComponent l : layers) { l.addMouseListener(ml); } } private void addMouseMotionListener (MouseMotionListener ml) { - for (HexLayer l : hexLayers) { + for (JComponent l : layers) { l.addMouseMotionListener(ml); } } commit 4948533d6fe55dd990e9ee3a6ca940f8cc6940f0 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 7 12:41:32 2012 +0100 Enabled company network info upon click on company captions If the caption of a company (both in ORPanel and StatusWindow) is clicked, its network info is displayed as if the corresponding network info menu item had been clicked. diff --git a/rails/ui/swing/GameStatus.java b/rails/ui/swing/GameStatus.java index e5b7c11..3e3e033 100644 --- a/rails/ui/swing/GameStatus.java +++ b/rails/ui/swing/GameStatus.java @@ -3,6 +3,7 @@ package rails.ui.swing; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseListener; import java.util.*; import java.util.List; @@ -188,6 +189,8 @@ public class GameStatus extends GridPanel implements ActionListener { upperPlayerCaption = new Caption[np]; lowerPlayerCaption = new Caption[np]; + MouseListener companyCaptionMouseClickListener = gameUIManager.getORUIManager().getORPanel().getCompanyCaptionMouseClickListener(); + int lastX = 0; int lastY = 1; certPerPlayerXOffset = ++lastX; @@ -328,6 +331,7 @@ public class GameStatus extends GridPanel implements ActionListener { f.setBackground(c.getBgColour()); HexHighlightMouseListener.addMouseListener(f, gameUIManager.getORUIManager(),(PublicCompanyI)c,false); + f.addMouseListener(companyCaptionMouseClickListener); addField(f, 0, certPerPlayerYOffset + i, 1, 1, WIDE_RIGHT, visible); for (int j = 0; j < np; j++) { @@ -451,6 +455,7 @@ public class GameStatus extends GridPanel implements ActionListener { f.setBackground(c.getBgColour()); HexHighlightMouseListener.addMouseListener(f, gameUIManager.getORUIManager(),(PublicCompanyI)c,false); + f.addMouseListener(companyCaptionMouseClickListener); addField(f, rightCompCaptionXOffset, certPerPlayerYOffset + i, 1, 1, WIDE_LEFT, visible); } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 4d20a9e..ba24299 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -61,7 +61,7 @@ implements ActionListener, KeyListener, RevenueListener { private JMenuItem zoomIn, zoomOut, fitToWindow, fitToWidth, fitToHeight, calibrateMap; private ActionMenuItem takeLoans; private ActionMenuItem repayLoans; - + // Grid elements per function private Caption leftCompName[]; private int leftCompNameXOffset, leftCompNameYOffset; @@ -310,6 +310,21 @@ implements ActionListener, KeyListener, RevenueListener { buttonPanel.setOpaque(true); } + public MouseListener getCompanyCaptionMouseClickListener() { + return new MouseListener() { + public void mouseClicked(MouseEvent e) { + if (e.getComponent() instanceof Caption) { + Caption c = (Caption)e.getComponent(); + executeNetworkInfo(c.getText()); + } + } + public void mouseExited(MouseEvent e) {} + public void mouseEntered(MouseEvent e) {} + public void mousePressed(MouseEvent e) {} + public void mouseReleased(MouseEvent e) {} + }; + } + private void initFields() { leftCompName = new Caption[nc]; rightCompName = new Caption[nc]; @@ -336,6 +351,8 @@ implements ActionListener, KeyListener, RevenueListener { leftCompNameYOffset = 2; int currentXOffset = leftCompNameXOffset; int lastXWidth = 0; + + MouseListener companyCaptionMouseClickListener = getCompanyCaptionMouseClickListener(); /* Top titles */ addField(new Caption("Company"), 0, 0, lastXWidth = 1, 2, @@ -440,6 +457,7 @@ implements ActionListener, KeyListener, RevenueListener { f.setForeground(c.getFgColour()); HexHighlightMouseListener.addMouseListener(f, orUIManager,(PublicCompanyI)c,false); + f.addMouseListener(companyCaptionMouseClickListener); addField(f, leftCompNameXOffset, leftCompNameYOffset + i, 1, 1, WIDE_RIGHT, visible); @@ -531,6 +549,7 @@ implements ActionListener, KeyListener, RevenueListener { f.setForeground(companies[i].getFgColour()); HexHighlightMouseListener.addMouseListener(f, orUIManager,(PublicCompanyI)c,false); + f.addMouseListener(companyCaptionMouseClickListener); addField(f, rightCompNameXOffset, rightCompNameYOffset + i, 1, 1, 0, visible); } @@ -683,6 +702,9 @@ implements ActionListener, KeyListener, RevenueListener { } else { CompanyManagerI cm = gm.getCompanyManager(); PublicCompanyI company = cm.getPublicCompany(companyName); + //handle the case of invalid parameters + //could occur if the method is not invoked by the menu (but by the click listener) + if (company == null) return; // // NetworkGraphBuilder nwGraph = NetworkGraphBuilder.create(gm); // NetworkCompanyGraph companyGraph = NetworkCompanyGraph.create(nwGraph, company); diff --git a/rails/ui/swing/ORUIManager.java b/rails/ui/swing/ORUIManager.java index 0ad825f..40da760 100644 --- a/rails/ui/swing/ORUIManager.java +++ b/rails/ui/swing/ORUIManager.java @@ -1950,6 +1950,11 @@ public class ORUIManager implements DialogOwner { return map; } + // TEMPORARY + public ORPanel getORPanel() { + return orPanel; + } + public GameUIManager getGameUIManager () { return gameUIManager; } commit f93b4e135a57554d10cafb17f27db0d0c90e0ea0 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 7 12:11:10 2012 +0100 Added config option for highlighting and public company highlighting Introduced highlighting for public/minor companies, displaying their home/destination hexes. Added config option for highlighting within the map tab. It applies to all triggers (ORPanel and StatusWindow) except for the menu items (for which highlighting will always take place). Fixed an issue with highlighting privates of portfolios. Now, portfolios are evaluated not during registration but during the mouse over event. diff --git a/LocalisedText.properties b/LocalisedText.properties index 8a1f4f7..b3875f2 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -171,6 +171,7 @@ ComponentManagerNotYetConfigured=ComponentManager has not yet been configured. Config.infoText.locale=<html>te_ST shows local text keys. <br> Requires restart.</html> Config.infoText.default_players=Enter player names separated by commas. Config.infoText.map.displayCurrentRoutes=If enabled, optimal train routes are displayed for the company which is currently taking its turn. +Config.infoText.map.highlightHexes=<html>If enabled, parts of the map are highlighted depending on the position of the mouse pointer:<ul><li><b>Private companies:</b> Point to the name of a private company in order to highlight the locations associated with it (e.g., its reserved hex).<ul><li>If you point to a set of private companies (in the player or company holding), the locations of all contained private companies are highlighted</ul><li><b>Minor & Public Companies:</b> Point to the name of the company in order to highlight the locations associated with it (home and destination).</ul></html> Config.infoText.sound.backgroundMusic.stockRound=<html>Enter assignment of music files (mp3) to phases.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax phaseName=complete file path<li>Default music is defined by omitting "phaseName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default music: <br><code>c:\SR-default.mp3</code><li>Set phase-dependent music and a default (for trains above 6): <br><code>2=c:\SR-2.mp3,3=c:\SR-3.mp3,4=c:\SR-4.mp3,5=c:\SR-5.mp3,6=c:\SR-6.mp3,c:\SR-D.mp3</code></ul> </html> Config.infoText.sound.backgroundMusic.operatingRound=<html>Enter assignment of music files (mp3) to phases.<ul><li>Separate the assignments by commas.<li>Each assignment has the syntax phaseName=complete file path<li>Default music is defined by omitting "phaseName=" in the assignment.</ul><strong>Examples:</strong><ul><li>Set default music: <br><code>c:\OR-default.mp3</code><li>Set phase-dependent music and a default (for trains above 6): <br><code>2=c:\OR-2.mp3,3=c:\OR-3.mp3,4=c:\OR-4.mp3,5=c:\OR-5.mp3,6=c:\OR-6.mp3,c:\OR-D.mp3</code></ul> </html> Config.label.default_game=Default game @@ -183,6 +184,7 @@ Config.label.locale=Language setting Config.label.map.autoscroll=Map autoscroll Config.label.map.displayCurrentRoutes=Display routes of active company Config.label.map.image.display=Display background map +Config.label.map.highlightHexes=Highlight company locations Config.label.map.zoomstep=Map zoomstep Config.label.money_format=Money format Config.label.or.number_format=OR number format diff --git a/data/Properties.xml b/data/Properties.xml index 29e377f..13cb9ff 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -32,6 +32,7 @@ <Property name="map.zoomstep" type="INTEGER" /> <Property name="map.image.display" type="BOOLEAN" /> <Property name="map.displayCurrentRoutes" type="BOOLEAN" /> + <Property name="map.highlightHexes" type="BOOLEAN" /> </Section> <Section name="Windows"> <Property name="report.window.type" type="LIST" values="static,dynamic" /> diff --git a/rails/ui/swing/GameStatus.java b/rails/ui/swing/GameStatus.java index 26a12aa..e5b7c11 100644 --- a/rails/ui/swing/GameStatus.java +++ b/rails/ui/swing/GameStatus.java @@ -326,6 +326,8 @@ public class GameStatus extends GridPanel implements ActionListener { f = new Caption(c.getName()); f.setForeground(c.getFgColour()); f.setBackground(c.getBgColour()); + HexHighlightMouseListener.addMouseListener(f, + gameUIManager.getORUIManager(),(PublicCompanyI)c,false); addField(f, 0, certPerPlayerYOffset + i, 1, 1, WIDE_RIGHT, visible); for (int j = 0; j < np; j++) { @@ -423,9 +425,9 @@ public class GameStatus extends GridPanel implements ActionListener { compPrivates[i] = new Field( c.getPortfolio().getPrivatesOwnedModel()); - f.addMouseListener(new HexHighlightMouseListener( - gameUIManager.getORUIManager(),null, - c.getPortfolio().getPrivateCompanies())); + HexHighlightMouseListener.addMouseListener(f, + gameUIManager.getORUIManager(), + c.getPortfolio()); addField(f, compPrivatesXOffset, compPrivatesYOffset + i, 1, 1, 0, visible); } @@ -447,6 +449,8 @@ public class GameStatus extends GridPanel implements ActionListener { f = new Caption(c.getName()); f.setForeground(c.getFgColour()); f.setBackground(c.getBgColour()); + HexHighlightMouseListener.addMouseListener(f, + gameUIManager.getORUIManager(),(PublicCompanyI)c,false); addField(f, rightCompCaptionXOffset, certPerPlayerYOffset + i, 1, 1, WIDE_LEFT, visible); } @@ -476,9 +480,9 @@ public class GameStatus extends GridPanel implements ActionListener { playerPrivates[i] = new Field( players[i].getPortfolio().getPrivatesOwnedModel()); - f.addMouseListener(new HexHighlightMouseListener( - gameUIManager.getORUIManager(),null, - players[i].getPortfolio().getPrivateCompanies())); + HexHighlightMouseListener.addMouseListener(f, + gameUIManager.getORUIManager(), + players[i].getPortfolio()); addField(f, playerPrivatesXOffset + i, playerPrivatesYOffset, 1, 1, 0, true); } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index ed92b8f..4d20a9e 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -438,6 +438,8 @@ implements ActionListener, KeyListener, RevenueListener { f = leftCompName[i] = new Caption(c.getName()); f.setBackground(c.getBgColour()); f.setForeground(c.getFgColour()); + HexHighlightMouseListener.addMouseListener(f, + orUIManager,(PublicCompanyI)c,false); addField(f, leftCompNameXOffset, leftCompNameYOffset + i, 1, 1, WIDE_RIGHT, visible); @@ -459,8 +461,8 @@ implements ActionListener, KeyListener, RevenueListener { privates[i] = new Field( c.getPortfolio().getPrivatesOwnedModel()); - f.addMouseListener(new HexHighlightMouseListener( - orUIManager,null,c.getPortfolio().getPrivateCompanies())); + HexHighlightMouseListener.addMouseListener(f, + orUIManager,c.getPortfolio()); addField(f, privatesXOffset, privatesYOffset + i, 1, 1, WIDE_RIGHT, visible); @@ -527,6 +529,8 @@ implements ActionListener, KeyListener, RevenueListener { f = rightCompName[i] = new Caption(c.getName()); f.setBackground(companies[i].getBgColour()); f.setForeground(companies[i].getFgColour()); + HexHighlightMouseListener.addMouseListener(f, + orUIManager,(PublicCompanyI)c,false); addField(f, rightCompNameXOffset, rightCompNameYOffset + i, 1, 1, 0, visible); } @@ -553,11 +557,19 @@ implements ActionListener, KeyListener, RevenueListener { item.setEnabled(true); JMenuItem menuItem = new JMenuItem(comp.getInfoText()); if (comp instanceof PrivateCompanyI) { - HexHighlightMouseListener ml = new HexHighlightMouseListener( - orUIManager,(PrivateCompanyI)comp); - menuItem.addMouseListener(ml); - item.addMouseListener(ml); + //highlighting on menu items always enabled irrespective of config + HexHighlightMouseListener.addMouseListener(menuItem, + orUIManager,(PrivateCompanyI)comp,true); + HexHighlightMouseListener.addMouseListener(item, + orUIManager,(PrivateCompanyI)comp,true); } + if (comp instanceof PublicCompanyI) { + //highlighting on menu items always enabled irrespective of config + HexHighlightMouseListener.addMouseListener(menuItem, + orUIManager,(PublicCompanyI)comp,true); + HexHighlightMouseListener.addMouseListener(item, + orUIManager,(PublicCompanyI)comp,true); + } item.add(menuItem); menu.add(item); } diff --git a/rails/ui/swing/StartRoundWindow.java b/rails/ui/swing/StartRoundWindow.java index 25f3fd6..8417b03 100644 --- a/rails/ui/swing/StartRoundWindow.java +++ b/rails/ui/swing/StartRoundWindow.java @@ -288,17 +288,18 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { for (int i = 0; i < ni; i++) { si = items[i]; - HexHighlightMouseListener ml = new HexHighlightMouseListener( + f = itemName[i] = new Caption(si.getName()); + HexHighlightMouseListener.addMouseListener(f, gameUIManager.getORUIManager(), si); - f = itemName[i] = new Caption(si.getName()); - f.addMouseListener(ml); addField(f, itemNameXOffset, itemNameYOffset + i, 1, 1, WIDE_RIGHT); f = itemNameButton[i] = new ClickField(si.getName(), "", "", this, itemGroup); - f.addMouseListener(ml); + HexHighlightMouseListener.addMouseListener(f, + gameUIManager.getORUIManager(), + si); addField(f, itemNameXOffset, itemNameYOffset + i, 1, 1, WIDE_RIGHT); // Prevent row height resizing after every buy action itemName[i].setPreferredSize(itemNameButton[i].getPreferredSize()); @@ -321,7 +322,9 @@ implements ActionListener, KeyListener, ActionPerformer, DialogOwner { f = info[i] = new Field (infoIcon); f.setToolTipText(getStartItemDescription(si)); - f.addMouseListener(ml); + HexHighlightMouseListener.addMouseListener(f, + gameUIManager.getORUIManager(), + si); addField (f, infoXOffset, infoYOffset + i, 1, 1, WIDE_LEFT); // Invisible field, only used to hold current item status. diff --git a/rails/ui/swing/hexmap/HexHighlightMouseListener.java b/rails/ui/swing/hexmap/HexHighlightMouseListener.java index 891362b..2627357 100644 --- a/rails/ui/swing/hexmap/HexHighlightMouseListener.java +++ b/rails/ui/swing/hexmap/HexHighlightMouseListener.java @@ -5,9 +5,15 @@ import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.List; +import javax.swing.JComponent; + +import rails.common.parser.Config; import rails.game.MapHex; +import rails.game.Portfolio; import rails.game.PrivateCompanyI; +import rails.game.PublicCompanyI; import rails.game.StartItem; +import rails.game.TokenI; import rails.game.special.LocatedBonus; import rails.game.special.SellBonusToken; import rails.game.special.SpecialPropertyI; @@ -27,97 +33,159 @@ public class HexHighlightMouseListener implements MouseListener { List<GUIHex> guiHexList; HexMap hexMap; ORUIManager orUIManager; + Portfolio portfolio; /** - * lazy creation of the gui hex list for two reasons: + * lazy creation of the gui hex list for these reasons: * - save effort in case the mouse over never happens * - hexmap is now more likely to be available than during construction + * - portfolio is to be evaluated only at mouse over time */ private void initGuiHexList() { - if (hexMap == null) { - hexMap = orUIManager.getMap(); - if (hexMap != null) { - for (MapHex h : hexList) { - guiHexList.add(hexMap.getHexByName(h.getName())); - } + //only create list if gui hexes are not yet available + if (!guiHexList.isEmpty()) return; + + //initially get hex map if not yet available + if (hexMap == null) hexMap = orUIManager.getMap(); + + //create gui hex list based on hex list + if (hexMap != null) { + for (MapHex h : hexList) { + guiHexList.add(hexMap.getHexByName(h.getName())); } } } - + /** * inefficient but probably ok due to very small size of lists */ - private void addToHexListOmittingDuplicates(List<MapHex> hl) { + private void addToHexListDistinct(List<MapHex> hl) { if (hl == null) return; for (MapHex h : hl) { - if (!hexList.contains(h)) { - hexList.add(h); - } + addToHexListDistinct(h); } } + private void addToHexListDistinct(MapHex h) { + if (h == null) return; + if (!hexList.contains(h)) hexList.add(h); + } private void initPrivateCompanies(List<PrivateCompanyI> privList) { for (PrivateCompanyI p : privList) { - addToHexListOmittingDuplicates(p.getBlockedHexes()); + addToHexListDistinct(p.getBlockedHexes()); for (SpecialPropertyI sp : p.getSpecialProperties()) { if (sp instanceof SpecialTileLay) { - addToHexListOmittingDuplicates(((SpecialTileLay)sp).getLocations()); + addToHexListDistinct(((SpecialTileLay)sp).getLocations()); } if (sp instanceof SpecialTokenLay) { - addToHexListOmittingDuplicates(((SpecialTokenLay)sp).getLocations()); + addToHexListDistinct(((SpecialTokenLay)sp).getLocations()); } if (sp instanceof SpecialRight) { - addToHexListOmittingDuplicates(((SpecialRight)sp).getLocations()); + addToHexListDistinct(((SpecialRight)sp).getLocations()); } if (sp instanceof LocatedBonus) { - addToHexListOmittingDuplicates(((LocatedBonus)sp).getLocations()); + addToHexListDistinct(((LocatedBonus)sp).getLocations()); } if (sp instanceof SellBonusToken) { - addToHexListOmittingDuplicates(((SellBonusToken)sp).getLocations()); + addToHexListDistinct(((SellBonusToken)sp).getLocations()); } } } } + private void clearHexList () { + //remove hexes from the list + //(as list will be built from the scratch during next mouse entered event) + hexList.clear(); + guiHexList.clear(); + } + + private void initPortfolioHexList () { + //build the hex list for the contained private companies + initPrivateCompanies(portfolio.getPrivateCompanies()); + } + + /** + * @param orUIManager The OR UI manager containing the map where the highlighting + * should occur + */ private HexHighlightMouseListener(ORUIManager orUIManager){ this.orUIManager = orUIManager; hexList = new ArrayList<MapHex>(); guiHexList = new ArrayList<GUIHex>(); + portfolio = null; } /** - * @param orUIManager The OR UI manager containing the map where the highlighting - * should occur - * @param hexList A list of hexes that are to be highlighted (in case of events) - * @param privList A list of private companies the hexes associated to which are - * to be highlighted (in case of events) + * @param pf Portfolio which is dynamically evaluated at mouse-even-time for + * any contained private companies */ - public HexHighlightMouseListener(ORUIManager orUIManager,List<MapHex> hexList,List<PrivateCompanyI> privList) { - this(orUIManager); - addToHexListOmittingDuplicates(hexList); - initPrivateCompanies(privList); + public static void addMouseListener(JComponent c,ORUIManager orUIManager,Portfolio pf) { + if (isEnabled(false)) { + HexHighlightMouseListener l = new HexHighlightMouseListener(orUIManager); + l.portfolio = pf; + c.addMouseListener(l); + } } - public HexHighlightMouseListener(ORUIManager orUIManager,PrivateCompanyI p) { - this(orUIManager); - List<PrivateCompanyI> privList = new ArrayList<PrivateCompanyI>(); - privList.add(p); - initPrivateCompanies(privList); + /** + * @param p Private company the hexes associated to which are + * to be highlighted (in case of events) + * @param enableIrrespectiveOfHighlightConfig If true, the mouse listener is + * enabled irrespective of the base configuration. Needed since some highlighting + * should not be disabled by configuration. + */ + public static void addMouseListener(JComponent c,ORUIManager orUIManager,PrivateCompanyI p,boolean enableIrrespectiveOfHighlightConfig) { + if (isEnabled(enableIrrespectiveOfHighlightConfig)) { + HexHighlightMouseListener l = new HexHighlightMouseListener(orUIManager); + List<PrivateCompanyI> privList = new ArrayList<PrivateCompanyI>(); + privList.add(p); + l.initPrivateCompanies(privList); + c.addMouseListener(l); + } } - public HexHighlightMouseListener(ORUIManager orUIManager,StartItem si) { - this(orUIManager); - List<PrivateCompanyI> privList = new ArrayList<PrivateCompanyI>(); - if (si.getPrimary() instanceof PrivateCompanyI) { - privList.add((PrivateCompanyI)si.getPrimary()); + /** + * @param p Public company the hexes associated to it (home, destination, ...) are + * to be highlighted (in case of events) + * @param enableIrrespectiveOfHighlightConfig If true, the mouse listener is + * enabled irrespective of the base configuration. Needed since some highlighting + * should not be disabled by configuration. + */ + public static void addMouseListener(JComponent c,ORUIManager orUIManager,PublicCompanyI p,boolean enableIrrespectiveOfHighlightConfig) { + if (isEnabled(enableIrrespectiveOfHighlightConfig)) { + HexHighlightMouseListener l = new HexHighlightMouseListener(orUIManager); + l.addToHexListDistinct(p.getHomeHexes()); + l.addToHexListDistinct(p.getDestinationHex()); + c.addMouseListener(l); } - if (si.getSecondary() instanceof PrivateCompanyI) { - privList.add((PrivateCompanyI)si.getSecondary()); + } + + /** + * @param si Start Item which is evaluated for any contained private companies + */ + public static void addMouseListener(JComponent c,ORUIManager orUIManager,StartItem si) { + if (isEnabled(false)) { + HexHighlightMouseListener l = new HexHighlightMouseListener(orUIManager); + List<PrivateCompanyI> privList = new ArrayList<PrivateCompanyI>(); + if (si.getPrimary() instanceof PrivateCompanyI) { + privList.add((PrivateCompanyI)si.getPrimary()); + } + if (si.getSecondary() instanceof PrivateCompanyI) { + privList.add((PrivateCompanyI)si.getSecondary()); + } + l.initPrivateCompanies(privList); + c.addMouseListener(l); } - initPrivateCompanies(privList); + } + + private static boolean isEnabled (boolean enableIrrespectiveOfHighlightConfig) { + return (enableIrrespectiveOfHighlightConfig + || "yes".equals(Config.get("map.highlightHexes"))); } public void mouseEntered(MouseEvent e) { + if (portfolio != null) initPortfolioHexList(); initGuiHexList(); if (hexMap != null && guiHexList.size() > 0) { for (GUIHex guiHex : guiHexList) { @@ -127,12 +195,12 @@ public class HexHighlightMouseListener implements MouseListener { } public void mouseExited(MouseEvent e) { - initGuiHexList(); if (hexMap != null && guiHexList.size() > 0) { for (GUIHex guiHex : guiHexList) { guiHex.removeHighlightRequest(); } } + if (portfolio != null) clearHexList(); } public void mouseClicked(MouseEvent e) { commit 902e1a1bdf6ffd1ca095d31e794f2b12d3f4aadb Author: Frederick Weld <fre...@gm...> Date: Sat Jan 7 07:27:09 2012 +0100 Added off-screen image buffers for hexMap layers and invalidation logic Vastly improved performance of painting the hex map by the following. Defined layers according to the prior drawing order of hexmap's paintComponent (tiles, routes, markings, tokens and texts). HexMap manages these layers is no JComponent any more. Each layer: - is a JComponent and has its z order in MapPanel, - only draws its content if it has been changed, - only draws into its own permanent off-screen drawing buffer, - copies drawing buffer to MapPanel for making its contents visible. Supported this by introducing a new invalidation logic (eg., repaintTiles) that: - indicates to the affected layer which portions are to be re-drawn, - averts redraw of inaffected layers - is triggered by the hexmap or GUIHex whenever possible (no need for triggering by consumers ORPanel, ORUIManager, etc.) diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index 632203b..1cce585 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -58,7 +58,7 @@ public class MapPanel extends JPanel { layeredPane.setLayout(null); layeredPane.setPreferredSize(originalMapSize); map.setBounds(0, 0, originalMapSize.width, originalMapSize.height); - layeredPane.add(map, 0); + map.addLayers(layeredPane, 1); if (mmgr.isMapImageUsed()) { mapImage = new HexMapImage (); diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index f060320..ed92b8f 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -695,7 +695,6 @@ implements ActionListener, KeyListener, RevenueListener { log.debug("Revenue Value:" + revenueValue); log.debug("Revenue Run:" + ra.getOptimalRunPrettyPrint(true)); ra.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); if (!Game.getDevelop()) { //parent component is ORPanel so that dialog won't hide the routes painted on the map @@ -725,7 +724,6 @@ implements ActionListener, KeyListener, RevenueListener { orUIManager.getMap().setTrainPaths(null); //but retain paths already existing before if (revenueAdapter != null) revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); } } @@ -750,7 +748,6 @@ implements ActionListener, KeyListener, RevenueListener { private void redrawRoutes() { if (revenueAdapter != null && isDisplayRoutes()) { revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); } } @@ -892,7 +889,6 @@ implements ActionListener, KeyListener, RevenueListener { private void disableRoutesDisplay() { clearRevenueAdapter(); orUIManager.getMap().setTrainPaths(null); - orUIManager.getMap().repaint(); } private void clearRevenueAdapter() { @@ -993,7 +989,6 @@ implements ActionListener, KeyListener, RevenueListener { if (finalResult) { orUIManager.getMap().setTrainPaths(null); revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); if (isRevenueValueToBeSet) { orUIManager.addInformation("Best Run Value = " + bestRevenue + " with " + Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(false))); diff --git a/rails/ui/swing/ORUIManager.java b/rails/ui/swing/ORUIManager.java index 82b3a61..0ad825f 100644 --- a/rails/ui/swing/ORUIManager.java +++ b/rails/ui/swing/ORUIManager.java @@ -158,14 +158,12 @@ public class ORUIManager implements DialogOwner { if (selectedHex != null) { selectedHex.removeTile(); selectedHex.setSelected(false); - mapPanel.getMap().repaint(selectedHex.getBounds()); selectedHex = null; } // remove selectable indications for (MapHex hex:hexUpgrades) { GUIHex guiHex = map.getHexByName(hex.getName()); guiHex.setSelectable(false); - mapPanel.getMap().repaint(guiHex.getBounds()); } hexUpgrades = null; } @@ -175,14 +173,12 @@ public class ORUIManager implements DialogOwner { if (selectedHex != null) { selectedHex.removeToken(); selectedHex.setSelected(false); - mapPanel.getMap().repaint(selectedHex.getBounds()); selectedHex = null; } // remove selectable indications for (MapHex hex:hexUpgrades) { GUIHex guiHex = map.getHexByName(hex.getName()); guiHex.setSelectable(false); - mapPanel.getMap().repaint(guiHex.getBounds()); } hexUpgrades = null; } @@ -615,7 +611,6 @@ public class ORUIManager implements DialogOwner { case SELECT_ORIENTATION: if (clickedHex == selectedHex) { selectedHex.forcedRotateTile(); - map.repaint(selectedHex.getBounds()); } else checkClickedHex = true; break; @@ -643,7 +638,7 @@ public class ORUIManager implements DialogOwner { map.selectHex(clickedHex); setLocalStep(SELECT_TOKEN); } else { - JOptionPane.showMessageDialog(map, LocalText.getText( + JOptionPane.showMessageDialog(mapPanel, LocalText.getText( "NoTokenPossible", clickedHex.getName())); setLocalStep(ORUIManager.SELECT_HEX_FOR_TOKEN); } @@ -652,7 +647,6 @@ public class ORUIManager implements DialogOwner { if (localStep == ROTATE_OR_CONFIRM_TILE && clickedHex == selectedHex) { selectedHex.rotateTile(); - map.repaint(selectedHex.getBounds()); return; } else { @@ -674,7 +668,7 @@ public class ORUIManager implements DialogOwner { map.selectHex(clickedHex); setLocalStep(SELECT_TILE); } else { - JOptionPane.showMessageDialog(map, + JOptionPane.showMessageDialog(mapPanel, "This hex cannot be upgraded now"); } } @@ -693,7 +687,6 @@ public class ORUIManager implements DialogOwner { if (mapCorrectionEnabled) { // paint tile hex.forcedDropTile(tileId, 0); - map.repaint(hex.getBounds()); // inform map correction manager mapCorrectionAction.selectTile(tile); orWindow.process(mapCorrectionAction); @@ -710,11 +703,10 @@ public class ORUIManager implements DialogOwner { if (hex.dropTile(tileId, mustConnect)) { /* Lay tile */ - map.repaint(hex.getBounds()); setLocalStep(ORUIManager.ROTATE_OR_CONFIRM_TILE); } else { /* Tile cannot be laid in a valid orientation: refuse it */ - JOptionPane.showMessageDialog(map, + JOptionPane.showMessageDialog(mapPanel, "This tile cannot be laid in a valid orientation."); tileUpgrades.remove(tile); setLocalStep(ORUIManager.SELECT_TILE); diff --git a/rails/ui/swing/hexmap/GUIHex.java b/rails/ui/swing/hexmap/GUIHex.java index 0ae02c4..52165a7 100644 --- a/rails/ui/swing/hexmap/GUIHex.java +++ b/rails/ui/swing/hexmap/GUIHex.java @@ -41,12 +41,19 @@ public class GUIHex implements ViewObject { protected MapHex model; protected GeneralPath innerHexagonSelected; + protected float selectedStrokeWidth; protected GeneralPath innerHexagonSelectable; + protected float selectableStrokeWidth; protected static final Color selectedColor = Color.red; protected static final Color selectableColor = Color.red; protected static final Color highlightedFillColor = new Color(255,255,255,128); protected static final Color highlightedBorderColor = Color.BLACK; - protected static final Stroke highlightedBorderStroke = new BasicStroke(3); + protected static final Stroke highlightedBorderStroke = new BasicStroke(3); + /** + * Defines by how much the hex bounds have to be increased in each direction + * for obtaining the dirty rectangle (markings coul... [truncated message content] |