From: Frederick W. <fre...@us...> - 2012-01-21 15:16:55
|
LocalisedText.properties | 5 - data/Properties.xml | 3 rails/ui/swing/GameStatus.java | 87 ++++++++++------- rails/ui/swing/GridPanel.java | 202 +++++++++++++++++++++++++++++++++++++++-- rails/ui/swing/ORPanel.java | 18 +++ 5 files changed, 269 insertions(+), 46 deletions(-) New commits: commit 28785080ae640691e138d8aaceb9d1c726630b22 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 21 16:10:54 2012 +0100 Introduced new option to enable/disable table borders in grid panels By default, borders are disabled (but highlighting is always enabled). diff --git a/LocalisedText.properties b/LocalisedText.properties index 6deba63..ee42f0c 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -170,6 +170,7 @@ ComponentManagerNotReconfigured=Cannot reconfigure the ComponentManager. 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.gridPanel.tableBorders=Grid layouts are used for the Status Window and the panel of the Operating Round Window. 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> @@ -179,6 +180,7 @@ Config.label.default_players=Default players Config.label.font.ui.name=Font selection Config.label.font.ui.scale=Font scaling Config.label.font.ui.style=Font style +Config.label.gridPanel.tableBorders=Display borders in grid layouts Config.label.local.player.name=Local player (for pbem) Config.label.locale=Language setting Config.label.map.autoscroll=Map autoscroll @@ -210,7 +212,8 @@ Config.label.save.filename.extension=Filename extension Config.label.save.recovery.active=Automatic save Config.label.save.recovery.filepath=Automatic save filepath Config.toolTip.local.player.name=Player name used as suffix for game save -Config.section.Format=Format/Colors +Config.section.Appearance=Appearance +Config.section.Format=Format Config.section.General=General Config.section.Log=Log Config.section.Font=Fonts diff --git a/data/Properties.xml b/data/Properties.xml index 6f89262..015513b 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -44,6 +44,9 @@ <Section name="Format"> <Property name="money_format" type="STRING" /> <Property name="or.number_format" type="LIST" values="simple,composite" /> + </Section> + <Section name="Appearance"> + <Property name="gridPanel.tableBorders" type="LIST" values="disabled,enabled"/> <Property name="route.colour.1" type="COLOR" initClass="rails.ui.swing.hexmap.HexMap" initMethod="setRouteColours" /> <Property name="route.colour.2" type="COLOR" diff --git a/rails/ui/swing/GridPanel.java b/rails/ui/swing/GridPanel.java index 5cbd1da..4941867 100644 --- a/rails/ui/swing/GridPanel.java +++ b/rails/ui/swing/GridPanel.java @@ -13,6 +13,7 @@ import javax.swing.border.CompoundBorder; import org.apache.log4j.Logger; +import rails.common.parser.Config; import rails.game.*; import rails.game.model.ModelObject; import rails.game.state.BooleanState; @@ -62,12 +63,21 @@ implements ActionListener, KeyListener { Logger.getLogger(GridPanel.class.getPackage().getName()); private JComponent highlightedComp = null; - protected Color tableBorderColor = Color.DARK_GRAY; - protected Color cellOutlineColor = Color.GRAY; - protected Color highlightedBorderColor = Color.RED; + protected Color tableBorderColor; + protected Color cellOutlineColor; + protected Color highlightedBorderColor; public GridPanel() { - + //initialize border colors according to the configuration + if ("enabled".equals(Config.get("gridPanel.tableBorders"))) { + tableBorderColor = Color.DARK_GRAY; + cellOutlineColor = Color.GRAY; + highlightedBorderColor = Color.RED; + } else { + tableBorderColor = getBackground(); + cellOutlineColor = getBackground(); + highlightedBorderColor = Color.RED; + } } public void redisplay() { commit 82883c227ce803b4cf44a9c96c6c3739e363bc97 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 21 15:56:51 2012 +0100 Fixed game status table layout for more pretty display with borders A lot of existing wide/narrow-gap issues became apparent when using table borders. Issues are now fixed. diff --git a/rails/ui/swing/GameStatus.java b/rails/ui/swing/GameStatus.java index bb7dcb5..c2e51b3 100644 --- a/rails/ui/swing/GameStatus.java +++ b/rails/ui/swing/GameStatus.java @@ -259,18 +259,20 @@ public class GameStatus extends GridPanel implements ActionListener { rowVisibilityObservers = new RowVisibility[nc]; addField(new Caption(LocalText.getText("COMPANY")), 0, 0, 1, 2, - WIDE_RIGHT + WIDE_BOTTOM, true); + WIDE_BOTTOM, true); addField(new Caption(LocalText.getText("PLAYERS")), - certPerPlayerXOffset, 0, np, 1, 0, true); + certPerPlayerXOffset, 0, np, 1, WIDE_LEFT + WIDE_RIGHT, true); for (int i = 0; i < np; i++) { playerIndex.put(players[i], new Integer(i)); f = upperPlayerCaption[i] = new Caption(players[i].getNameAndPriority()); - addField(f, certPerPlayerXOffset + i, 1, 1, 1, WIDE_BOTTOM, true); + int wideGapPosition = WIDE_BOTTOM + + ((i==0)? WIDE_LEFT : 0) + ((i==np-1)? WIDE_RIGHT : 0); + addField(f, certPerPlayerXOffset + i, 1, 1, 1, wideGapPosition, true); } addField(new Caption(LocalText.getText("BANK_SHARES")), - certInIPOXOffset, 0, 2, 1, WIDE_LEFT + WIDE_RIGHT, true); + certInIPOXOffset, 0, 2, 1, WIDE_RIGHT, true); addField(new Caption(LocalText.getText("IPO")), certInIPOXOffset, 1, 1, - 1, WIDE_LEFT + WIDE_BOTTOM, true); + 1, WIDE_BOTTOM, true); addField(new Caption(LocalText.getText("POOL")), certInPoolXOffset, 1, 1, 1, WIDE_RIGHT + WIDE_BOTTOM, true); @@ -333,7 +335,7 @@ public class GameStatus extends GridPanel implements ActionListener { gameUIManager.getORUIManager(),c,false); f.addMouseListener(companyCaptionMouseClickListener); f.setToolTipText(LocalText.getText("NetworkInfoDialogTitle",c.getName())); - addField(f, 0, certPerPlayerYOffset + i, 1, 1, WIDE_RIGHT, visible); + addField(f, 0, certPerPlayerYOffset + i, 1, 1, 0, visible); for (int j = 0; j < np; j++) { f = @@ -341,18 +343,19 @@ public class GameStatus extends GridPanel implements ActionListener { new Field( players[j].getPortfolio().getShareModel( c)); + int wideGapPosition = ((j==0)? WIDE_LEFT : 0) + ((j==np-1)? WIDE_RIGHT : 0); addField(f, certPerPlayerXOffset + j, certPerPlayerYOffset + i, - 1, 1, 0, visible); + 1, 1, wideGapPosition, visible); f = certPerPlayerButton[i][j] = new ClickField("", SELL_CMD, LocalText.getText("ClickForSell"), this, buySellGroup); addField(f, certPerPlayerXOffset + j, certPerPlayerYOffset + i, - 1, 1, 0, false); + 1, 1, wideGapPosition, false); } f = certInIPO[i] = new Field(ipo.getShareModel(c)); - addField(f, certInIPOXOffset, certInIPOYOffset + i, 1, 1, WIDE_LEFT, visible); + addField(f, certInIPOXOffset, certInIPOYOffset + i, 1, 1, 0, visible); f = certInIPOButton[i] = new ClickField( @@ -360,8 +363,10 @@ public class GameStatus extends GridPanel implements ActionListener { BUY_FROM_IPO_CMD, LocalText.getText("ClickToSelectForBuying"), this, buySellGroup); - addField(f, certInIPOXOffset, certInIPOYOffset + i, 1, 1, WIDE_LEFT, false); - certInIPO[i].setPreferredSize(certInIPOButton[i].getPreferredSize()); + addField(f, certInIPOXOffset, certInIPOYOffset + i, 1, 1, 0, false); + + //no size alignment as button size could also be smaller than the field's one + //certInIPO[i].setPreferredSize(certInIPOButton[i].getPreferredSize()); f = certInPool[i] = new Field(pool.getShareModel(c)); addField(f, certInPoolXOffset, certInPoolYOffset + i, 1, 1, @@ -375,7 +380,8 @@ public class GameStatus extends GridPanel implements ActionListener { this, buySellGroup); addField(f, certInPoolXOffset, certInPoolYOffset + i, 1, 1, WIDE_RIGHT, false); - certInPool[i].setPreferredSize(certInIPOButton[i].getPreferredSize());/* sic */ + //no size alignment as button size could also be smaller than the field's one + //certInPool[i].setPreferredSize(certInIPOButton[i].getPreferredSize());/* sic */ if (compCanHoldOwnShares) { f = @@ -450,7 +456,6 @@ public class GameStatus extends GridPanel implements ActionListener { addField (f, rightsXOffset, rightsYOffset + i, 1, 1, 0, visible); } - f = new Caption(c.getName()); f.setForeground(c.getFgColour()); f.setBackground(c.getBgColour()); @@ -464,11 +469,13 @@ public class GameStatus extends GridPanel implements ActionListener { // Player possessions addField(new Caption(LocalText.getText("CASH")), 0, playerCashYOffset, - 1, 1, WIDE_TOP + WIDE_RIGHT, true); + 1, 1, WIDE_TOP , true); for (int i = 0; i < np; i++) { f = playerCash[i] = new Field(players[i].getCashModel()); + int wideGapPosition = WIDE_TOP + + ((i==0)? WIDE_LEFT : 0) + ((i==np-1)? WIDE_RIGHT : 0); addField(f, playerCashXOffset + i, playerCashYOffset, 1, 1, - WIDE_TOP, true); + wideGapPosition, true); f = playerCashButton[i] = new ClickField( @@ -477,11 +484,11 @@ public class GameStatus extends GridPanel implements ActionListener { LocalText.getText("CorrectCashToolTip"), this, buySellGroup); addField(f, playerCashXOffset + i, playerCashYOffset, 1, 1, - WIDE_TOP, false); + wideGapPosition, false); } - addField(new Caption("Privates"), 0, playerPrivatesYOffset, 1, 1, - WIDE_RIGHT, false); + addField(new Caption(LocalText.getText("PRIVATES")), 0, playerPrivatesYOffset, 1, 1, + 0, true); for (int i = 0; i < np; i++) { f = playerPrivates[i] = @@ -490,65 +497,71 @@ public class GameStatus extends GridPanel implements ActionListener { HexHighlightMouseListener.addMouseListener(f, gameUIManager.getORUIManager(), players[i].getPortfolio()); + int wideGapPosition = ((i==0)? WIDE_LEFT : 0) + ((i==np-1)? WIDE_RIGHT : 0); addField(f, playerPrivatesXOffset + i, playerPrivatesYOffset, 1, 1, - 0, true); + wideGapPosition, true); } addField(new Caption(LocalText.getText("WORTH")), 0, - playerWorthYOffset, 1, 1, WIDE_RIGHT, true); + playerWorthYOffset, 1, 1, 0, true); for (int i = 0; i < np; i++) { f = playerWorth[i] = new Field(players[i].getWorthModel()); - addField(f, playerWorthXOffset + i, playerWorthYOffset, 1, 1, 0, true); + int wideGapPosition = ((i==0)? WIDE_LEFT : 0) + ((i==np-1)? WIDE_RIGHT : 0); + addField(f, playerWorthXOffset + i, playerWorthYOffset, 1, 1, wideGapPosition, true); } addField(new Caption(LocalText.getText("ORWORTHINCR")), 0, - playerORWorthIncreaseYOffset, 1, 1, WIDE_RIGHT, true); + playerORWorthIncreaseYOffset, 1, 1, 0, true); for (int i = 0; i < np; i++) { f = playerORWorthIncrease[i] = new Field(players[i].getLastORWorthIncrease()); - addField(f, playerORWorthIncreaseXOffset + i, playerORWorthIncreaseYOffset, 1, 1, 0, true); + int wideGapPosition = ((i==0)? WIDE_LEFT : 0) + ((i==np-1)? WIDE_RIGHT : 0); + addField(f, playerORWorthIncreaseXOffset + i, playerORWorthIncreaseYOffset, 1, 1, wideGapPosition, true); } addField(new Caption("Certs"), 0, playerCertCountYOffset, 1, 1, - WIDE_RIGHT + WIDE_TOP, true); + WIDE_TOP, true); for (int i = 0; i < np; i++) { f = playerCertCount[i] = new Field(players[i].getCertCountModel(), false, true); + int wideGapPosition = WIDE_TOP + + ((i==0)? WIDE_LEFT : 0) + ((i==np-1)? WIDE_RIGHT : 0); addField(f, playerCertCountXOffset + i, playerCertCountYOffset, 1, - 1, WIDE_TOP, true); + 1, wideGapPosition, true); } - + for (int i = 0; i < np; i++) { f = lowerPlayerCaption[i] = new Caption(players[i].getName()); - addField(f, i + 1, playerCertCountYOffset + 1, 1, 1, WIDE_TOP, true); + int wideGapPosition = WIDE_TOP + + ((i==0)? WIDE_LEFT : 0) + ((i==np-1)? WIDE_RIGHT : 0); + addField(f, i + 1, playerCertCountYOffset + 1, 1, 1, wideGapPosition, true); } // Certificate Limit addField(new Caption(LocalText.getText("LIMIT")), certLimitXOffset - 1, - certLimitYOffset, 1, 1, WIDE_TOP + WIDE_LEFT, true); + certLimitYOffset, 1, 1, WIDE_TOP, true); addField(new Field(gameUIManager.getGameManager().getPlayerCertificateLimitModel()), certLimitXOffset, - certLimitYOffset, 1, 1, WIDE_TOP, true); + certLimitYOffset, 1, 1, WIDE_TOP + WIDE_RIGHT, true); // Phase addField(new Caption(LocalText.getText("PHASE")), phaseXOffset - 1, - phaseYOffset, 1, 1, WIDE_TOP + WIDE_LEFT, true); + phaseYOffset, 1, 1, WIDE_TOP, true); addField(new Field(gameUIManager.getGameManager().getPhaseManager().getCurrentPhaseModel()), phaseXOffset, phaseYOffset, 1, 1, WIDE_TOP, true); // Bank addField(new Caption(LocalText.getText("BANK")), bankCashXOffset - 1, - bankCashYOffset - 1, 1, 2, WIDE_TOP + WIDE_LEFT, true); + bankCashYOffset - 1, 1, 2, WIDE_TOP, true); addField(new Caption(LocalText.getText("CASH")), bankCashXOffset, - bankCashYOffset - 1, 1, 1, WIDE_TOP, true); + bankCashYOffset - 1, 1, 1, WIDE_TOP + WIDE_RIGHT, true); bankCash = new Field(bank.getCashModel()); - addField(bankCash, bankCashXOffset, bankCashYOffset, 1, 1, 0, true); + addField(bankCash, bankCashXOffset, bankCashYOffset, 1, 1, WIDE_RIGHT, true); // Trains addField(new Caption(LocalText.getText("TRAINS")), - poolTrainsXOffset - 1, poolTrainsYOffset - 1, 1, 2, WIDE_TOP - + WIDE_LEFT, true); + poolTrainsXOffset - 1, poolTrainsYOffset - 1, 1, 2, WIDE_TOP, true); addField(new Caption(LocalText.getText("USED")), poolTrainsXOffset, poolTrainsYOffset - 1, 1, 1, WIDE_TOP, true); poolTrains = new Field(pool.getTrainsModel()); @@ -570,6 +583,10 @@ public class GameStatus extends GridPanel implements ActionListener { addField(futureTrains, futureTrainsXOffset, futureTrainsYOffset, futureTrainsWidth, 1, 0, true); + // dummy field for nice rendering of table borders + addField (new Caption(""), certInIPOXOffset, newTrainsYOffset + 1, + poolTrainsXOffset - certInIPOXOffset, 2, 0, true); + // Train cost overview String text = gameUIManager.getGameManager().getTrainManager().getTrainCostOverview(); addField (f = new Caption("<html>" + text + "</html>"), poolTrainsXOffset, newTrainsYOffset + 1, diff --git a/rails/ui/swing/GridPanel.java b/rails/ui/swing/GridPanel.java index 58f4ae6..5cbd1da 100644 --- a/rails/ui/swing/GridPanel.java +++ b/rails/ui/swing/GridPanel.java @@ -130,7 +130,12 @@ implements ActionListener, KeyListener { comp.setVisible(visible); } - public void setHighlight(JComponent comp,boolean isToBeHighlighted) { + /** + * highlights given component by altering its border's attributes + * If another component had been highlighted before, it's highlighting is first + * undone before highlighting the new given component. + */ + protected void setHighlight(JComponent comp,boolean isToBeHighlighted) { //quit if nothing is to be done if (isToBeHighlighted && comp == highlightedComp) return; removeHighlight(); @@ -144,7 +149,7 @@ implements ActionListener, KeyListener { } } - public void removeHighlight() { + protected void removeHighlight() { if (highlightedComp == null) return; if (highlightedComp.getBorder() instanceof FieldBorder) { FieldBorder fb = (FieldBorder)highlightedComp.getBorder(); @@ -153,7 +158,7 @@ implements ActionListener, KeyListener { } highlightedComp = null; } - + public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_F1) { HelpWindow.displayHelp(GameManager.getInstance().getHelp()); @@ -276,13 +281,13 @@ implements ActionListener, KeyListener { public void paintBorder(Component c,Graphics g, int x, int y, int width,int height) { Graphics2D g2d = (Graphics2D)g; + Stroke oldStroke = g2d.getStroke(); + g2d.setStroke(new BasicStroke(thickness)); if (isHighlighted) { g2d.setColor(highlightedBorderColor); } else { g2d.setColor(borderColor); } - Stroke oldStroke = g2d.getStroke(); - g2d.setStroke(new BasicStroke(thickness)); g2d.drawRect(x, y, width-1, height-1); g2d.setStroke(oldStroke); } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 4a0d059..ffeabf8 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -792,7 +792,6 @@ implements ActionListener, KeyListener, RevenueListener { //clear all highlighting (president column and beyond) resetActions(); - removeHighlight(); } @@ -917,6 +916,8 @@ implements ActionListener, KeyListener, RevenueListener { } undoButton.setEnabled(false); + removeHighlight(); + } public void resetORCompanyTurn(int orCompIndex) { @@ -1233,7 +1234,6 @@ implements ActionListener, KeyListener, RevenueListener { //clear all highlighting (president column and beyond) resetActions(); - removeHighlight(); button1.setEnabled(false); commit fa6e193f977764f5ba4d3d02d0da50c516629109 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 21 14:15:34 2012 +0100 Introduced highlighting and table borders for Status Win & ORPanel Instead of insets as parts of GridBag constraints, GridPanel now attaches dynamic borders to the fields. This has enabled the following: - GridPanel table borders are visualized without any effort - making the panels much nicer - GridPanel cells (fields,...) can now be highlighted by altering their dynamic borders - even inner borders (margins) used for the highlight outline box - design corresponds to the one used for displaying selected tiles in the hex map diff --git a/rails/ui/swing/GridPanel.java b/rails/ui/swing/GridPanel.java index 661c8b3..58f4ae6 100644 --- a/rails/ui/swing/GridPanel.java +++ b/rails/ui/swing/GridPanel.java @@ -7,18 +7,25 @@ import java.util.*; import java.util.List; import javax.swing.*; +import javax.swing.border.AbstractBorder; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; import org.apache.log4j.Logger; import rails.game.*; import rails.game.model.ModelObject; import rails.game.state.BooleanState; +import rails.ui.swing.elements.Caption; +import rails.ui.swing.elements.ClickField; import rails.ui.swing.elements.Field; import rails.ui.swing.elements.ViewObject; public abstract class GridPanel extends JPanel implements ActionListener, KeyListener { + private static final long serialVersionUID = 1L; + protected static final int NARROW_GAP = 1; protected static final int WIDE_GAP = 3; protected static final int WIDE_LEFT = 1; @@ -54,6 +61,14 @@ implements ActionListener, KeyListener { protected static Logger log = Logger.getLogger(GridPanel.class.getPackage().getName()); + private JComponent highlightedComp = null; + protected Color tableBorderColor = Color.DARK_GRAY; + protected Color cellOutlineColor = Color.GRAY; + protected Color highlightedBorderColor = Color.RED; + + public GridPanel() { + + } public void redisplay() { revalidate(); @@ -74,19 +89,35 @@ implements ActionListener, KeyListener { protected void addField(JComponent comp, int x, int y, int width, int height, int wideGapPositions, boolean visible) { - int padTop, padLeft, padBottom, padRight; gbc.gridx = x; gbc.gridy = y; gbc.gridwidth = width; gbc.gridheight = height; gbc.weightx = gbc.weighty = 0.5; gbc.fill = GridBagConstraints.BOTH; - padTop = (wideGapPositions & WIDE_TOP) > 0 ? WIDE_GAP : NARROW_GAP; - padLeft = (wideGapPositions & WIDE_LEFT) > 0 ? WIDE_GAP : NARROW_GAP; + gbc.insets = new Insets(0,0,0,0); + + //special handling of clickfields as their compound border does not fit + //to this field border logic + if ((comp instanceof ClickField)) { + comp.setBorder(BorderFactory.createLineBorder(new Color(0,0,0,0),1)); + } + + int padTop, padLeft, padBottom, padRight; + padTop = (wideGapPositions & WIDE_TOP) > 0 ? WIDE_GAP - NARROW_GAP : 0; + padLeft = (wideGapPositions & WIDE_LEFT) > 0 ? WIDE_GAP - NARROW_GAP : 0; padBottom = - (wideGapPositions & WIDE_BOTTOM) > 0 ? WIDE_GAP : NARROW_GAP; - padRight = (wideGapPositions & WIDE_RIGHT) > 0 ? WIDE_GAP : NARROW_GAP; - gbc.insets = new Insets(padTop, padLeft, padBottom, padRight); + (wideGapPositions & WIDE_BOTTOM) > 0 ? WIDE_GAP - NARROW_GAP : 0; + padRight = (wideGapPositions & WIDE_RIGHT) > 0 ? WIDE_GAP - NARROW_GAP : 0; + + //set field borders + //- inner border: the field's native border + //- outline border: the field's outline (in narrow_gap thickness) + //- outer border: grid table lines (in wide_gap - narrow_gap thickness) + + comp.setBorder(new FieldBorder(comp.getBorder(), + new DynamicSymmetricBorder(cellOutlineColor,NARROW_GAP), + new DynamicAsymmetricBorder(tableBorderColor,padTop,padLeft,padBottom,padRight))); gridPanel.add(comp, gbc); @@ -98,6 +129,30 @@ implements ActionListener, KeyListener { if (fields != null && fields[x][y] == null) fields[x][y] = comp; comp.setVisible(visible); } + + public void setHighlight(JComponent comp,boolean isToBeHighlighted) { + //quit if nothing is to be done + if (isToBeHighlighted && comp == highlightedComp) return; + removeHighlight(); + if (isToBeHighlighted) { + if (comp.getBorder() instanceof FieldBorder) { + FieldBorder fb = (FieldBorder)comp.getBorder(); + fb.setHighlight(isToBeHighlighted); + comp.repaint(); + } + highlightedComp = comp; + } + } + + public void removeHighlight() { + if (highlightedComp == null) return; + if (highlightedComp.getBorder() instanceof FieldBorder) { + FieldBorder fb = (FieldBorder)highlightedComp.getBorder(); + fb.setHighlight(false); + highlightedComp.repaint(); + } + highlightedComp = null; + } public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_F1) { @@ -169,4 +224,122 @@ implements ActionListener, KeyListener { } } + /** + * Wrapper for three level compound borders and directly accessing border constituents + * @author Frederick Weld + * + */ + private class FieldBorder extends CompoundBorder { + private static final long serialVersionUID = 1L; + Border nativeInnerBorder; + DynamicAsymmetricBorder highlightedInnerBorder; + DynamicSymmetricBorder outlineBorder; + DynamicAsymmetricBorder outerBorder; + public FieldBorder(Border innerBorder,DynamicSymmetricBorder outlineBorder,DynamicAsymmetricBorder outerBorder) { + super(new CompoundBorder(outerBorder,outlineBorder),innerBorder); + this.nativeInnerBorder = innerBorder; + this.outlineBorder = outlineBorder; + this.outerBorder = outerBorder; + this.highlightedInnerBorder = new DynamicAsymmetricBorder( + highlightedBorderColor, + nativeInnerBorder.getBorderInsets(null).top, + nativeInnerBorder.getBorderInsets(null).left, + nativeInnerBorder.getBorderInsets(null).bottom, + nativeInnerBorder.getBorderInsets(null).right); + } + public void setHighlight(boolean isToBeHighlighted) { + outlineBorder.setHighlight(isToBeHighlighted); + this.insideBorder = isToBeHighlighted ? + highlightedInnerBorder : nativeInnerBorder; + } + } + + /** + * A line border providing methods for changing the look + * @author Frederick Weld + * + */ + private class DynamicSymmetricBorder extends AbstractBorder { + private static final long serialVersionUID = 1L; + private int thickness; + private Color borderColor; + private boolean isHighlighted = false; + public DynamicSymmetricBorder (Color borderColor,int thickness) { + this.thickness = thickness; + this.borderColor = borderColor; + } + public void setHighlight(boolean isToBeHighlighted) { + if (isHighlighted != isToBeHighlighted) { + isHighlighted = isToBeHighlighted; + } + } + + public void paintBorder(Component c,Graphics g, int x, int y, int width,int height) { + Graphics2D g2d = (Graphics2D)g; + if (isHighlighted) { + g2d.setColor(highlightedBorderColor); + } else { + g2d.setColor(borderColor); + } + Stroke oldStroke = g2d.getStroke(); + g2d.setStroke(new BasicStroke(thickness)); + g2d.drawRect(x, y, width-1, height-1); + g2d.setStroke(oldStroke); + } + + public Insets getBorderInsets (Component c) { + return new Insets(thickness,thickness,thickness,thickness); + } + + public boolean isBorderOpaque() { + return true; + } + } + /** + * An asymmetric line border providing methods for changing the look + * @author Frederick Weld + * + */ + private class DynamicAsymmetricBorder extends AbstractBorder { + private static final long serialVersionUID = 1L; + private int padTop, padLeft, padBottom, padRight; + private Color borderColor; + public DynamicAsymmetricBorder (Color borderColor,int padTop, int padLeft, int padBottom, int padRight) { + this.padTop = padTop; + this.padLeft = padLeft; + this.padBottom = padBottom; + this.padRight = padRight; + this.borderColor = borderColor; + } + public void paintBorder(Component c,Graphics g, int x, int y, int width,int height) { + Graphics2D g2d = (Graphics2D)g; + g2d.setColor(borderColor); + Stroke oldStroke = g2d.getStroke(); + if (padTop > 0) { + g2d.setStroke(new BasicStroke(padTop)); + g2d.fillRect(x, y, width, padTop); + } + if (padLeft > 0) { + g2d.setStroke(new BasicStroke(padLeft)); + g2d.fillRect(x, y, padLeft, height); + } + if (padBottom > 0) { + g2d.setStroke(new BasicStroke(padBottom)); + g2d.fillRect(x, y+height-padBottom, width, padBottom); + } + if (padRight > 0) { + g2d.setStroke(new BasicStroke(padRight)); + g2d.fillRect(x+width-padRight, y, padRight, height); + } + g2d.setStroke(oldStroke); + } + + public Insets getBorderInsets (Component c) { + return new Insets(padTop,padLeft,padBottom,padRight); + } + + public boolean isBorderOpaque() { + return true; + } + } } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 8a47981..4a0d059 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -491,7 +491,7 @@ implements ActionListener, KeyListener, RevenueListener { HexHighlightMouseListener.addMouseListener(f, orUIManager,c.getPortfolio()); addField(f, privatesXOffset, privatesYOffset + i, 1, 1, - WIDE_RIGHT, visible); + 0, visible); f = newPrivatesCost[i] = @@ -792,6 +792,7 @@ implements ActionListener, KeyListener, RevenueListener { //clear all highlighting (president column and beyond) resetActions(); + removeHighlight(); } @@ -1002,7 +1003,9 @@ implements ActionListener, KeyListener, RevenueListener { this.orComp = orComp; this.orCompIndex = orCompIndex; president[orCompIndex].setHighlight(true); - + + removeHighlight(); + buttonOC.clearPossibleActions(); button1.clearPossibleActions(); button2.clearPossibleActions(); @@ -1016,10 +1019,11 @@ implements ActionListener, KeyListener, RevenueListener { updateCurrentRoutes(false); } - + public void initTileLayingStep() { tileCaption.setHighlight(true); + setHighlight(tiles[orCompIndex],true); button1.setVisible(false); } @@ -1027,6 +1031,7 @@ implements ActionListener, KeyListener, RevenueListener { public void initTokenLayingStep() { tokenCaption.setHighlight(true); + setHighlight(tokens[orCompIndex],true); button1.setEnabled(false); button1.setVisible(false); button3.setEnabled(false); @@ -1036,6 +1041,7 @@ implements ActionListener, KeyListener, RevenueListener { public void initRevenueEntryStep(int orCompIndex, SetDividend action) { revenueCaption.setHighlight(true); + setHighlight(revenueSelect[orCompIndex],true); revenueSelect[orCompIndex].setValue(action.getPresetRevenue()); setSelect(revenue[orCompIndex], revenueSelect[orCompIndex], true); @@ -1074,6 +1080,8 @@ implements ActionListener, KeyListener, RevenueListener { public void initPayoutStep(int orCompIndex, SetDividend action, boolean withhold, boolean split, boolean payout) { + setHighlight(revenue[orCompIndex],true); + SetDividend clonedAction; setSelect(revenue[orCompIndex], revenueSelect[orCompIndex], false); @@ -1120,6 +1128,7 @@ implements ActionListener, KeyListener, RevenueListener { public void initTrainBuying(boolean enabled) { trainCaption.setHighlight(true); + setHighlight(trains[orCompIndex],true); button1.setText(LocalText.getText("BUY_TRAIN")); button1.setActionCommand(BUY_TRAIN_CMD); @@ -1149,6 +1158,7 @@ implements ActionListener, KeyListener, RevenueListener { button2.setEnabled(enabled); button2.setVisible(enabled); privatesCaption.setHighlight(enabled); + setHighlight(privates[orCompIndex],enabled); } else { button2.setVisible(false); } @@ -1201,6 +1211,7 @@ implements ActionListener, KeyListener, RevenueListener { repayLoans.setEnabled(true); loansCaption.setHighlight(true); + setHighlight(compLoans[orCompIndex],true); button1.setText(LocalText.getText("RepayLoans")); button1.setActionCommand(REPAY_LOANS_CMD); @@ -1222,6 +1233,7 @@ implements ActionListener, KeyListener, RevenueListener { //clear all highlighting (president column and beyond) resetActions(); + removeHighlight(); button1.setEnabled(false); |