You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(3) |
Nov
(46) |
Dec
(57) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(51) |
Feb
(10) |
Mar
|
Apr
|
May
(14) |
Jun
|
Jul
(13) |
Aug
(30) |
Sep
(83) |
Oct
(56) |
Nov
(148) |
Dec
(107) |
2010 |
Jan
(260) |
Feb
(164) |
Mar
(183) |
Apr
(99) |
May
(160) |
Jun
(40) |
Jul
(33) |
Aug
(48) |
Sep
(22) |
Oct
(24) |
Nov
(1) |
Dec
(12) |
2011 |
Jan
(6) |
Feb
(15) |
Mar
(13) |
Apr
(37) |
May
(27) |
Jun
(29) |
Jul
(33) |
Aug
(20) |
Sep
(17) |
Oct
(20) |
Nov
(33) |
Dec
(17) |
2012 |
Jan
(39) |
Feb
(38) |
Mar
(20) |
Apr
(21) |
May
(17) |
Jun
(22) |
Jul
(16) |
Aug
(3) |
Sep
(9) |
Oct
(10) |
Nov
|
Dec
|
From: Frederick W. <fre...@us...> - 2012-01-21 18:27:47
|
rails/ui/swing/MessagePanel.java | 4 ++-- rails/ui/swing/ORPanel.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) New commits: commit 0c3a97d2c55df8ab8e8d06064e5d909bc89448fa Author: Frederick Weld <fre...@gm...> Date: Sat Jan 21 19:26:03 2012 +0100 Fixed MessagePanel's revalidate invocation diff --git a/rails/ui/swing/MessagePanel.java b/rails/ui/swing/MessagePanel.java index 6c50471..3b3d2cc 100644 --- a/rails/ui/swing/MessagePanel.java +++ b/rails/ui/swing/MessagePanel.java @@ -74,7 +74,7 @@ public class MessagePanel extends JPanel { if (showDetails) { showDetails = false; parentSlider.setPreferredSize(new Dimension(minWidth,defaultHeight)); - parentSlider.getParent().revalidate(); + ((JComponent)parentSlider.getParent()).revalidate(); } } @@ -82,7 +82,7 @@ public class MessagePanel extends JPanel { if (!showDetails && currentDetails != null) { showDetails = true; parentSlider.setPreferredSize(new Dimension(minWidth,fullHeight)); - parentSlider.getParent().revalidate(); + ((JComponent)parentSlider.getParent()).revalidate(); } } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index f3b8b18..c8193ac 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -1037,7 +1037,7 @@ implements ActionListener, KeyListener, RevenueListener { setHighlight(tokens[orCompIndex],true); setHighlight(tokenCost[orCompIndex],true); setHighlight(tokensLeft[orCompIndex],true); - setHighlight(tokenBonus[orCompIndex],true); + if (tokenBonus != null) setHighlight(tokenBonus[orCompIndex],true); button1.setEnabled(false); button1.setVisible(false); button3.setEnabled(false); |
From: Frederick W. <fre...@us...> - 2012-01-21 18:15:33
|
rails/ui/swing/GridPanel.java | 38 ++++++++++++++++++++------------------ rails/ui/swing/ORPanel.java | 16 +++++++++++----- 2 files changed, 31 insertions(+), 23 deletions(-) New commits: commit a6d8c72b5d2cebe6ef49788daa5e197427af2524 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 21 19:12:00 2012 +0100 Enhanced OR panel highlighting (highlights for multi-cell & spinner) Now all relevant cells of a company's turn are highlighted (eg. all token related cells during the lay token turn). The revenue spinner cell's highlighting is now aligned with the one of standard cells. Re-adjusted highlighting scope (eg., revenue is not highlighted any more during the decision turn). diff --git a/rails/ui/swing/GridPanel.java b/rails/ui/swing/GridPanel.java index 4941867..a64f955 100644 --- a/rails/ui/swing/GridPanel.java +++ b/rails/ui/swing/GridPanel.java @@ -62,7 +62,7 @@ implements ActionListener, KeyListener { protected static Logger log = Logger.getLogger(GridPanel.class.getPackage().getName()); - private JComponent highlightedComp = null; + private List<JComponent> highlightedComps = new ArrayList<JComponent>(); protected Color tableBorderColor; protected Color cellOutlineColor; protected Color highlightedBorderColor; @@ -142,31 +142,33 @@ implements ActionListener, KeyListener { /** * 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(); - if (isToBeHighlighted) { - if (comp.getBorder() instanceof FieldBorder) { - FieldBorder fb = (FieldBorder)comp.getBorder(); - fb.setHighlight(isToBeHighlighted); - comp.repaint(); + if (isToBeHighlighted && highlightedComps.contains(comp)) return; + if (!isToBeHighlighted && !highlightedComps.contains(comp)) return; + + if (comp.getBorder() instanceof FieldBorder) { + FieldBorder fb = (FieldBorder)comp.getBorder(); + fb.setHighlight(isToBeHighlighted); + comp.repaint(); + if (isToBeHighlighted) { + highlightedComps.add(comp); + } else { + highlightedComps.remove(comp); } - highlightedComp = comp; } } - protected void removeHighlight() { - if (highlightedComp == null) return; - if (highlightedComp.getBorder() instanceof FieldBorder) { - FieldBorder fb = (FieldBorder)highlightedComp.getBorder(); - fb.setHighlight(false); - highlightedComp.repaint(); + protected void removeAllHighlights() { + for (JComponent c : highlightedComps) { + if (c.getBorder() instanceof FieldBorder) { + FieldBorder fb = (FieldBorder)c.getBorder(); + fb.setHighlight(false); + c.repaint(); + } } - highlightedComp = null; + highlightedComps.clear(); } public void keyPressed(KeyEvent e) { diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index ffeabf8..f3b8b18 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -396,7 +396,7 @@ implements ActionListener, KeyListener, RevenueListener { loansXOffset = currentXOffset += lastXWidth; loansYOffset = leftCompNameYOffset; addField (loansCaption = new Caption(LocalText.getText("LOANS")), - loansXOffset, 0, lastXWidth = 1, 2, WIDE_RIGHT); + loansXOffset, 0, lastXWidth = 1, 2, WIDE_BOTTOM + WIDE_RIGHT); } if (hasRights) { @@ -541,7 +541,8 @@ implements ActionListener, KeyListener, RevenueListener { addField(f, revXOffset, revYOffset + i, 1, 1, 0, visible); f = revenueSelect[i] = new Spinner(0, 0, 0, 10); //zero-border so that size matches revenue field (thus, averting or panel resize) - f.setBorder(new javax.swing.border.EmptyBorder(0,0,0,0)); + f.setPreferredSize(revenue[i].getPreferredSize()); + //f.setBorder(new javax.swing.border.EmptyBorder(0,0,0,0)); addField(f, revXOffset, revYOffset + i, 1, 1, 0, false); // deactived below, as this caused problems by gridpanel rowvisibility function -- sfy // revenue[i].addDependent(revenueSelect[i]); @@ -916,7 +917,7 @@ implements ActionListener, KeyListener, RevenueListener { } undoButton.setEnabled(false); - removeHighlight(); + removeAllHighlights(); } @@ -1005,7 +1006,7 @@ implements ActionListener, KeyListener, RevenueListener { this.orCompIndex = orCompIndex; president[orCompIndex].setHighlight(true); - removeHighlight(); + removeAllHighlights(); buttonOC.clearPossibleActions(); button1.clearPossibleActions(); @@ -1025,6 +1026,7 @@ implements ActionListener, KeyListener, RevenueListener { tileCaption.setHighlight(true); setHighlight(tiles[orCompIndex],true); + setHighlight(tileCost[orCompIndex],true); button1.setVisible(false); } @@ -1033,6 +1035,9 @@ implements ActionListener, KeyListener, RevenueListener { tokenCaption.setHighlight(true); setHighlight(tokens[orCompIndex],true); + setHighlight(tokenCost[orCompIndex],true); + setHighlight(tokensLeft[orCompIndex],true); + setHighlight(tokenBonus[orCompIndex],true); button1.setEnabled(false); button1.setVisible(false); button3.setEnabled(false); @@ -1081,7 +1086,7 @@ implements ActionListener, KeyListener, RevenueListener { public void initPayoutStep(int orCompIndex, SetDividend action, boolean withhold, boolean split, boolean payout) { - setHighlight(revenue[orCompIndex],true); + setHighlight(decision[orCompIndex],true); SetDividend clonedAction; @@ -1130,6 +1135,7 @@ implements ActionListener, KeyListener, RevenueListener { trainCaption.setHighlight(true); setHighlight(trains[orCompIndex],true); + setHighlight(newTrainCost[orCompIndex],true); button1.setText(LocalText.getText("BUY_TRAIN")); button1.setActionCommand(BUY_TRAIN_CMD); |
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); |
From: Frederick W. <fre...@us...> - 2012-01-17 16:46:16
|
data/18GA/MapImage_CottonPort.svg | 184 ++++++++++++++++++++++++++++++++++++-- rails/ui/swing/GameStatus.java | 2 rails/ui/swing/ORPanel.java | 9 + 3 files changed, 185 insertions(+), 10 deletions(-) New commits: commit 8a211c6c4916208777105ddb9c67e5ef3c797225 Author: Frederick Weld <fre...@gm...> Date: Tue Jan 17 17:23:54 2012 +0100 Disabled caption highlighting for non-active windows Now, all of the OR's president/stepCaption highlighting is removed upon leaving an operation round. The same applies vice versa for the stock round. (This was not the case before.) diff --git a/rails/ui/swing/GameStatus.java b/rails/ui/swing/GameStatus.java index 6cc5c2e..bb7dcb5 100644 --- a/rails/ui/swing/GameStatus.java +++ b/rails/ui/swing/GameStatus.java @@ -838,7 +838,7 @@ public class GameStatus extends GridPanel implements ActionListener { this.actorIndex = actorIndex; - highlightCurrentPlayer(playerIndex.get(gameUIManager.getCurrentPlayer())); + highlightCurrentPlayer(this.actorIndex); if (treasurySharesCaption != null) treasurySharesCaption.setHighlight(actorIndex == -1); // Set new highlights diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index bfab7d8..8a47981 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -789,6 +789,10 @@ implements ActionListener, KeyListener, RevenueListener { redoButton.setEnabled(false); disableRoutesDisplay(); + + //clear all highlighting (president column and beyond) + resetActions(); + } public void redrawRoutes() { @@ -1216,9 +1220,8 @@ implements ActionListener, KeyListener, RevenueListener { public void finishORCompanyTurn(int orCompIndex) { - for (Field field : president) { - field.setHighlight(false); - } + //clear all highlighting (president column and beyond) + resetActions(); button1.setEnabled(false); commit f355793cb88692be4ce62fb00f63a862a2fec1d4 Author: Frederick Weld <fre...@gm...> Date: Tue Jan 17 16:31:41 2012 +0100 Aligned SAL token placement on background image with rails (cotton port) diff --git a/data/18GA/MapImage_CottonPort.svg b/data/18GA/MapImage_CottonPort.svg index 7689c16..6ad585a 100644 --- a/data/18GA/MapImage_CottonPort.svg +++ b/data/18GA/MapImage_CottonPort.svg @@ -39,14 +39,14 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="1737" + inkscape:window-width="1745" inkscape:window-height="1047" id="namedview8508" showgrid="false" inkscape:zoom="1" - inkscape:cx="432" + inkscape:cx="431.69887" inkscape:cy="465.61951" - inkscape:window-x="172" + inkscape:window-x="1444" inkscape:window-y="-11" inkscape:window-maximized="1" inkscape:current-layer="svg2" /> @@ -16538,6 +16538,7 @@ + <text transform="translate(238.5708,369.5615)" font-size="11" @@ -16546,6 +16547,7 @@ + <g id="g7038"> <circle @@ -16567,6 +16569,7 @@ + <text transform="translate(690.0059,987.5615)" font-size="12" @@ -16575,6 +16578,7 @@ + <text transform="translate(235.9185,789.5625)" font-size="12" @@ -16583,6 +16587,7 @@ + <g id="g7048"> <circle @@ -16604,6 +16609,7 @@ + </g> <path d="M 835.486,687.847" @@ -16680,6 +16686,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,2.8315,-2.0274)" cx="592.79498" @@ -16745,6 +16752,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,3.5331,-2.0148)" cx="589.46198" @@ -16810,6 +16818,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,2.5226,-1.8223)" cx="532.79498" @@ -16875,6 +16884,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,2.2008,-1.6342)" cx="477.79501" @@ -16940,6 +16950,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,2.1814,-0.467)" cx="137.295" @@ -16964,6 +16975,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,2.5634,-0.6594)" cx="193.629" @@ -16988,6 +17000,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,2.8774,-0.4714)" cx="138.96201" @@ -17012,6 +17025,7 @@ + <path d="m 244.072,929.84 c -0.018,5.109 -20.308,9.16 -53.031,9.049 -32.723,-0.113 -59.236,-4.344 -59.219,-9.455 0.018,-5.107 26.559,-9.156 59.281,-9.045 32.722,0.111 52.987,4.343 52.969,9.451 z" id="path7218" @@ -17029,6 +17043,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,1.8949,-0.6663)" cx="195.295" @@ -17053,6 +17068,7 @@ + <ellipse transform="matrix(0.8795,0.4759,-0.4759,0.8795,198.6645,-89.6501)" @@ -17074,6 +17090,7 @@ + <text transform="matrix(0.8888,0.4583,-0.4583,0.8888,271.6406,334.4824)" font-size="11" @@ -17082,6 +17099,7 @@ + <text transform="matrix(0.8821,0.4711,-0.4711,0.8821,276.5225,337.001)" font-size="11" @@ -17090,6 +17108,7 @@ + <text transform="matrix(0.877,0.4806,-0.4806,0.877,281.3745,339.5996)" font-size="11" @@ -17098,6 +17117,7 @@ + <text transform="matrix(0.873,0.4878,-0.4878,0.873,283.7783,340.9141)" font-size="11" @@ -17106,6 +17126,7 @@ + <text transform="matrix(0.868,0.4966,-0.4966,0.868,286.8823,342.6475)" font-size="11" @@ -17114,6 +17135,7 @@ + <text transform="matrix(0.8628,0.5056,-0.5056,0.8628,290.3701,344.6436)" font-size="11" @@ -17122,6 +17144,7 @@ + <text transform="matrix(0.8583,0.5131,-0.5131,0.8583,293.3291,346.3799)" font-size="11" @@ -17130,6 +17153,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,0.8875,-1.6319)" cx="476.44601" @@ -17195,6 +17219,7 @@ + <ellipse transform="matrix(0.9993,-0.0367,0.0367,0.9993,-9.116,13.8394)" @@ -17216,6 +17241,7 @@ + <text transform="matrix(0.9984,-0.0566,0.0566,0.9984,361.832,246.584)" font-size="11" @@ -17224,6 +17250,7 @@ + <text transform="matrix(0.9991,-0.0421,0.0421,0.9991,367.3169,246.2739)" font-size="11" @@ -17232,6 +17259,7 @@ + <text transform="matrix(0.9995,-0.0314,0.0314,0.9995,372.8174,246.0503)" font-size="11" @@ -17240,6 +17268,7 @@ + <text transform="matrix(0.9997,-0.0231,0.0231,0.9997,375.5786,245.9609)" font-size="11" @@ -17248,6 +17277,7 @@ + <text transform="matrix(0.9999,-0.013,0.013,0.9999,379.1089,245.8779)" font-size="11" @@ -17256,6 +17286,7 @@ + <text transform="matrix(1,-0.0026,0.0026,1,383.1274,245.8271)" font-size="11" @@ -17264,6 +17295,7 @@ + <text transform="matrix(1,0.0062,-0.0062,1,386.5591,245.8193)" font-size="11" @@ -17272,6 +17304,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,0.8907,-0.48)" cx="140.463" @@ -17337,6 +17370,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,1.212,-0.272)" cx="79.947998" @@ -17402,6 +17436,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,2.215,-2.4081)" cx="703.54498" @@ -17467,6 +17502,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,1.8963,-1.4422)" cx="421.62799" @@ -17532,6 +17568,7 @@ + </g> <g id="cities_copy"> @@ -17600,6 +17637,7 @@ + <ellipse transform="matrix(0.9995,-0.0311,0.0311,0.9995,-25.5865,8.511)" @@ -17654,6 +17692,7 @@ + <ellipse transform="matrix(0.9995,-0.0311,0.0311,0.9995,-28.4159,13.6104)" @@ -17720,6 +17759,7 @@ + <ellipse transform="matrix(0.9995,-0.0311,0.0311,0.9995,-28.7966,17.1317)" @@ -17786,6 +17826,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,1.8459,-1.4412)" cx="421.29401" @@ -17881,6 +17922,7 @@ + <ellipse transform="matrix(1,0.0081,-0.0081,1,5.2,-2.9606)" cx="366.94" @@ -17901,6 +17943,7 @@ + <text transform="matrix(1,0.0024,-0.0024,1,361.8525,629.2285)" font-size="14" @@ -17909,6 +17952,7 @@ + <text transform="matrix(0.9999,0.0157,-0.0157,0.9999,367.6826,629.248)" font-size="14" @@ -17917,6 +17961,7 @@ + <text transform="matrix(0.9996,0.0285,-0.0285,0.9996,372.1895,629.3164)" font-size="14" @@ -17925,6 +17970,7 @@ + <text transform="matrix(0.999,0.0438,-0.0438,0.999,377.2896,629.459)" font-size="14" @@ -17933,6 +17979,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,1.5436,-2.0245)" cx="591.29401" @@ -17992,6 +18039,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,2.4918,-2.2131)" cx="646.79401" @@ -18069,6 +18117,7 @@ + <ellipse transform="matrix(0.8849,-0.4657,0.4657,0.8849,-247.4879,456.6866)" @@ -18155,6 +18204,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,1.1804,-0.6632)" cx="194.04401" @@ -18196,6 +18246,7 @@ + </g> <g id="privates_x27__track_copy"> @@ -18461,6 +18512,7 @@ + <text transform="matrix(0.861,-0.5086,0.5086,0.861,674.4219,561.6182)" @@ -18470,6 +18522,7 @@ + <text transform="matrix(0.8658,-0.5004,0.5004,0.8658,676.6973,560.2695)" @@ -18479,6 +18532,7 @@ + <text transform="matrix(0.8704,-0.4923,0.4923,0.8704,680.6631,557.9814)" @@ -18488,6 +18542,7 @@ + <text transform="matrix(0.8751,-0.484,0.484,0.8751,682.9746,556.6689)" @@ -18497,6 +18552,7 @@ + <text transform="matrix(0.8811,-0.473,0.473,0.8811,686.9668,554.46)" @@ -18506,6 +18562,7 @@ + <text transform="matrix(0.8872,-0.4613,0.4613,0.8872,691.1025,552.2383)" @@ -18515,6 +18572,7 @@ + <ellipse transform="matrix(0.8677,-0.497,0.497,0.8677,-194.4408,420.1078)" @@ -18537,6 +18595,7 @@ + <text transform="matrix(0.8471,-0.5314,0.5314,0.8471,672.8418,576.1484)" @@ -18546,6 +18605,7 @@ + <text transform="matrix(0.8525,-0.5226,0.5226,0.8525,676.7324,573.7148)" @@ -18555,6 +18615,7 @@ + <text transform="matrix(0.8563,-0.5165,0.5165,0.8563,678.9561,572.3525)" @@ -18564,6 +18625,7 @@ + <text transform="matrix(0.8603,-0.5098,0.5098,0.8603,681.2168,570.9854)" @@ -18573,6 +18635,7 @@ + <text transform="matrix(0.8651,-0.5015,0.5015,0.8651,683.9961,569.3389)" @@ -18582,6 +18645,7 @@ + <text transform="matrix(0.8707,-0.4919,0.4919,0.8707,687.4639,567.3242)" @@ -18591,6 +18655,7 @@ + <text transform="matrix(0.8765,-0.4814,0.4814,0.8765,691.4336,565.0811)" @@ -18600,6 +18665,7 @@ + <text transform="matrix(0.8813,-0.4725,0.4725,0.8813,695.4678,562.8711)" @@ -18609,6 +18675,7 @@ + <text transform="matrix(0.8875,-0.4608,0.4608,0.8875,697.8652,561.5693)" @@ -18618,6 +18685,7 @@ + <text transform="matrix(0.8949,-0.4462,0.4462,0.8949,703.7812,558.5117)" @@ -18627,6 +18695,7 @@ + <text transform="matrix(0.8998,-0.4364,0.4364,0.8998,707.3623,556.7295)" @@ -18636,6 +18705,7 @@ + <ellipse transform="matrix(0.8677,-0.497,0.497,0.8677,-279.2318,290.8105)" @@ -18658,6 +18728,7 @@ + <text transform="matrix(0.8237,-0.5671,0.5671,0.8237,377.1455,677.7783)" @@ -18667,6 +18738,7 @@ + <text transform="matrix(0.83,-0.5578,0.5578,0.83,380.0664,675.7705)" @@ -18676,6 +18748,7 @@ + <text transform="matrix(0.835,-0.5503,0.5503,0.835,382.2539,674.3008)" @@ -18685,6 +18758,7 @@ + <text transform="matrix(0.8396,-0.5433,0.5433,0.8396,384.4521,672.8525)" @@ -18694,6 +18768,7 @@ + <text transform="matrix(0.8455,-0.534,0.534,0.8455,386.666,671.4141)" @@ -18703,6 +18778,7 @@ + <text transform="matrix(0.8511,-0.525,0.525,0.8511,390.5381,668.9746)" @@ -18712,6 +18788,7 @@ + <text transform="matrix(0.8568,-0.5156,0.5156,0.8568,392.8936,667.5137)" @@ -18721,6 +18798,7 @@ + <text transform="matrix(0.863,-0.5052,0.5052,0.863,397.3076,664.8623)" @@ -18730,6 +18808,7 @@ + <text transform="matrix(0.869,-0.4948,0.4948,0.869,400.7695,662.8301)" @@ -18739,6 +18818,7 @@ + <text transform="matrix(0.8734,-0.487,0.487,0.8734,404.8623,660.5049)" @@ -18748,6 +18828,7 @@ + <text transform="matrix(0.878,-0.4786,0.4786,0.878,407.1484,659.2246)" @@ -18757,6 +18838,7 @@ + <text transform="matrix(0.8832,-0.469,0.469,0.8832,411.1758,657.0332)" @@ -18766,6 +18848,7 @@ + <text transform="matrix(0.8875,-0.4607,0.4607,0.8875,414.1123,655.4727)" @@ -18775,6 +18858,7 @@ + <text transform="matrix(0.893,-0.4501,0.4501,0.893,416.9551,653.9922)" @@ -18784,6 +18868,7 @@ + <text transform="matrix(0.8983,-0.4393,0.4393,0.8983,421.1572,651.8809)" @@ -18793,6 +18878,7 @@ + <text transform="matrix(0.9057,-0.4239,0.4239,0.9057,423.6143,650.6582)" @@ -18802,6 +18888,7 @@ + <text transform="matrix(0.9177,-0.3972,0.3972,0.9177,429.8418,647.7402)" @@ -18811,6 +18898,7 @@ + <ellipse transform="matrix(0.8677,-0.497,0.497,0.8677,-252.3202,193.0875)" @@ -18871,6 +18959,7 @@ + <ellipse transform="matrix(0.8677,-0.497,0.497,0.8677,-256.7026,196.8265)" @@ -18893,6 +18982,7 @@ + <text transform="matrix(0.8329,-0.5533,0.5533,0.8329,215.9805,585.5352)" @@ -18902,6 +18992,7 @@ + <text transform="matrix(0.8382,-0.5453,0.5453,0.8382,218.1816,584.0703)" @@ -18911,6 +19002,7 @@ + <text transform="matrix(0.8466,-0.5322,0.5322,0.8466,220.874,582.3018)" @@ -18920,6 +19012,7 @@ + <text transform="matrix(0.8538,-0.5206,0.5206,0.8538,226.7803,578.6064)" @@ -18929,6 +19022,7 @@ + <text transform="matrix(0.8589,-0.5121,0.5121,0.8589,229.0273,577.2305)" @@ -18938,6 +19032,7 @@ + <text transform="matrix(0.8647,-0.5023,0.5023,0.8647,233.0703,574.8232)" @@ -18947,6 +19042,7 @@ + <text transform="matrix(0.8701,-0.4928,0.4928,0.8701,236.4453,572.8604)" @@ -18956,6 +19052,7 @@ + <text transform="matrix(0.876,-0.4823,0.4823,0.876,240.4199,570.6084)" @@ -18965,6 +19062,7 @@ + <text transform="matrix(0.8836,-0.4683,0.4683,0.8836,244.4463,568.3809)" @@ -18974,6 +19072,7 @@ + <text transform="matrix(0.8901,-0.4558,0.4558,0.8901,250.6045,565.1328)" @@ -18983,6 +19082,7 @@ + <text transform="matrix(0.8969,-0.4422,0.4422,0.8969,253.0566,563.8594)" @@ -18992,6 +19092,7 @@ + <text transform="matrix(0.9075,-0.4201,0.4201,0.9075,259.2227,560.8174)" @@ -19001,6 +19102,7 @@ + <ellipse transform="matrix(0.8677,-0.497,0.497,0.8677,-358.7006,368.7227)" @@ -19023,6 +19125,7 @@ + <text transform="matrix(0.8577,-0.5141,0.5141,0.8577,500.3037,855.2539)" @@ -19032,6 +19135,7 @@ + <text transform="matrix(0.8635,-0.5044,0.5044,0.8635,504.2246,852.9062)" @@ -19041,6 +19145,7 @@ + <text transform="matrix(0.869,-0.4948,0.4948,0.869,507.6943,850.8789)" @@ -19050,6 +19155,7 @@ + <text transform="matrix(0.8727,-0.4882,0.4882,0.8727,510.7734,849.123)" @@ -19059,6 +19165,7 @@ + <text transform="matrix(0.8773,-0.4799,0.4799,0.8773,513.5645,847.5596)" @@ -19068,6 +19175,7 @@ + <text transform="matrix(0.8822,-0.4709,0.4709,0.8822,517.0781,845.6396)" @@ -19077,6 +19185,7 @@ + <text transform="matrix(0.8868,-0.4622,0.4622,0.8868,520.1309,844.0098)" @@ -19086,6 +19195,7 @@ + <text transform="matrix(0.891,-0.454,0.454,0.891,523.166,842.4297)" @@ -19095,6 +19205,7 @@ + <text transform="matrix(0.8997,-0.4365,0.4365,0.8997,525.5986,841.1523)" @@ -19104,6 +19215,7 @@ + <text transform="matrix(0.9093,-0.416,0.416,0.9093,534.082,837.0752)" @@ -19113,6 +19225,7 @@ + <ellipse transform="matrix(0.8677,-0.497,0.497,0.8677,-361.7391,373.4455)" @@ -19135,6 +19248,7 @@ + <text transform="matrix(0.8442,-0.536,0.536,0.8442,500.2051,867.9854)" @@ -19144,6 +19258,7 @@ + <text transform="matrix(0.8509,-0.5252,0.5252,0.8509,503.5967,865.8301)" @@ -19153,6 +19268,7 @@ + <text transform="matrix(0.8562,-0.5166,0.5166,0.8562,507.582,863.376)" @@ -19162,6 +19278,7 @@ + <text transform="matrix(0.8612,-0.5083,0.5083,0.8612,509.8535,862)" @@ -19171,6 +19288,7 @@ + <text transform="matrix(0.8663,-0.4994,0.4994,0.8663,513.7812,859.6855)" @@ -19180,6 +19298,7 @@ + <text transform="matrix(0.8706,-0.492,0.492,0.8706,516.666,858.0225)" @@ -19189,6 +19308,7 @@ + <text transform="matrix(0.8756,-0.483,0.483,0.8756,519.458,856.4404)" @@ -19198,6 +19318,7 @@ + <text transform="matrix(0.8805,-0.4741,0.4741,0.8805,523.5723,854.1758)" @@ -19207,6 +19328,7 @@ + <text transform="matrix(0.8869,-0.462,0.462,0.8869,525.998,852.8525)" @@ -19216,6 +19338,7 @@ + <text transform="matrix(0.8964,-0.4432,0.4432,0.8964,532.0898,849.6787)" @@ -19225,6 +19348,7 @@ + </g> <g id="red_cities_copy"> @@ -19335,6 +19459,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,0.7079,-2.0216)" cx="590.04401" @@ -19400,6 +19525,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,0.3319,-0.6655)" cx="194.29401" @@ -19507,6 +19633,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,0.3879,-0.6654)" cx="194.29401" @@ -19572,6 +19699,7 @@ + <ellipse transform="matrix(1,-0.0021,0.0021,1,-0.9603,0.5699)" cx="266" @@ -19631,6 +19759,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,3.5189,-2.4124)" cx="705.461" @@ -19744,6 +19873,7 @@ + <ellipse transform="matrix(1,0.0034,-0.0034,1,3.5686,-2.4055)" cx="703.461" @@ -19809,6 +19939,7 @@ + <ellipse transform="matrix(0.9995,-0.0311,0.0311,0.9995,-31.7773,8.5141)" @@ -19911,6 +20042,7 @@ + <ellipse transform="matrix(0.9995,-0.0311,0.0311,0.9995,-32.2134,8.4741)" @@ -19936,6 +20068,7 @@ + <ellipse transform="matrix(0.8574,-0.5146,0.5146,0.8574,-236.3294,99.6702)" @@ -19957,6 +20090,7 @@ + <text transform="matrix(0.8312,-0.556,0.556,0.8312,39.9404,479.3311)" font-size="13" @@ -19965,6 +20099,7 @@ + <text transform="matrix(0.8394,-0.5435,0.5435,0.8394,43.8672,476.7002)" font-size="13" @@ -19973,6 +20108,7 @@ + <text transform="matrix(0.8459,-0.5334,0.5334,0.8459,48.5293,473.6904)" font-size="13" @@ -19981,6 +20117,7 @@ + <text transform="matrix(0.8514,-0.5246,0.5246,0.8514,51.1709,472.0195)" font-size="13" @@ -19989,6 +20126,7 @@ + <text transform="matrix(0.8588,-0.5124,0.5124,0.8588,55.0928,469.5977)" font-size="13" @@ -19997,6 +20135,7 @@ + <text transform="matrix(0.8663,-0.4995,0.4995,0.8663,59.1514,467.1519)" font-size="13" @@ -20005,6 +20144,7 @@ + <text transform="matrix(0.8746,-0.4849,0.4849,0.8746,66.3115,463.0439)" font-size="13" @@ -20013,6 +20153,7 @@ + <text transform="matrix(0.88,-0.4751,0.4751,0.88,69.7529,461.1353)" font-size="13" @@ -20021,6 +20162,7 @@ + <text transform="matrix(0.8862,-0.4634,0.4634,0.8862,73.0918,459.3291)" font-size="13" @@ -20029,6 +20171,7 @@ + <text transform="matrix(0.8922,-0.4516,0.4516,0.8922,77.2881,457.1406)" font-size="13" @@ -20037,6 +20180,7 @@ + <text transform="matrix(0.8974,-0.4412,0.4412,0.8974,80.0684,455.7334)" font-size="13" @@ -20045,6 +20189,7 @@ + <text transform="matrix(0.907,-0.4212,0.4212,0.907,82.9609,454.2842)" font-size="13" @@ -20053,6 +20198,7 @@ + <text transform="matrix(0.9228,-0.3852,0.3852,0.9228,89.7256,451.1367)" font-size="13" @@ -20061,6 +20207,7 @@ + <ellipse transform="matrix(0.8574,-0.5146,0.5146,0.8574,-242.8069,105.0529)" @@ -20082,6 +20229,7 @@ + <text transform="matrix(0.8483,-0.5295,0.5295,0.8483,55,488.0664)" font-size="13" @@ -20090,6 +20238,7 @@ + <text transform="matrix(0.8561,-0.5168,0.5168,0.8561,60.5156,484.6328)" font-size="13" @@ -20098,6 +20247,7 @@ + <text transform="matrix(0.8636,-0.5042,0.5042,0.8636,66.0996,481.2817)" font-size="13" @@ -20106,6 +20256,7 @@ + <text transform="matrix(0.8679,-0.4968,0.4968,0.8679,68.8008,479.7046)" font-size="13" @@ -20114,6 +20265,7 @@ + <text transform="matrix(0.8745,-0.4851,0.4851,0.8745,71.6055,478.0869)" font-size="13" @@ -20122,6 +20274,7 @@ + <text transform="matrix(0.8837,-0.4681,0.4681,0.8837,77.2861,474.9341)" font-size="13" @@ -20130,6 +20283,7 @@ + <text transform="matrix(0.8936,-0.4488,0.4488,0.8936,83.0342,471.8867)" font-size="13" @@ -20138,6 +20292,7 @@ + </g> <polygon transform="translate(112.94187,-196.20459)" @@ -20202,6 +20357,7 @@ style="font-size:13px;fill:#ffffff;font-family:Baskerville-Bold" x="861.79529" y="497.92188">GA</text> + <g id="g9128" transform="matrix(0.28726254,-0.16540582,0.16575504,0.28632533,425.92965,616.56351)"><path @@ -20308,13 +20464,15 @@ sodipodi:rx="16.200001" sodipodi:ry="16.200001" style="fill:#fede58;stroke:#000000;stroke-linecap:round;stroke-linejoin:round" - d="m 777.06102,691.97198 c 0,8.94702 -7.25298,16.20001 -16.2,16.20001 -8.94701,0 -16.2,-7.25299 -16.2,-16.20001 0,-8.94701 7.25299,-16.2 16.2,-16.2 8.94702,0 16.2,7.25299 16.2,16.2 z" /></g><text + d="m 777.06102,691.97198 c 0,8.94702 -7.25298,16.20001 -16.2,16.20001 -8.94701,0 -16.2,-7.25299 -16.2,-16.20001 0,-8.94701 7.25299,-16.2 16.2,-16.2 8.94702,0 16.2,7.25299 16.2,16.2 z" + transform="translate(-28,16)" /></g><text transform="matrix(0.99997688,0.00679984,-0.00679984,0.99997688,0,0)" font-size="12" id="text7052-4" style="font-size:12.00027752px;font-family:Baskerville-Bold" - x="767.2597" - y="683.37854">SAL</text> + x="739.36945" + y="699.5686">SAL</text> + </g> <g id="player_info" @@ -20466,6 +20624,7 @@ + </g> <g id="Layer_40"> @@ -20554,6 +20713,7 @@ + <ellipse cx="759.93701" cy="369.15601" @@ -20643,6 +20803,7 @@ + <g id="peach"> <g @@ -20995,6 +21156,7 @@ + <ellipse cx="758.375" cy="380.44299" @@ -21060,6 +21222,7 @@ + <ellipse cx="757.867" cy="360.47101" @@ -21155,6 +21318,7 @@ + </g> <g id="_x31_8GA"> @@ -21235,6 +21399,7 @@ + <ellipse cx="749.85901" cy="274.20599" @@ -21296,6 +21461,7 @@ + <ellipse cx="756.77502" cy="336.56" @@ -21343,6 +21509,7 @@ + </g> </g> <text @@ -21357,6 +21524,7 @@ id="tspan7162-7" style="font-size:11.00002861px;font-family:Baskerville-Italic" rotate="0 0 1.705 2.3150001 2.79 3.3710001 3.9660001 4.4679999">$20 cost</tspan></text> + <text style="font-size:12.00003052px" y="760.13715" @@ -21368,6 +21536,7 @@ font-size="11" id="tspan7162-7-0" style="font-size:13px;font-family:Baskerville-Italic">$30, $60</tspan></text> + <text style="font-size:12.00003052px" y="559.35315" @@ -21379,6 +21548,7 @@ font-size="11" id="tspan7162-7-0-4" style="font-size:13px;font-family:Baskerville-Italic">$30, $60</tspan></text> + <text style="font-size:12.00003052px" y="745.6438" @@ -21390,6 +21560,7 @@ font-size="11" id="tspan7162-7-0-4-8" style="font-size:13px;font-family:Baskerville-Italic">Savannah</tspan></text> + <text style="font-size:12.00003052px" y="493.79361" @@ -21401,4 +21572,5 @@ font-size="11" id="tspan7162-7-0-4-8-4" style="font-size:16px;font-family:Baskerville-Italic">Charleston</tspan></text> + </svg> \ No newline at end of file |
From: Frederick W. <fre...@us...> - 2012-01-14 21:19:32
|
rails/ui/swing/ORPanel.java | 2 rails/ui/swing/ORUIManager.java | 40 +++++++++-- rails/ui/swing/UpgradesPanel.java | 8 -- rails/ui/swing/hexmap/GUIHex.java | 23 +++--- rails/ui/swing/hexmap/HexMap.java | 129 +++++++++++++++++++++++++++++++++++--- 5 files changed, 169 insertions(+), 33 deletions(-) New commits: commit cca1aa0b9824993fe84cbdc24262be77bded9815 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 14 22:14:00 2012 +0100 Fixed hex map's dirty regions mgmt (multiple non-intersecting repaints) Before, each layer had a flag whether the image buffer was dirty. Yet, merely having a flag is not enough as several repaints could have been triggered before paintComponent. This means that each layer has to keep track of each dirty region. This is now implemented. diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 0d0c5ec..bfab7d8 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -1223,6 +1223,8 @@ implements ActionListener, KeyListener, RevenueListener { button1.setEnabled(false); orCompIndex = -1; + + orUIManager.getMap().setTrainPaths(null); } // TEMPORARY diff --git a/rails/ui/swing/ORUIManager.java b/rails/ui/swing/ORUIManager.java index 0faaaae..4bed76d 100644 --- a/rails/ui/swing/ORUIManager.java +++ b/rails/ui/swing/ORUIManager.java @@ -1022,6 +1022,8 @@ public class ORUIManager implements DialogOwner { if (orWindow.process(executedAction)) { upgradePanel.clear(); map.selectHex(null); + //ensure painting the token (model update currently does not arrive at UI) + map.repaintTokens(selectedHex.getBounds()); selectedHex = null; } } diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index e220614..5d2188d 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -31,17 +31,118 @@ import rails.util.Util; public abstract class HexMap implements MouseListener, MouseMotionListener { + /** + * class for managing sets of rectangles. Apart from several convenience methods, + * this class aims at keeping the set as minimal as possible. + */ + private class RectangleSet { + private List<Rectangle> rs = new LinkedList<Rectangle>(); + /** + * @param rOp Rectangle to be added to the set. Only added if not contained in + * a rectangle of the set. If added, all of the set's rectangles which are a + * sub-area of this rectangle are dropped (in order to keep the rectangle list + * as small as possible). + */ + public void add(Rectangle rOp) { + // exit if rectangle already contained in set of rectangles + for (Rectangle r : rs) { + if (r.contains(rOp)) return; + } + + // build new set (do not include rectangles contained by new rectangle) + List<Rectangle> newRs = new LinkedList<Rectangle>(); + for (Rectangle r : rs) { + if (!rOp.contains(r)) newRs.add(r); + } + newRs.add(rOp); + rs = newRs; + } + + /** + * As a side-effect, the area defined by the given rectangle is removed from the + * area defined by the set of rectangles. This might lead to splitting the set's + * rectangles if only parts of their areas become removed. + * @return The intersection between the given rectangle and the set of rectangles. + * Returns null if the intersection is empty. + */ + public Rectangle getIntersectionAndRemoveFromSet(Rectangle rOp) { + Rectangle intersection = null; + RectangleSet newRs = new RectangleSet(); + for (Rectangle r : rs) { + Rectangle intersectionPart = null; + + //check for the most common case: set's rectangle is a sub-area + //of the given rectangle (common because repaint creates unions) + //avoid further (complex) processing for this case + if (rOp.contains(r)) { + intersectionPart = r; + } else if (r.intersects(rOp)) { + //update intersection region + intersectionPart = r.intersection(rOp); + + //adjust rectangle: potentially split into 4 sub-rectangles + // *************************** + // * | 3 | * + // * ************* * + // * 1 * rOp * 2 * + // * ************* * + // * | 4 | * + // *************************** + + //region 1 + if (r.x < rOp.x && (r.x + r.width) > rOp.x) { + newRs.add(new Rectangle(r.x,r.y,(rOp.x-r.x),r.height)); + } + //region 2 + if ((r.x + r.width) > (rOp.x + rOp.width) && r.x < (rOp.x + rOp.width)) { + newRs.add(new Rectangle((rOp.x+rOp.width),r.y, + (r.x+r.width-rOp.x-rOp.width),r.height)); + } + //region 3 + if (r.y < rOp.y) { + int x1 = Math.max(r.x, rOp.x); + int x2 = Math.min(r.x+r.width, rOp.x+rOp.width); + if (x1 < x2) newRs.add(new Rectangle(x1,r.y,x2-x1,rOp.y-r.y)); + } + //region 4 + if ((r.y + r.height) > (rOp.y + rOp.height)) { + int x1 = Math.max(r.x, rOp.x); + int x2 = Math.min(r.x+r.width, rOp.x+rOp.width); + if (x1 < x2) newRs.add(new Rectangle(x1,(rOp.y+rOp.height), + x2-x1,(r.y+r.height-rOp.y-rOp.height))); + } + } + + if (intersectionPart == null) { + //if no intersection part, this rectangle remains unchanged in the set + newRs.add(r); + } else { + //expand the intersection region if intersection part found + if (intersection == null) { + intersection = (Rectangle)intersectionPart.clone(); + } else { + intersection.add(intersectionPart); + } + } + } + rs = newRs.rs; + return intersection; + } + } private abstract class HexLayer extends JComponent { private static final long serialVersionUID = 1L; private BufferedImage bufferedImage; - private boolean isBufferDirty = false; + /* + * list of regions for which the layer's image buffer is dirty + */ + private RectangleSet bufferDirtyRegions = new RectangleSet();; protected abstract void paintImage(Graphics g); final public void repaint() { - isBufferDirty = true; + bufferDirtyRegions.add( new Rectangle(0,0,getWidth(),getHeight()) ); super.repaint(); } public void repaint(Rectangle r) { - isBufferDirty = true; + bufferDirtyRegions.add( r ); super.repaint(r); } final public void paintComponent(Graphics g) { @@ -60,18 +161,26 @@ public abstract class HexMap implements MouseListener, || bufferedImage.getHeight() != getHeight() ) { //create new buffer image bufferedImage = new BufferedImage(getWidth(), getHeight(),BufferedImage.TYPE_INT_ARGB); - isBufferDirty = true; + + //clear information of the image buffer's dirty regions + bufferDirtyRegions = new RectangleSet();; + bufferDirtyRegions.add( new Rectangle(0,0,getWidth(),getHeight()) ); //since the buffered image is empty, it has to be completely redrawn rectClip = new Rectangle (0, 0, getWidth(), getHeight()); } - if (isBufferDirty) { + //determine which parts of the clip are dirty and have to be redrawn + Rectangle dirtyClipArea = bufferDirtyRegions.getIntersectionAndRemoveFromSet(rectClip); + if (dirtyClipArea != null) { //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); + imageGraphics.setClip(dirtyClipArea.x, + dirtyClipArea.y, + dirtyClipArea.width, + dirtyClipArea.height); //set the background to transparent so that only drawn parts of the //buffer will be taken over @@ -80,16 +189,18 @@ public abstract class HexMap implements MouseListener, //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); + imageGraphics.clearRect(dirtyClipArea.x, + dirtyClipArea.y, + dirtyClipArea.width, + dirtyClipArea.height); //paint within the buffer paintImage(imageGraphics); imageGraphics.dispose(); - isBufferDirty = false; } - //buffer is valid and can be used + //now 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); commit 4c1048ef3816c429aa208275985c2725a6faf892 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 14 18:09:08 2012 +0100 Excluded layable tiles from upgrade panel if no valid rotation exists Before, selecting a tile of the upgrade panel could lead to the message "This tile cannot be laid in a valid orientation." Now, tiles are excluded from the upgrade panel selection if such message would be issued upon clicking on them. Stated differently, every tile listed in the upgrade panel can now be laid by the user. diff --git a/rails/ui/swing/ORUIManager.java b/rails/ui/swing/ORUIManager.java index 410605e..0faaaae 100644 --- a/rails/ui/swing/ORUIManager.java +++ b/rails/ui/swing/ORUIManager.java @@ -705,12 +705,7 @@ public class ORUIManager implements DialogOwner { } // Check if the new tile must be connected to some other track - boolean mustConnect = - tile.getColourName().equalsIgnoreCase(Tile.YELLOW_COLOUR_NAME) - // Does not apply to the current company's home hex(es) - && !hex.getHexModel().isHomeFor(orComp) - // Does not apply to special tile lays - && !isUnconnectedTileLayTarget(hex); + boolean mustConnect = getMustConnectRequirement(hex,tile); if (hex.dropTile(tileId, mustConnect)) { /* Lay tile */ @@ -724,13 +719,38 @@ public class ORUIManager implements DialogOwner { upgradePanel.showUpgrades(); } } + + private boolean getMustConnectRequirement (GUIHex hex,TileI tile) { + if (tile == null || hex == null) return false; + return tile.getColourName().equalsIgnoreCase(Tile.YELLOW_COLOUR_NAME) + // Does not apply to the current company's home hex(es) + && !hex.getHexModel().isHomeFor(orComp) + // Does not apply to special tile lays + && !isUnconnectedTileLayTarget(hex.getHexModel()); + } + + public void addTileUpgradeIfValid(GUIHex hex, int tileId) { + addTileUpgradeIfValid (hex, + gameUIManager.getGameManager().getTileManager().getTile(tileId)); + } + + public void addTileUpgradeIfValid(GUIHex hex, TileI tile) { + if (!tileUpgrades.contains(tile) && isTileUpgradeValid(hex,tile)) { + tileUpgrades.add(tile); + } + } + + private boolean isTileUpgradeValid(GUIHex hex, TileI tile) { + // Check if the new tile must be connected to some other track + return hex.isTileUpgradeValid(tile.getId(), + getMustConnectRequirement(hex,tile)); + } - protected boolean isUnconnectedTileLayTarget(GUIHex hex) { + protected boolean isUnconnectedTileLayTarget(MapHex hex) { - MapHex mapHex = hex.getHexModel(); for (LayTile action : possibleActions.getType(LayTile.class)) { if (action.getType() == LayTile.SPECIAL_PROPERTY - && action.getSpecialProperty().getLocations().contains(mapHex)) { + && action.getSpecialProperty().getLocations().contains(hex)) { // log.debug(hex.getName()+" is a special property target"); return true; } diff --git a/rails/ui/swing/UpgradesPanel.java b/rails/ui/swing/UpgradesPanel.java index 4ff56e8..7c67112 100644 --- a/rails/ui/swing/UpgradesPanel.java +++ b/rails/ui/swing/UpgradesPanel.java @@ -98,16 +98,14 @@ public class UpgradesPanel extends Box implements MouseListener, ActionListener // Skip if not allowed in LayTile //if (!layTile.isTileColourAllowed(tile.getColourName())) continue; - if (!orUIManager.tileUpgrades.contains(tile) && layTile.isTileColourAllowed(tile.getColourName())) - orUIManager.tileUpgrades.add(tile); + if (layTile.isTileColourAllowed(tile.getColourName())) + orUIManager.addTileUpgradeIfValid(uiHex,tile); } } else { for (TileI tile : tiles) { // Skip if colour is not allowed yet if (!allowedColours.contains(tile.getColourName())) continue; - - if (!orUIManager.tileUpgrades.contains(tile)) - orUIManager.tileUpgrades.add(tile); + orUIManager.addTileUpgradeIfValid(uiHex,tile); } } } diff --git a/rails/ui/swing/hexmap/GUIHex.java b/rails/ui/swing/hexmap/GUIHex.java index 52165a7..f67de31 100644 --- a/rails/ui/swing/hexmap/GUIHex.java +++ b/rails/ui/swing/hexmap/GUIHex.java @@ -879,21 +879,24 @@ public class GUIHex implements ViewObject { public boolean dropTile(int tileId, boolean upgradeMustConnect) { this.upgradeMustConnect = upgradeMustConnect; - provisionalGUITile = new GUITile(tileId, this); - /* Check if we can find a valid orientation of this tile */ - if (provisionalGUITile.rotate(0, currentGUITile, upgradeMustConnect)) { - /* If so, accept it */ + provisionalGUITile = createUpgradeTileIfValid (tileId, upgradeMustConnect); + if (provisionalGUITile != null) { provisionalGUITile.setScale(SELECTED_SCALE); toolTip = "Click to rotate"; hexMap.repaintMarks(getBounds()); hexMap.repaintTiles(getBounds()); // provisional tile resides in tile layer - return true; - } else { - /* If not, refuse it */ - provisionalGUITile = null; - return false; } - + return (provisionalGUITile != null); + } + + private GUITile createUpgradeTileIfValid (int tileId, boolean upgradeMustConnect) { + GUITile t = new GUITile(tileId, this); + /* Check if we can find a valid orientation of this tile */ + return ( t.rotate(0, currentGUITile, upgradeMustConnect) ? t : null); + } + + public boolean isTileUpgradeValid (int tileId, boolean upgradeMustConnect) { + return ( createUpgradeTileIfValid(tileId, upgradeMustConnect) != null ); } /** forces the tile to drop */ |
From: Frederick W. <fre...@us...> - 2012-01-13 20:26:14
|
rails/ui/swing/GUIToken.java | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) New commits: commit 9d1152f5efce158c43ebf25a984ba89a35cf5502 Author: Frederick Weld <fre...@gm...> Date: Fri Jan 13 21:24:04 2012 +0100 Enhanced readability of token texts (condensed, multi-line) Texts containing 3 characters are displayed in condensed mode. Texts with more than 4 characters are split into two lines. With these changes, 1830 labels are readable on 800x600. diff --git a/rails/ui/swing/GUIToken.java b/rails/ui/swing/GUIToken.java index 5a02f08..7e07c63 100644 --- a/rails/ui/swing/GUIToken.java +++ b/rails/ui/swing/GUIToken.java @@ -2,8 +2,11 @@ package rails.ui.swing; import java.awt.*; +import java.awt.font.TextAttribute; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; +import java.util.HashMap; +import java.util.Map; import javax.swing.JPanel; @@ -109,19 +112,41 @@ public class GUIToken extends JPanel { public static void drawTokenText (String text, Graphics g, Color c, Point tokenCenter, double tokenDiameter) { + //recursion if text contains more than 3 characters + //not perfect (heuristic!) but good enough for this exceptional case + if (text.length() > 3) { + drawTokenText( text.substring(0, text.length() / 2), g, c, + new Point (tokenCenter.x, (int)((double)tokenCenter.y - tokenDiameter / 4 / 1.3)), + tokenDiameter / 2 / (1 - tokenTextMargin) * 1.2); + drawTokenText( text.substring(text.length() / 2, text.length()), g, c, + new Point (tokenCenter.x, (int)((double)tokenCenter.y + tokenDiameter / 4 * 1.1)), + tokenDiameter / 2 / (1 - tokenTextMargin) * 1.2); + return; + } + + //create condensed font if more than 2 chars in a line + Font fontTemplate; + if (text.length() > 2) { + Map<TextAttribute, Object> attributes = new HashMap<TextAttribute, Object>(); + attributes.put(TextAttribute.WIDTH, TextAttribute.WIDTH_CONDENSED); + fontTemplate = tokenFontTemplate.deriveFont(attributes); + } else { + fontTemplate = tokenFontTemplate; + } + //first calculate font size double allowedTextDiameter = tokenDiameter * (1 - tokenTextMargin); - Rectangle2D textBoundsInTemplate = g.getFontMetrics(tokenFontTemplate).getStringBounds(text, g); + Rectangle2D textBoundsInTemplate = g.getFontMetrics(fontTemplate).getStringBounds(text, g); double fontScalingX = allowedTextDiameter / textBoundsInTemplate.getWidth(); double fontScalingY = allowedTextDiameter / textBoundsInTemplate.getHeight(); double fontScaling = (fontScalingX < fontScalingY) ? fontScalingX : fontScalingY; - int fontSize = (int) Math.floor(fontScaling * tokenFontTemplate.getSize()); + int fontSize = (int) Math.floor(fontScaling * fontTemplate.getSize()); //draw text Color oldColor = g.getColor(); Font oldFont = g.getFont(); g.setColor(c); - g.setFont(tokenFontTemplate.deriveFont((float)fontSize)); //float needed to indicate size (not style) + g.setFont(fontTemplate.deriveFont((float)fontSize)); //float needed to indicate size (not style) Rectangle2D textBounds = g.getFontMetrics().getStringBounds(text, g); g.drawString(text, tokenCenter.x - (int)textBounds.getCenterX(), |
From: Frederick W. <fre...@us...> - 2012-01-13 17:50:42
|
rails/ui/swing/MapPanel.java | 6 ++- rails/ui/swing/MessagePanel.java | 75 +++++++++++++++++++++++++++----------- rails/ui/swing/ORPanel.java | 4 +- rails/ui/swing/ORUIManager.java | 26 +++++++++---- rails/ui/swing/ORWindow.java | 7 --- rails/ui/swing/hexmap/HexMap.java | 33 +++++++++++++++- 6 files changed, 110 insertions(+), 41 deletions(-) New commits: commit 4cdf576bea5a4364d278af8dc6f736b6b4868624 Author: Frederick Weld <fre...@gm...> Date: Fri Jan 13 18:47:21 2012 +0100 Enlarged message panel for route details Upon click details, the message panel's height is now increased. In addition, the bug of duplicating message contents for set revenue is fixed. diff --git a/rails/ui/swing/MessagePanel.java b/rails/ui/swing/MessagePanel.java index 6e8e1fc..6c50471 100644 --- a/rails/ui/swing/MessagePanel.java +++ b/rails/ui/swing/MessagePanel.java @@ -2,10 +2,9 @@ package rails.ui.swing; import java.awt.Color; +import java.awt.Dimension; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import java.util.ArrayList; -import java.util.List; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -14,14 +13,20 @@ public class MessagePanel extends JPanel { private static final long serialVersionUID = 1L; //the height of this panel (fixed because scroll bar is used) - public static final int fixedHeight = 45; + public static final int defaultHeight = 45; + + //the height of this panel if details are open + public static final int fullHeight = 90; + public static final int minWidth = 100; public static final int scrollUnit = 8; + public static final int minMarginForFullHeight = 8; private JLabel message; + private JScrollPane parentSlider; private String currentMessage; private StringBuffer currentInformation; - private List<String> currentDetails = new ArrayList<String>(); + private String currentDetails; private boolean showDetails; Color background = new Color(225, 225, 225); @@ -44,8 +49,7 @@ public class MessagePanel extends JPanel { this.addMouseListener(new MouseListener() { public void mouseClicked(MouseEvent arg0) { - showDetails = !showDetails; - updateMessageText(); + toggleDetailsEnablement(); } public void mouseEntered(MouseEvent arg0) {} @@ -56,6 +60,41 @@ public class MessagePanel extends JPanel { } + /** + * @param parentSlider Component between OR window and the panel + */ + public void setParentSlider(JScrollPane parentSlider) { + this.parentSlider = parentSlider; + parentSlider.setBorder(BorderFactory.createLoweredBevelBorder()); + parentSlider.getVerticalScrollBar().setUnitIncrement(scrollUnit); + parentSlider.setPreferredSize(new Dimension(minWidth,defaultHeight)); + } + + private void disableDetails() { + if (showDetails) { + showDetails = false; + parentSlider.setPreferredSize(new Dimension(minWidth,defaultHeight)); + parentSlider.getParent().revalidate(); + } + } + + private void enableDetails() { + if (!showDetails && currentDetails != null) { + showDetails = true; + parentSlider.setPreferredSize(new Dimension(minWidth,fullHeight)); + parentSlider.getParent().revalidate(); + } + } + + private void toggleDetailsEnablement() { + if (showDetails) { + disableDetails(); + } else { + enableDetails(); + } + updateMessageText(); + } + private void updateMessageText() { StringBuffer messageText = new StringBuffer() ; if (currentMessage != null) { @@ -68,19 +107,15 @@ public class MessagePanel extends JPanel { } if (showDetails) { messageText.append("<span style='color:blue; font-size:80%'>"); - for (String detail:currentDetails) { - messageText.append(detail); - } + messageText.append(currentDetails); messageText.append("</span>"); - } else if (currentDetails.size() != 0) { + } else if (currentDetails != null) { messageText.append("<span style='color:blue; font-size:80%'>"); - messageText.append("<BR> Click for more details"); + messageText.append(" Click for more details"); messageText.append("</span>"); } // display String text = messageText.toString(); - //int lines = text.split("<[Bb][Rr]>").length + 1; -// setLines(lines); message.setText("<html><center>" + text + "</center></html>"); } @@ -88,21 +123,19 @@ public class MessagePanel extends JPanel { public void setMessage(String messageText) { currentMessage = messageText; currentInformation = null; - currentDetails.clear(); - showDetails = false; + currentDetails = null; + disableDetails(); updateMessageText(); } - public void addInformation(String infoText) { - if (currentInformation == null) { - currentInformation = new StringBuffer(); - } + public void setInformation(String infoText) { + currentInformation = new StringBuffer(); currentInformation.append("<BR>" + infoText); updateMessageText(); } - public void addDetail(String detailText) { - currentDetails.add("<BR>" + detailText); + public void setDetail(String detailText) { + currentDetails = "<BR>" + detailText; updateMessageText(); } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index b2251c3..0d0c5ec 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -1055,9 +1055,9 @@ implements ActionListener, KeyListener, RevenueListener { orUIManager.getMap().setTrainPaths(null); revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); if (isRevenueValueToBeSet) { - orUIManager.addInformation("Best Run Value = " + bestRevenue + + orUIManager.setInformation("Best Run Value = " + bestRevenue + " with " + Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(false))); - orUIManager.addDetail(Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(true))); + orUIManager.setDetail(Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(true))); } } } diff --git a/rails/ui/swing/ORUIManager.java b/rails/ui/swing/ORUIManager.java index a7bef1c..410605e 100644 --- a/rails/ui/swing/ORUIManager.java +++ b/rails/ui/swing/ORUIManager.java @@ -1934,12 +1934,12 @@ public class ORUIManager implements DialogOwner { messagePanel.setMessage(message); } - public void addInformation(String infoText) { - messagePanel.addInformation(infoText); + public void setInformation(String infoText) { + messagePanel.setInformation(infoText); } - public void addDetail(String detailText) { - messagePanel.addDetail(detailText); + public void setDetail(String detailText) { + messagePanel.setDetail(detailText); } public void setLocalAction(boolean value) { diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index c0a162f..5c6f5bb 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -2,13 +2,11 @@ package rails.ui.swing; import java.awt.BorderLayout; -import java.awt.Dimension; import java.awt.Rectangle; import java.awt.event.*; import java.util.ArrayList; import java.util.List; -import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JScrollPane; @@ -65,9 +63,7 @@ public class ORWindow extends JFrame implements ActionPerformer { messagePanel = new MessagePanel(); JScrollPane slider = new JScrollPane(messagePanel); - slider.setBorder(BorderFactory.createLoweredBevelBorder()); - slider.getVerticalScrollBar().setUnitIncrement(MessagePanel.scrollUnit); - slider.setPreferredSize(new Dimension(100,MessagePanel.fixedHeight)); + messagePanel.setParentSlider(slider); getContentPane().add(slider, BorderLayout.NORTH); commit d011569730b37316997b35d67778dcd2014ba6cb Author: Frederick Weld <fre...@gm...> Date: Fri Jan 13 17:13:24 2012 +0100 Configured tooltips such that they remain visible forever unless mouse move Upon Erik's request: tool tip dismiss delay is on infinity. diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index 7f19442..265defe 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -64,6 +64,9 @@ public class MapPanel extends JPanel { //lightwight tooltip possible since tool tip has its own layer in hex map ToolTipManager.sharedInstance().setLightWeightPopupEnabled(true); + //tooltip should not be dismissed after at all + ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE); + layeredPane = new JLayeredPane(); layeredPane.setLayout(null); layeredPane.setPreferredSize(originalMapSize); commit 115afe5d4f7d12f6e8109e4f1e7aebd190979039 Author: Frederick Weld <fre...@gm...> Date: Fri Jan 13 17:07:44 2012 +0100 Polished hex map tool tips (lightwight tooltips, tooltip upon click) - mouseover on tooltip no longer leads to no highlighted hex (put tooltips as lightwight - possible due to new hexmap layering) - clicking on hex without associated action does not lead to disappearance of tooltip diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index 66c81d6..7f19442 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -61,7 +61,8 @@ public class MapPanel extends JPanel { return; } - ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false); + //lightwight tooltip possible since tool tip has its own layer in hex map + ToolTipManager.sharedInstance().setLightWeightPopupEnabled(true); layeredPane = new JLayeredPane(); layeredPane.setLayout(null); diff --git a/rails/ui/swing/ORUIManager.java b/rails/ui/swing/ORUIManager.java index a097bf7..a7bef1c 100644 --- a/rails/ui/swing/ORUIManager.java +++ b/rails/ui/swing/ORUIManager.java @@ -600,9 +600,15 @@ public class ORUIManager implements DialogOwner { if (!(dialog instanceof MessageDialog)) orPanel.disableButtons(); } - public void hexClicked(GUIHex clickedHex, GUIHex selectedHex) { + /** + * @return True if the map panel expected hex clicks for actions / corrections + */ + public boolean hexClicked(GUIHex clickedHex, GUIHex selectedHex) { + boolean triggerORPanelRepaint = false; + if (mapCorrectionEnabled) { + triggerORPanelRepaint = true; boolean checkClickedHex = false; switch (mapCorrectionAction.getStep()) { case SELECT_HEX: @@ -622,11 +628,12 @@ public class ORUIManager implements DialogOwner { orWindow.process(mapCorrectionAction); } } else if (tokenLayingEnabled) { + triggerORPanelRepaint = true; // if clickedHex == null, then go back to select hex step if (clickedHex == null) { upgradePanel.setPossibleTokenLays(null); setLocalStep(SELECT_HEX_FOR_TOKEN); - return; + return true; } List<LayToken> allowances = map.getTokenAllowanceForHex(clickedHex.getHexModel()); @@ -645,10 +652,11 @@ public class ORUIManager implements DialogOwner { } } else if (tileLayingEnabled) { + triggerORPanelRepaint = true; if (localStep == ROTATE_OR_CONFIRM_TILE && clickedHex == selectedHex) { selectedHex.rotateTile(); - return; + return true; } else { if (selectedHex != null && clickedHex != selectedHex) { @@ -676,7 +684,9 @@ public class ORUIManager implements DialogOwner { } } - orWindow.repaintORPanel(); + if (triggerORPanelRepaint) orWindow.repaintORPanel(); + + return triggerORPanelRepaint; } public void tileSelected(int tileId) { diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index dcef993..c0a162f 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -12,7 +12,6 @@ import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JScrollPane; -import javax.swing.border.EmptyBorder; import org.apache.log4j.Logger; diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index 6029c93..e220614 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -780,7 +780,7 @@ public abstract class HexMap implements MouseListener, // } // do nothing as tooltip update before display } - + /** * Mouse Listener methods (hexMap offers listener for all layers) */ @@ -789,7 +789,34 @@ public abstract class HexMap implements MouseListener, Point point = arg0.getPoint(); GUIHex clickedHex = getHexContainingPoint(point); - orUIManager.hexClicked(clickedHex, selectedHex); + //if no action/correction was expected on the map panel + if (!orUIManager.hexClicked(clickedHex, selectedHex)) { + + // force the tool tip popup to appear immediately + ToolTipManager ttm = ToolTipManager.sharedInstance(); + MouseEvent phantomME = new MouseEvent( + toolTipsLayer, + MouseEvent.MOUSE_MOVED, + System.currentTimeMillis(), + 0, + arg0.getX(), + arg0.getY(), + 0, + false); + + int priorToolTipDelay = ttm.getInitialDelay(); + ttm.setInitialDelay(0); + ttm.mouseMoved(phantomME); + ttm.setInitialDelay(priorToolTipDelay); + +// int priorToolTipDelay = ttm.getInitialDelay(); +// ttm.mouseEntered(new MouseAdapter()); +// ToolTipManager.sharedInstance().setInitialDelay(0); +// try { +// this.wait(1); +// } catch (InterruptedException e) {} +// map = map; + } } public void mouseDragged(MouseEvent arg0) {} @@ -806,7 +833,7 @@ public abstract class HexMap implements MouseListener, if (newHex != null) newHex.addHighlightRequest(); //display tool tip - setToolTipText(newHex != null ? newHex.getToolTip() : ""); + setToolTipText(newHex != null ? newHex.getToolTip() : null); hexAtMousePosition = newHex; } |
From: Frederick W. <fre...@us...> - 2012-01-12 15:17:30
|
rails/ui/swing/hexmap/HexMapImage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) New commits: commit 37094a814afed9d7da83d61d68c2fdd85293ae25 Author: Frederick Weld <fre...@gm...> Date: Thu Jan 12 16:07:48 2012 +0100 Fixed missing initial map image scaling (if no auto-zoom configured) diff --git a/rails/ui/swing/hexmap/HexMapImage.java b/rails/ui/swing/hexmap/HexMapImage.java index ec64685..b8e95f4 100644 --- a/rails/ui/swing/hexmap/HexMapImage.java +++ b/rails/ui/swing/hexmap/HexMapImage.java @@ -87,7 +87,7 @@ public final class HexMapImage extends JSVGCanvas { initialized = true; //catch up on setting the bounds (if bounds setting were called before rendering prepare) - if (initialMapSize != null) setBoundsAndResize(initialMapSize,initialZoomStep); + setBoundsAndResize(hexMap.getCurrentSize(),hexMap.getZoomStep()); } addGVTTreeRendererListener(null); } |
From: Erik V. <ev...@us...> - 2012-01-12 15:07:15
|
rails/ui/swing/GameStatus.java | 1 rails/ui/swing/ORPanel.java | 193 ++++---- rails/ui/swing/ORUIManager.java | 325 +++++++------- rails/ui/swing/StartRoundWindow.java | 7 rails/ui/swing/StatusWindow.java | 86 +-- rails/ui/swing/gamespecific/_1835/StatusWindow_1835.java | 25 - rails/ui/swing/gamespecific/_1856/StatusWindow_1856.java | 18 rails/ui/swing/gamespecific/_18EU/GameStatus_18EU.java | 8 rails/ui/swing/gamespecific/_18EU/GameUIManager_18EU.java | 110 ++-- 9 files changed, 397 insertions(+), 376 deletions(-) New commits: commit 80327b9fd861613e417dbdbe76aec32703ec16cf Author: Erik Vos <eri...@xs...> Date: Thu Jan 12 16:05:58 2012 +0100 Disable buttons on non-modal popups. diff --git a/rails/ui/swing/GameStatus.java b/rails/ui/swing/GameStatus.java index bab6fb0..6cc5c2e 100644 --- a/rails/ui/swing/GameStatus.java +++ b/rails/ui/swing/GameStatus.java @@ -746,6 +746,7 @@ public class GameStatus extends GridPanel implements ActionListener { companyName), options.toArray(new String[0]), -1); gameUIManager.setCurrentDialog(dialog, actions.get(0)); + parent.disableButtons(); return; } else { String sp = diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index e8f8254..b2251c3 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -9,7 +9,6 @@ import java.util.List; import javax.swing.*; import org.apache.log4j.Logger; - import org.jgrapht.graph.SimpleGraph; import rails.algorithms.*; @@ -61,7 +60,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; @@ -102,7 +101,7 @@ implements ActionListener, KeyListener, RevenueListener { private boolean hasRights; private Caption tileCaption, tokenCaption, revenueCaption, trainCaption, - privatesCaption, loansCaption; + privatesCaption, loansCaption; private ActionButton buttonOC; // sfy: button for operating costs private ActionButton button1; @@ -116,13 +115,13 @@ implements ActionListener, KeyListener, RevenueListener { private int orCompIndex = -1; private PublicCompanyI orComp = null; - + private boolean isRevenueValueToBeSet = false; private RevenueAdapter revenueAdapter = null; private Thread revenueThread = null; protected static Logger log = - Logger.getLogger(ORPanel.class.getPackage().getName()); + Logger.getLogger(ORPanel.class.getPackage().getName()); public ORPanel(ORWindow parent, ORUIManager orUIManager) { super(); @@ -141,7 +140,7 @@ implements ActionListener, KeyListener, RevenueListener { parentFrame = parent; round = gameUIManager.getCurrentRound(); -// noMapMode = gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.NO_MAP_MODE); + // noMapMode = gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.NO_MAP_MODE); privatesCanBeBought = gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.CAN_ANY_COMPANY_BUY_PRIVATES); bonusTokensExist = gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.DO_BONUS_TOKENS_EXIST); hasCompanyLoans = gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.HAS_ANY_COMPANY_LOANS); @@ -168,7 +167,7 @@ implements ActionListener, KeyListener, RevenueListener { infoMenu = new JMenu(LocalText.getText("Info")); infoMenu.setEnabled(true); remainingTilesMenuItem = - new JMenuItem(LocalText.getText("RemainingTiles")); + new JMenuItem(LocalText.getText("RemainingTiles")); remainingTilesMenuItem.addActionListener(this); remainingTilesMenuItem.setActionCommand(REM_TILES_CMD); infoMenu.add(remainingTilesMenuItem); @@ -240,14 +239,14 @@ implements ActionListener, KeyListener, RevenueListener { JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(name); menuItem.addActionListener(this); menuItem.setEnabled(true); - + //check whether this is the default fit to option if (name.equalsIgnoreCase(Config.get("map.defaultZoomFitOption"))) { menuItem.setSelected(true); } return menuItem; } - + public void recreate(OperatingRound or) { log.debug("ORPanel.recreate() called"); @@ -260,11 +259,11 @@ implements ActionListener, KeyListener, RevenueListener { // Create new fields initFields(); - + // update the networkInfo menu // TODO: This relies on a recreate as soon as companies have changed addNetworkInfo(); - + repaint(); } @@ -333,7 +332,7 @@ implements ActionListener, KeyListener, RevenueListener { public void mouseReleased(MouseEvent e) {} }; } - + private void initFields() { leftCompName = new Caption[nc]; rightCompName = new Caption[nc]; @@ -360,7 +359,7 @@ implements ActionListener, KeyListener, RevenueListener { leftCompNameYOffset = 2; int currentXOffset = leftCompNameXOffset; int lastXWidth = 0; - + MouseListener companyCaptionMouseClickListener = getCompanyCaptionMouseClickListener(); /* Top titles */ @@ -399,7 +398,7 @@ implements ActionListener, KeyListener, RevenueListener { addField (loansCaption = new Caption(LocalText.getText("LOANS")), loansXOffset, 0, lastXWidth = 1, 2, WIDE_RIGHT); } - + if (hasRights) { rightsXOffset = currentXOffset += lastXWidth; rightsYOffset = leftCompNameYOffset; @@ -413,7 +412,7 @@ implements ActionListener, KeyListener, RevenueListener { lastXWidth = 2, 1, WIDE_RIGHT); addField(new Caption("laid"), tilesXOffset, 1, 1, 1, WIDE_BOTTOM); addField(new Caption("cost"), tilesXOffset + 1, 1, 1, 1, WIDE_BOTTOM - + WIDE_RIGHT); + + WIDE_RIGHT); tokensXOffset = currentXOffset += lastXWidth; tokensYOffset = leftCompNameYOffset; @@ -435,7 +434,7 @@ implements ActionListener, KeyListener, RevenueListener { lastXWidth = 2, 1, WIDE_RIGHT); addField(new Caption("earned"), revXOffset, 1, 1, 1, WIDE_BOTTOM); addField(new Caption("payout"), revXOffset + 1, 1, 1, 1, WIDE_BOTTOM - + WIDE_RIGHT); + + WIDE_RIGHT); trainsXOffset = currentXOffset += lastXWidth; trainsYOffset = leftCompNameYOffset; @@ -443,7 +442,7 @@ implements ActionListener, KeyListener, RevenueListener { lastXWidth = 2, 1, WIDE_RIGHT); addField(new Caption("owned"), trainsXOffset, 1, 1, 1, WIDE_BOTTOM); addField(new Caption("cost"), trainsXOffset + 1, 1, 1, 1, WIDE_BOTTOM - + WIDE_RIGHT); + + WIDE_RIGHT); rightCompNameXOffset = currentXOffset += lastXWidth; rightCompNameYOffset = leftCompNameYOffset; @@ -456,7 +455,7 @@ implements ActionListener, KeyListener, RevenueListener { for (int i = 0; i < nc; i++) { c = companies[i]; rowVisibilityObservers[i] - = new RowVisibility (this, leftCompNameYOffset + i, c.getInGameModel(), true); + = new RowVisibility (this, leftCompNameYOffset + i, c.getInGameModel(), true); observers.add(rowVisibilityObservers[i]); boolean visible = !c.isClosed(); @@ -465,17 +464,17 @@ implements ActionListener, KeyListener, RevenueListener { f.setBackground(c.getBgColour()); f.setForeground(c.getFgColour()); HexHighlightMouseListener.addMouseListener(f, - orUIManager,(PublicCompanyI)c,false); + orUIManager,c,false); f.addMouseListener(companyCaptionMouseClickListener); f.setToolTipText(LocalText.getText("NetworkInfoDialogTitle",c.getName())); addField(f, leftCompNameXOffset, leftCompNameYOffset + i, 1, 1, WIDE_RIGHT, visible); f = - president[i] = -// new Field(c.hasStarted() && !c.isClosed() -// ? c.getPresident().getNameAndPriority() : ""); - new Field(c.getPresidentModel()); + president[i] = + // new Field(c.hasStarted() && !c.isClosed() + // ? c.getPresident().getNameAndPriority() : ""); + new Field(c.getPresidentModel()); addField(f, presidentXOffset, presidentYOffset + i, 1, 1, 0, visible); f = sharePrice[i] = new Field(c.getCurrentPriceModel()); @@ -486,17 +485,17 @@ implements ActionListener, KeyListener, RevenueListener { if (privatesCanBeBought) { f = - privates[i] = - new Field( - c.getPortfolio().getPrivatesOwnedModel()); + privates[i] = + new Field( + c.getPortfolio().getPrivatesOwnedModel()); HexHighlightMouseListener.addMouseListener(f, orUIManager,c.getPortfolio()); addField(f, privatesXOffset, privatesYOffset + i, 1, 1, WIDE_RIGHT, visible); f = - newPrivatesCost[i] = - new Field(c.getPrivatesSpentThisTurnModel()); + newPrivatesCost[i] = + new Field(c.getPrivatesSpentThisTurnModel()); addField(f, privatesXOffset + 1, privatesYOffset + i, 1, 1, WIDE_RIGHT, visible); } @@ -510,7 +509,7 @@ implements ActionListener, KeyListener, RevenueListener { } addField (f, loansXOffset, loansYOffset + i, 1, 1, WIDE_RIGHT, visible); } - + if (hasRights) { f = rights[i] = new Field (c.getRightsModel()); addField (f, rightsXOffset, rightsYOffset + i, 1, 1, WIDE_RIGHT, visible); @@ -560,7 +559,7 @@ implements ActionListener, KeyListener, RevenueListener { f.setBackground(companies[i].getBgColour()); f.setForeground(companies[i].getFgColour()); HexHighlightMouseListener.addMouseListener(f, - orUIManager,(PublicCompanyI)c,false); + orUIManager,c,false); f.addMouseListener(companyCaptionMouseClickListener); f.setToolTipText(LocalText.getText("NetworkInfoDialogTitle",c.getName())); addField(f, rightCompNameXOffset, rightCompNameYOffset + i, 1, 1, 0, visible); @@ -571,30 +570,30 @@ implements ActionListener, KeyListener, RevenueListener { protected void addCompanyInfo() { - CompanyManagerI cm = orUIManager.getGameUIManager().getGameManager().getCompanyManager(); - List<CompanyTypeI> comps = cm.getCompanyTypes(); - JMenu compMenu, menu, item; + CompanyManagerI cm = orUIManager.getGameUIManager().getGameManager().getCompanyManager(); + List<CompanyTypeI> comps = cm.getCompanyTypes(); + JMenu compMenu, menu, item; compMenu = new JMenu(LocalText.getText("Companies")); compMenu.setEnabled(true); infoMenu.add(compMenu); - for (CompanyTypeI type : comps) { - menu = new JMenu (LocalText.getText(type.getName())); - menu.setEnabled(true); + for (CompanyTypeI type : comps) { + menu = new JMenu (LocalText.getText(type.getName())); + menu.setEnabled(true); compMenu.add(menu); - for (CompanyI comp : type.getCompanies()) { - item = new JMenu(comp.getName()); - item.setEnabled(true); - JMenuItem menuItem = new JMenuItem(comp.getInfoText()); - if (comp instanceof PrivateCompanyI) { - //highlighting on menu items always enabled irrespective of config + for (CompanyI comp : type.getCompanies()) { + item = new JMenu(comp.getName()); + item.setEnabled(true); + JMenuItem menuItem = new JMenuItem(comp.getInfoText()); + if (comp instanceof PrivateCompanyI) { + //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, @@ -603,9 +602,9 @@ implements ActionListener, KeyListener, RevenueListener { orUIManager,(PublicCompanyI)comp,true); } item.add(menuItem); - menu.add(item); - } - } + menu.add(item); + } + } } protected void addTrainsInfo() { @@ -670,16 +669,16 @@ implements ActionListener, KeyListener, RevenueListener { networkInfoMenu.setEnabled(true); infoMenu.add(networkInfoMenu); } - + protected JMenu createNetworkInfo() { boolean route_highlight = orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.ROUTE_HIGHLIGHT); - boolean revenue_suggest = orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.REVENUE_SUGGEST); - - if (!route_highlight && !revenue_suggest) return null; - + boolean revenue_suggest = orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.REVENUE_SUGGEST); + + if (!route_highlight && !revenue_suggest) return null; + JMenu networkMenu = new JMenu(LocalText.getText("NetworkInfo")); - + //network graphs only for developers if (route_highlight && Game.getDevelop()) { JMenuItem item = new JMenuItem("Network"); @@ -687,7 +686,7 @@ implements ActionListener, KeyListener, RevenueListener { item.setActionCommand(NETWORK_INFO_CMD); networkMenu.add(item); } - + if (revenue_suggest) { CompanyManagerI cm = orUIManager.getGameUIManager().getGameManager().getCompanyManager(); for (PublicCompanyI comp : cm.getAllPublicCompanies()) { @@ -698,35 +697,35 @@ implements ActionListener, KeyListener, RevenueListener { networkMenu.add(item); } } - + return networkMenu; } - + protected void executeNetworkInfo(String companyName) { GameManagerI gm = orUIManager.getGameUIManager().getGameManager(); - + if (companyName.equals("Network")) { NetworkGraphBuilder nwGraph = NetworkGraphBuilder.create(gm); SimpleGraph<NetworkVertex, NetworkEdge> mapGraph = nwGraph.getMapGraph(); - -// NetworkGraphBuilder.visualize(mapGraph, "Map Network"); + + // NetworkGraphBuilder.visualize(mapGraph, "Map Network"); mapGraph = NetworkGraphBuilder.optimizeGraph(mapGraph); NetworkGraphBuilder.visualize(mapGraph, "Optimized Map Network"); } 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) + //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); -// companyGraph.createRouteGraph(false); -// companyGraph.createRevenueGraph(new ArrayList<NetworkVertex>()); -// Multigraph<NetworkVertex, NetworkEdge> graph= companyGraph.createPhaseTwoGraph(); -// NetworkGraphBuilder.visualize(graph, "Phase Two Company Network"); -// JOptionPane.showMessageDialog(orWindow, -// "Vertices = " + graph.vertexSet().size() + ", Edges = " + graph.edgeSet().size()); + // + // NetworkGraphBuilder nwGraph = NetworkGraphBuilder.create(gm); + // NetworkCompanyGraph companyGraph = NetworkCompanyGraph.create(nwGraph, company); + // companyGraph.createRouteGraph(false); + // companyGraph.createRevenueGraph(new ArrayList<NetworkVertex>()); + // Multigraph<NetworkVertex, NetworkEdge> graph= companyGraph.createPhaseTwoGraph(); + // NetworkGraphBuilder.visualize(graph, "Phase Two Company Network"); + // JOptionPane.showMessageDialog(orWindow, + // "Vertices = " + graph.vertexSet().size() + ", Edges = " + graph.edgeSet().size()); List<String> addTrainList = new ArrayList<String>(); boolean anotherTrain = true; RevenueAdapter ra = null; @@ -742,24 +741,24 @@ implements ActionListener, KeyListener, RevenueListener { log.debug("Revenue Value:" + revenueValue); log.debug("Revenue Run:" + ra.getOptimalRunPrettyPrint(true)); ra.drawOptimalRunAsPath(orUIManager.getMap()); - + if (!Game.getDevelop()) { //parent component is ORPanel so that dialog won't hide the routes painted on the map - JOptionPane.showMessageDialog(this, + JOptionPane.showMessageDialog(this, LocalText.getText("NetworkInfoDialogMessage",company.getName(),Bank.format(revenueValue)) , LocalText.getText("NetworkInfoDialogTitle",company.getName()), JOptionPane.INFORMATION_MESSAGE); //train simulation only for developers break; } - + JOptionPane.showMessageDialog(orWindow, "RevenueValue = " + revenueValue + "\nRevenueRun = \n" + ra.getOptimalRunPrettyPrint(true)); - + String trainString = JOptionPane.showInputDialog(null, "Enter train string (Examples: 5, 3+3, 4D, 6E, D)", - "Add another train to run?", - JOptionPane.QUESTION_MESSAGE); + "Add another train to run?", + JOptionPane.QUESTION_MESSAGE); if (trainString == null || trainString.equals("")) { anotherTrain = false; } else { @@ -773,7 +772,7 @@ implements ActionListener, KeyListener, RevenueListener { if (revenueAdapter != null) revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); } } - + private void appendInfoText (StringBuffer b, String text) { if (text == null || text.length() == 0) return; if (b.length() > 6) b.append("<br>"); @@ -797,7 +796,7 @@ implements ActionListener, KeyListener, RevenueListener { revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); } } - + public void actionPerformed(ActionEvent actor) { // What kind action has been taken? @@ -904,7 +903,7 @@ implements ActionListener, KeyListener, RevenueListener { if (hasCompanyLoans) { loansCaption.setHighlight(false); } - + for (JMenuItem item : menuItemsToReset) { item.setEnabled(false); if (item instanceof ActionMenuItem) { @@ -912,7 +911,7 @@ implements ActionListener, KeyListener, RevenueListener { } } undoButton.setEnabled(false); - + } public void resetORCompanyTurn(int orCompIndex) { @@ -925,7 +924,7 @@ implements ActionListener, KeyListener, RevenueListener { public void resetCurrentRevenueDisplay() { setSelect(revenue[orCompIndex], revenueSelect[orCompIndex], false); } - + /** * * @return True if route should be displayed (at least for the set revenue step) @@ -933,11 +932,11 @@ implements ActionListener, KeyListener, RevenueListener { private boolean isDisplayRoutes() { return (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.ROUTE_HIGHLIGHT)); } - + private boolean isSuggestRevenue() { return (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.REVENUE_SUGGEST)); } - + /** * * @return True if the routes of the currently active company should be displayed. @@ -947,7 +946,7 @@ implements ActionListener, KeyListener, RevenueListener { return (isDisplayRoutes() && "yes".equalsIgnoreCase(Config.get("map.displayCurrentRoutes"))); } - + /** * any routes currently displayed on the map are removed * In addition, revenue adapter and its thread are interrupted / removed. @@ -956,7 +955,7 @@ implements ActionListener, KeyListener, RevenueListener { clearRevenueAdapter(); orUIManager.getMap().setTrainPaths(null); } - + private void clearRevenueAdapter() { if (revenueThread != null) { revenueThread.interrupt(); @@ -967,9 +966,9 @@ implements ActionListener, KeyListener, RevenueListener { revenueAdapter = null; } } - + private void updateCurrentRoutes(boolean isSetRevenueStep) { - + // initialize and start the revenue adapter if routes to be displayed // or revenue to be suggested in the revenue step if (isDisplayCurrentRoutes() || (isSuggestRevenue() && isSetRevenueStep)) { @@ -993,7 +992,7 @@ implements ActionListener, KeyListener, RevenueListener { } } - + public void initORCompanyTurn(PublicCompanyI orComp, int orCompIndex) { this.orComp = orComp; @@ -1009,7 +1008,7 @@ implements ActionListener, KeyListener, RevenueListener { button1.setEnabled(false); button2.setEnabled(false); button3.setEnabled(false); - + updateCurrentRoutes(false); } @@ -1018,7 +1017,7 @@ implements ActionListener, KeyListener, RevenueListener { tileCaption.setHighlight(true); button1.setVisible(false); - + } public void initTokenLayingStep() { @@ -1034,7 +1033,7 @@ implements ActionListener, KeyListener, RevenueListener { revenueCaption.setHighlight(true); revenueSelect[orCompIndex].setValue(action.getPresetRevenue()); - + setSelect(revenue[orCompIndex], revenueSelect[orCompIndex], true); button1.setText(LocalText.getText("SET_REVENUE")); @@ -1043,7 +1042,7 @@ implements ActionListener, KeyListener, RevenueListener { button1.setMnemonic(KeyEvent.VK_R); button1.setEnabled(true); button1.setVisible(true); - + //indicate interest in setting revenue values (and not only displaying routes) updateCurrentRoutes(true); } @@ -1062,12 +1061,12 @@ implements ActionListener, KeyListener, RevenueListener { } } } - + public void stopRevenueUpdate() { isRevenueValueToBeSet = false; } - - + + public void initPayoutStep(int orCompIndex, SetDividend action, boolean withhold, boolean split, boolean payout) { @@ -1207,6 +1206,14 @@ implements ActionListener, KeyListener, RevenueListener { button1.setVisible(true); } + public void disableButtons () { + button1.setEnabled(false); + button2.setEnabled(false); + button3.setEnabled(false); + undoButton.setEnabled(false); + redoButton.setEnabled(false); + } + public void finishORCompanyTurn(int orCompIndex) { for (Field field : president) { diff --git a/rails/ui/swing/ORUIManager.java b/rails/ui/swing/ORUIManager.java index 40da760..a097bf7 100644 --- a/rails/ui/swing/ORUIManager.java +++ b/rails/ui/swing/ORUIManager.java @@ -20,7 +20,7 @@ import rails.game.special.*; import rails.ui.swing.elements.*; import rails.ui.swing.hexmap.GUIHex; import rails.ui.swing.hexmap.HexMap; -import rails.util.*; +import rails.util.Util; public class ORUIManager implements DialogOwner { @@ -46,7 +46,7 @@ public class ORUIManager implements DialogOwner { protected PossibleActions possibleActions = PossibleActions.getInstance(); private boolean privatesCanBeBoughtNow; public List<PossibleAction> mapRelatedActions = - new ArrayList<PossibleAction>(); + new ArrayList<PossibleAction>(); private boolean tileLayingEnabled = false; public List<LayTile> allowedTileLays = new ArrayList<LayTile>(); @@ -84,13 +84,13 @@ public class ORUIManager implements DialogOwner { /* Message key per substep */ protected static final String[] messageKey = - new String[] { "Inactive", "SelectAHexForTile", "SelectATile", - "RotateTile", "SelectAHexForToken", "SelectAToken", - "ConfirmToken", "SetRevenue", "SelectPayout", - "CorrectMap" }; + new String[] { "Inactive", "SelectAHexForTile", "SelectATile", + "RotateTile", "SelectAHexForToken", "SelectAToken", + "ConfirmToken", "SetRevenue", "SelectPayout", + "CorrectMap" }; protected static Logger log = - Logger.getLogger(ORUIManager.class.getPackage().getName()); + Logger.getLogger(ORUIManager.class.getPackage().getName()); public ORUIManager() { @@ -296,9 +296,9 @@ public class ORUIManager implements DialogOwner { // For now, this only has an effect during tile and token laying. // Perhaps we need to centralise message updating here in a later stage. log.debug("Calling updateMessage, subStep=" + localStep/* - * , new - * Exception("TRACE") - */); + * , new + * Exception("TRACE") + */); if (localStep == ORUIManager.INACTIVE) return; String message = LocalText.getText(ORUIManager.messageKey[localStep]); @@ -349,9 +349,9 @@ public class ORUIManager implements DialogOwner { } if (normalTileMessage.length() > 1) { message += - " " - + LocalText.getText("TileColours", - normalTileMessage); + " " + + LocalText.getText("TileColours", + normalTileMessage); } } else if (localStep == ORUIManager.SELECT_HEX_FOR_TOKEN) { @@ -361,7 +361,7 @@ public class ORUIManager implements DialogOwner { StringBuffer normalTokenMessage = new StringBuffer(" "); List<LayBaseToken> tokenLays = - possibleActions.getType(LayBaseToken.class); + possibleActions.getType(LayBaseToken.class); log.debug("There are " + tokenLays.size() + " TokenLay objects"); int ii = 0; for (LayBaseToken tokenLay : tokenLays) { @@ -380,7 +380,7 @@ public class ORUIManager implements DialogOwner { } if (normalTokenMessage.length() > 1) { message += " " + LocalText.getText("NormalToken", - normalTokenMessage); + normalTokenMessage); } } if (extraMessage.length() > 0) { @@ -400,10 +400,10 @@ public class ORUIManager implements DialogOwner { public void processAction(String command, List<PossibleAction> actions) { if (actions != null && actions.size() > 0 - && !processGameSpecificActions(actions)) { + && !processGameSpecificActions(actions)) { Class<? extends PossibleAction> actionType = - actions.get(0).getClass(); + actions.get(0).getClass(); if (actionType == SetDividend.class) { @@ -426,7 +426,7 @@ public class ORUIManager implements DialogOwner { buyBonusToken ((BuyBonusToken)actions.get(0)); } else if (actionType == NullAction.class - || actionType == GameAction.class ) { + || actionType == GameAction.class ) { orWindow.process(actions.get(0)); @@ -495,7 +495,7 @@ public class ORUIManager implements DialogOwner { action.setActualRevenue(amount); if (amount == 0 || action.getRevenueAllocation() != SetDividend.UNKNOWN) { log.debug("Allocation is known: " - + action.getRevenueAllocation()); + + action.getRevenueAllocation()); orWindow.process(action); } else { log.debug("Allocation is unknown, asking for it"); @@ -597,6 +597,7 @@ public class ORUIManager implements DialogOwner { public void setCurrentDialog (JDialog dialog, PossibleAction action) { gameUIManager.setCurrentDialog(dialog, action); + if (!(dialog instanceof MessageDialog)) orPanel.disableButtons(); } public void hexClicked(GUIHex clickedHex, GUIHex selectedHex) { @@ -628,10 +629,10 @@ public class ORUIManager implements DialogOwner { return; } List<LayToken> allowances = - map.getTokenAllowanceForHex(clickedHex.getHexModel()); + map.getTokenAllowanceForHex(clickedHex.getHexModel()); if (allowances.size() > 0) { log.debug("Hex " + clickedHex.getName() - + " clicked, allowances:"); + + " clicked, allowances:"); for (LayToken allowance : allowances) { log.debug(allowance.toString()); } @@ -645,7 +646,7 @@ public class ORUIManager implements DialogOwner { } else if (tileLayingEnabled) { if (localStep == ROTATE_OR_CONFIRM_TILE - && clickedHex == selectedHex) { + && clickedHex == selectedHex) { selectedHex.rotateTile(); return; @@ -660,16 +661,16 @@ public class ORUIManager implements DialogOwner { setLocalStep(SELECT_HEX_FOR_TILE); } else { if (clickedHex.getHexModel().isUpgradeableNow()) - /* - * Direct call to Model to be replaced later by use of - * allowedTilesPerHex. Would not work yet. - */ + /* + * Direct call to Model to be replaced later by use of + * allowedTilesPerHex. Would not work yet. + */ { map.selectHex(clickedHex); setLocalStep(SELECT_TILE); } else { JOptionPane.showMessageDialog(mapPanel, - "This hex cannot be upgraded now"); + "This hex cannot be upgraded now"); } } } @@ -695,11 +696,11 @@ public class ORUIManager implements DialogOwner { // Check if the new tile must be connected to some other track boolean mustConnect = - tile.getColourName().equalsIgnoreCase(Tile.YELLOW_COLOUR_NAME) - // Does not apply to the current company's home hex(es) - && !hex.getHexModel().isHomeFor(orComp) - // Does not apply to special tile lays - && !isUnconnectedTileLayTarget(hex); + tile.getColourName().equalsIgnoreCase(Tile.YELLOW_COLOUR_NAME) + // Does not apply to the current company's home hex(es) + && !hex.getHexModel().isHomeFor(orComp) + // Does not apply to special tile lays + && !isUnconnectedTileLayTarget(hex); if (hex.dropTile(tileId, mustConnect)) { /* Lay tile */ @@ -707,7 +708,7 @@ public class ORUIManager implements DialogOwner { } else { /* Tile cannot be laid in a valid orientation: refuse it */ JOptionPane.showMessageDialog(mapPanel, - "This tile cannot be laid in a valid orientation."); + "This tile cannot be laid in a valid orientation."); tileUpgrades.remove(tile); setLocalStep(ORUIManager.SELECT_TILE); upgradePanel.showUpgrades(); @@ -719,7 +720,7 @@ public class ORUIManager implements DialogOwner { MapHex mapHex = hex.getHexModel(); for (LayTile action : possibleActions.getType(LayTile.class)) { if (action.getType() == LayTile.SPECIAL_PROPERTY - && action.getSpecialProperty().getLocations().contains(mapHex)) { + && action.getSpecialProperty().getLocations().contains(mapHex)) { // log.debug(hex.getName()+" is a special property target"); return true; } @@ -746,7 +747,7 @@ public class ORUIManager implements DialogOwner { if (selectedHex != null && selectedHex.canFixTile()) { List<LayTile> allowances = - map.getTileAllowancesForHex(selectedHex.getHexModel()); + map.getTileAllowancesForHex(selectedHex.getHexModel()); LayTile allowance = null; TileI tile = selectedHex.getProvisionalTile(); if (allowances.size() == 1) { @@ -769,7 +770,7 @@ public class ORUIManager implements DialogOwner { && !sp_tiles.contains(tile)) continue; // 2. SP refers to specified hexes, (one of) which is chosen: // (example: 1830 hex B20) - if ((sp_hexes = lt.getLocations()) != null + if ((sp_hexes = lt.getLocations()) != null && !sp_hexes.contains(selectedHex.getModel())) continue; spec_lt = lt; } else { @@ -777,12 +778,12 @@ public class ORUIManager implements DialogOwner { gen_lt = lt; } } - + allowance = spec_lt == null ? gen_lt : - gen_lt == null ? spec_lt : - spec_lt.getSpecialProperty().getPriority() - == SpecialPropertyI.Priority.FIRST ? spec_lt : gen_lt; - + gen_lt == null ? spec_lt : + spec_lt.getSpecialProperty().getPriority() + == SpecialPropertyI.Priority.FIRST ? spec_lt : gen_lt; + } allowance.setChosenHex(selectedHex.getHexModel()); allowance.setOrientation(selectedHex.getProvisionalTileRotation()); @@ -835,11 +836,11 @@ public class ORUIManager implements DialogOwner { if (city.hasTokenSlotsLeft()) { prompt = LocalText.getText( "SelectStationForTokenOption", - city.getNumber(), - ((MapHex) selectedHex.getModel()).getConnectionString( - selectedHex.getCurrentTile(), - ((MapHex) selectedHex.getModel()).getCurrentTileRotation(), - city.getRelatedStation().getNumber())) ; + city.getNumber(), + ((MapHex) selectedHex.getModel()).getConnectionString( + selectedHex.getCurrentTile(), + ((MapHex) selectedHex.getModel()).getCurrentTileRotation(), + city.getRelatedStation().getNumber())) ; prompts.add(prompt); promptToCityMap.put(prompt, city); } @@ -847,17 +848,17 @@ public class ORUIManager implements DialogOwner { if (prompts.isEmpty()) { return; } - // If more than one City to choose from, ask the player. Otherwise use Element zero (first) for the station. + // If more than one City to choose from, ask the player. Otherwise use Element zero (first) for the station. if (prompts.size() > 1) { String selected = - (String) JOptionPane.showInputDialog(orWindow, - LocalText.getText("SelectStationForToken", - action.getPlayerName(), - selectedHex.getName(), - action.getCompanyName()), - LocalText.getText("WhichStation"), - JOptionPane.PLAIN_MESSAGE, null, - prompts.toArray(), prompts.get(0)); + (String) JOptionPane.showInputDialog(orWindow, + LocalText.getText("SelectStationForToken", + action.getPlayerName(), + selectedHex.getName(), + action.getCompanyName()), + LocalText.getText("WhichStation"), + JOptionPane.PLAIN_MESSAGE, null, + prompts.toArray(), prompts.get(0)); if (selected == null) return; station = promptToCityMap.get(selected).getNumber(); } else { @@ -891,7 +892,7 @@ public class ORUIManager implements DialogOwner { MapHex hex = action.getChosenHex(); TileI newTile = action.getLaidTile(); TileI oldTile = hex.getCurrentTile(); - if (!action.isRelayBaseTokens() + if (!action.isRelayBaseTokens() && !oldTile.relayBaseTokensOnUpgrade()) return; for (Stop oldStop : hex.getStops()) { if (oldStop.hasTokens()) { @@ -906,9 +907,9 @@ public class ORUIManager implements DialogOwner { prompt = LocalText.getText("SelectStationForTokenOption", newStation.getNumber(), hex.getConnectionString( - newTile, - action.getOrientation(), - newStation.getNumber()) ); + newTile, + action.getOrientation(), + newStation.getNumber()) ); prompts.add(prompt); promptToCityMap.put(prompt, newStation.getNumber()); } @@ -918,21 +919,21 @@ public class ORUIManager implements DialogOwner { } if (prompts.size () > 1) { String selected = - (String) JOptionPane.showInputDialog(orWindow, - LocalText.getText("SelectStationForToken", - action.getPlayerName(), - hex.getName(), - company.getName() - ), - LocalText.getText("WhichStation"), - JOptionPane.PLAIN_MESSAGE, null, - prompts.toArray(), prompts.get(0)); + (String) JOptionPane.showInputDialog(orWindow, + LocalText.getText("SelectStationForToken", + action.getPlayerName(), + hex.getName(), + company.getName() + ), + LocalText.getText("WhichStation"), + JOptionPane.PLAIN_MESSAGE, null, + prompts.toArray(), prompts.get(0)); if (selected == null) return; action.addRelayBaseToken(company.getName(), promptToCityMap.get(selected)); } else { action.addRelayBaseToken(company.getName(), promptToCityMap.get(prompts.toArray() [0])); } - } + } } } @@ -945,15 +946,15 @@ public class ORUIManager implements DialogOwner { Map<String, Station> promptToStationMap = new HashMap<String, Station>(); String prompt; for (Station station:possibleStations) { - prompt = LocalText.getText( - "SelectStationForTokenOption", - station.getNumber(), - ((MapHex) selectedHex.getModel()).getConnectionString( - selectedHex.getProvisionalTile(), - selectedHex.getProvisionalTileRotation(), - station.getNumber())) ; - prompts.add(prompt); - promptToStationMap.put(prompt, station); + prompt = LocalText.getText( + "SelectStationForTokenOption", + station.getNumber(), + ((MapHex) selectedHex.getModel()).getConnectionString( + selectedHex.getProvisionalTile(), + selectedHex.getProvisionalTileRotation(), + station.getNumber())) ; + prompts.add(prompt); + promptToStationMap.put(prompt, station); } String selected = (String) JOptionPane.showInputDialog(orWindow, @@ -1012,11 +1013,11 @@ public class ORUIManager implements DialogOwner { OperatingCost.OCType t = ac.getOCType(); if (t == OperatingCost.OCType.LAY_TILE) textOC.add(LocalText.getText("OCLayTile", - suggestedCostText )); + suggestedCostText )); if (t == OperatingCost.OCType.LAY_BASE_TOKEN) textOC.add(LocalText.getText("OCLayBaseToken", - suggestedCostText )); + suggestedCostText )); } if (!textOC.isEmpty()) { @@ -1056,7 +1057,7 @@ public class ORUIManager implements DialogOwner { List<String> prompts = new ArrayList<String>(); Map<String, PossibleAction> promptToTrain = - new HashMap<String, PossibleAction>(); + new HashMap<String, PossibleAction>(); TrainI train; String usingPrivates = ""; @@ -1082,7 +1083,7 @@ public class ORUIManager implements DialogOwner { from.getName() )); if (bTrain.isForExchange()) { b.append(" (").append(LocalText.getText("EXCHANGED")).append( - ")"); + ")"); } if (cost > 0) { b.append(" ").append( @@ -1090,7 +1091,7 @@ public class ORUIManager implements DialogOwner { } if (bTrain.hasSpecialProperty()) { String priv = - (bTrain.getSpecialProperty()).getOriginalCompany().getName(); + (bTrain.getSpecialProperty()).getOriginalCompany().getName(); b.append(" ").append(LocalText.getText("USING_SP", priv)); usingPrivates += ", " + priv; } @@ -1119,7 +1120,7 @@ public class ORUIManager implements DialogOwner { } StringBuffer msgbuf = - new StringBuffer(LocalText.getText("SelectTrain")); + new StringBuffer(LocalText.getText("SelectTrain")); if (usingPrivates.length() > 0) { msgbuf.append("<br><font color=\"red\">"); msgbuf.append(LocalText.getText("SelectCheapTrain", @@ -1129,11 +1130,11 @@ public class ORUIManager implements DialogOwner { setMessage(msgbuf.toString()); String selectedActionText = - (String) JOptionPane.showInputDialog(orWindow, - LocalText.getText("BUY_WHICH_TRAIN"), - LocalText.getText("WHICH_TRAIN"), - JOptionPane.QUESTION_MESSAGE, null, prompts.toArray(), - prompts.get(0)); + (String) JOptionPane.showInputDialog(orWindow, + LocalText.getText("BUY_WHICH_TRAIN"), + LocalText.getText("WHICH_TRAIN"), + JOptionPane.QUESTION_MESSAGE, null, prompts.toArray(), + prompts.get(0)); if (!Util.hasValue(selectedActionText)) return; selectedAction = promptToTrain.get(selectedActionText); @@ -1146,15 +1147,15 @@ public class ORUIManager implements DialogOwner { if (price == 0 && seller.getOwner() instanceof PublicCompanyI) { prompt = LocalText.getText("WHICH_TRAIN_PRICE", - orComp.getName(), - train.getName(), - seller.getName() ); + orComp.getName(), + train.getName(), + seller.getName() ); String response; for (;;) { response = - JOptionPane.showInputDialog(orWindow, prompt, - LocalText.getText("WHICH_PRICE"), - JOptionPane.QUESTION_MESSAGE); + JOptionPane.showInputDialog(orWindow, prompt, + LocalText.getText("WHICH_PRICE"), + JOptionPane.QUESTION_MESSAGE); if (response == null) return; // Cancel try { price = Integer.parseInt(response); @@ -1165,8 +1166,8 @@ public class ORUIManager implements DialogOwner { if (!prompt.startsWith("Please")) { prompt = - LocalText.getText("ENTER_PRICE_OR_CANCEL") + "\n" - + prompt; + LocalText.getText("ENTER_PRICE_OR_CANCEL") + "\n" + + prompt; } } } @@ -1178,21 +1179,21 @@ public class ORUIManager implements DialogOwner { exchangedTrain = oldTrains.get(0); } else { List<String> oldTrainOptions = - new ArrayList<String>(oldTrains.size()); + new ArrayList<String>(oldTrains.size()); String[] options = new String[oldTrains.size()]; int jj = 0; for (int j = 0; j < oldTrains.size(); j++) { options[jj + j] = - LocalText.getText("N_Train", oldTrains.get(j).getName()); + LocalText.getText("N_Train", oldTrains.get(j).getName()); oldTrainOptions.add(options[jj + j]); } String exchangedTrainName = - (String) JOptionPane.showInputDialog(orWindow, - LocalText.getText("WHICH_TRAIN_EXCHANGE_FOR", - Bank.format(price)), - LocalText.getText("WHICH_TRAIN_TO_EXCHANGE"), - JOptionPane.QUESTION_MESSAGE, null, options, - options[0]); + (String) JOptionPane.showInputDialog(orWindow, + LocalText.getText("WHICH_TRAIN_EXCHANGE_FOR", + Bank.format(price)), + LocalText.getText("WHICH_TRAIN_TO_EXCHANGE"), + JOptionPane.QUESTION_MESSAGE, null, options, + options[0]); if (exchangedTrainName != null) { int index = oldTrainOptions.indexOf(exchangedTrainName); if (index >= 0) { @@ -1209,7 +1210,7 @@ public class ORUIManager implements DialogOwner { if (train != null) { // Remember the old off-board revenue step int oldOffBoardRevenueStep = - gameUIManager.getCurrentPhase().getOffBoardRevenueStep(); + gameUIManager.getCurrentPhase().getOffBoardRevenueStep(); buyAction.setPricePaid(price); buyAction.setExchangedTrain(exchangedTrain); @@ -1231,11 +1232,11 @@ public class ORUIManager implements DialogOwner { gameUIManager.discardTrains(dt); } - */ + */ } int newOffBoardRevenueStep = - gameUIManager.getCurrentPhase().getOffBoardRevenueStep(); + gameUIManager.getCurrentPhase().getOffBoardRevenueStep(); if (newOffBoardRevenueStep != oldOffBoardRevenueStep) { map.updateOffBoardToolTips(); } @@ -1262,7 +1263,7 @@ public class ORUIManager implements DialogOwner { } else { priceRange = Bank.format(maxPrice); } - + privatesForSale.add(LocalText.getText("BuyPrivatePrompt", action.getPrivateCompany().getName(), action.getPrivateCompany().getPortfolio().getName(), @@ -1271,11 +1272,11 @@ public class ORUIManager implements DialogOwner { if (privatesForSale.size() > 0) { chosenOption = - (String) JOptionPane.showInputDialog(orWindow, - LocalText.getText("BUY_WHICH_PRIVATE"), - LocalText.getText("WHICH_PRIVATE"), - JOptionPane.QUESTION_MESSAGE, null, - privatesForSale.toArray(), privatesForSale.get(0)); + (String) JOptionPane.showInputDialog(orWindow, + LocalText.getText("BUY_WHICH_PRIVATE"), + LocalText.getText("WHICH_PRIVATE"), + JOptionPane.QUESTION_MESSAGE, null, + privatesForSale.toArray(), privatesForSale.get(0)); if (chosenOption != null) { index = privatesForSale.indexOf(chosenOption); chosenAction = privates.get(index); @@ -1283,13 +1284,13 @@ public class ORUIManager implements DialogOwner { maxPrice = chosenAction.getMaximumPrice(); if (minPrice < maxPrice) { String price = - JOptionPane.showInputDialog(orWindow, - LocalText.getText("WHICH_PRIVATE_PRICE", - chosenOption, - Bank.format(minPrice), - Bank.format(maxPrice) ), - LocalText.getText("WHICH_PRICE"), - JOptionPane.QUESTION_MESSAGE); + JOptionPane.showInputDialog(orWindow, + LocalText.getText("WHICH_PRIVATE_PRICE", + chosenOption, + Bank.format(minPrice), + Bank.format(maxPrice) ), + LocalText.getText("WHICH_PRICE"), + JOptionPane.QUESTION_MESSAGE); try { amount = Integer.parseInt(price); } catch (NumberFormatException e) { @@ -1386,8 +1387,8 @@ public class ORUIManager implements DialogOwner { action.getCompanyName(), Bank.format(action.getPrice())); if (JOptionPane.showConfirmDialog(orWindow, prompt, - message, JOptionPane.OK_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE) + message, JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) { action.setNumberTaken(1); orWindow.process(action); @@ -1433,9 +1434,9 @@ public class ORUIManager implements DialogOwner { orWindow, LocalText.getText("Select"), LocalText.getText("SelectLoansToRepay", action.getCompanyName()), - options, + options, 0); - gameUIManager.setCurrentDialog (currentDialog, action); + setCurrentDialog (currentDialog, action); } } @@ -1490,7 +1491,7 @@ public class ORUIManager implements DialogOwner { orPanel.initORCompanyTurn(orComp, orCompIndex); if (!myTurn) return; - + privatesCanBeBoughtNow = possibleActions.contains(BuyPrivate.class); orPanel.initPrivateBuying(privatesCanBeBoughtNow); @@ -1526,14 +1527,14 @@ public class ORUIManager implements DialogOwner { log.debug("Tiles can be laid"); mapRelatedActions.addAll(possibleActions.getType(LayTile.class)); - //} else if (possibleActions.contains(LayBaseToken.class)) { + //} else if (possibleActions.contains(LayBaseToken.class)) { } else if (orStep == GameDef.OrStep.LAY_TOKEN) { orWindow.requestFocus(); // Include bonus tokens List<LayToken> possibleTokenLays = - possibleActions.getType(LayToken.class); + possibleActions.getType(LayToken.class); mapRelatedActions.addAll(possibleTokenLays); allowedTokenLays = possibleTokenLays; @@ -1542,7 +1543,7 @@ public class ORUIManager implements DialogOwner { log.debug("BaseTokens can be laid"); } else if (possibleActions.contains(SetDividend.class) - && localStep == SELECT_PAYOUT) { + && localStep == SELECT_PAYOUT) { SetDividend action; if (actionToComplete != null) { @@ -1563,7 +1564,7 @@ public class ORUIManager implements DialogOwner { } else if (possibleActions.contains(SetDividend.class)) { SetDividend action = - possibleActions.getType(SetDividend.class).get(0); + possibleActions.getType(SetDividend.class).get(0); orPanel.initRevenueEntryStep(orCompIndex, action); @@ -1572,13 +1573,13 @@ public class ORUIManager implements DialogOwner { message += "<br><font color=\"red\">" + LocalText.getText("WarningNeedCash", Bank.format(action.getRequiredCash())) - + "</font>"; + + "</font>"; } setMessage(message); } else if (orStep == GameDef.OrStep.BUY_TRAIN) { - boolean canBuyTrain = possibleActions.contains(BuyTrain.class); + boolean canBuyTrain = possibleActions.contains(BuyTrain.class); orPanel.initTrainBuying(canBuyTrain); StringBuffer b = new StringBuffer(LocalText.getText("BuyTrain")); @@ -1621,7 +1622,7 @@ public class ORUIManager implements DialogOwner { if (possibleActions.contains(NullAction.class)) { List<NullAction> actions = - possibleActions.getType(NullAction.class); + possibleActions.getType(NullAction.class); for (NullAction action : actions) { switch (action.getMode()) { case NullAction.DONE: @@ -1634,7 +1635,7 @@ public class ORUIManager implements DialogOwner { if (possibleActions.contains(GameAction.class)) { List<GameAction> actions = - possibleActions.getType(GameAction.class); + possibleActions.getType(GameAction.class); for (GameAction action : actions) { switch (action.getMode()) { case GameAction.UNDO: @@ -1657,7 +1658,7 @@ public class ORUIManager implements DialogOwner { && orStep != GameDef.OrStep.LAY_TOKEN) { List<LayToken> tokenActions = - possibleActions.getType(LayToken.class); + possibleActions.getType(LayToken.class); for (LayToken tAction : tokenActions) { if (tAction instanceof LayBaseToken @@ -1678,14 +1679,14 @@ public class ORUIManager implements DialogOwner { if (possibleActions.contains(BuyBonusToken.class)) { List<BuyBonusToken> bonusTokenActions = - possibleActions.getType(BuyBonusToken.class); + possibleActions.getType(BuyBonusToken.class); for (BuyBonusToken bbt : bonusTokenActions) { String text = - LocalText.getText("BuyBonusToken", - bbt.getName(), - Bank.format(bbt.getValue()), - bbt.getSellerName(), - Bank.format(bbt.getPrice()) ); + LocalText.getText("BuyBonusToken", + bbt.getName(), + Bank.format(bbt.getValue()), + bbt.getSellerName(), + Bank.format(bbt.getPrice()) ); orPanel.addSpecialAction(bbt, text); } } @@ -1747,7 +1748,7 @@ public class ORUIManager implements DialogOwner { public void setLocalStep(int localStep) { log.debug("Setting upgrade step to " + localStep + " " - + ORUIManager.messageKey[localStep]); + + ORUIManager.messageKey[localStep]); this.localStep = localStep; updateMessage(); @@ -1758,7 +1759,7 @@ public class ORUIManager implements DialogOwner { if (upgradePanel != null) { log.debug("Initial localStep is " + localStep + " " - + ORUIManager.messageKey[localStep]); + + ORUIManager.messageKey[localStep]); ... [truncated message content] |
From: Frederick W. <fre...@us...> - 2012-01-11 18:57:30
|
rails/ui/swing/MessagePanel.java | 15 ++++++++------- rails/ui/swing/ORPanel.java | 2 ++ rails/ui/swing/ORWindow.java | 11 ++++++++++- rails/ui/swing/hexmap/HexMap.java | 2 +- 4 files changed, 21 insertions(+), 9 deletions(-) New commits: commit 268fbf6844786c9c36948a55566123b7159c1d1e Author: Frederick Weld <fre...@gm...> Date: Wed Jan 11 19:19:41 2012 +0100 Prohibited resizing of OR's message panel (and ORPanel to some extent) Frequent resizing by the message panel and the OR panel caused the map panel to being resized - which was not desirable in case of activated auto-zoom. Message Panel is now fixed to the height of two lines. The additional vertical scrollbar allows for text containing more than two lines. ORPanel used to resize itself for each set-revenue step as the size of the revenue input box did not match the one of the revenue read-only field. These sizes are now aligned. (ORPanel still resizes if companies are added/removed from the list.) diff --git a/rails/ui/swing/MessagePanel.java b/rails/ui/swing/MessagePanel.java index 04f1add..6e8e1fc 100644 --- a/rails/ui/swing/MessagePanel.java +++ b/rails/ui/swing/MessagePanel.java @@ -8,9 +8,14 @@ import java.util.ArrayList; import java.util.List; import javax.swing.*; +import javax.swing.border.EmptyBorder; public class MessagePanel extends JPanel { private static final long serialVersionUID = 1L; + + //the height of this panel (fixed because scroll bar is used) + public static final int fixedHeight = 45; + public static final int scrollUnit = 8; private JLabel message; @@ -25,14 +30,14 @@ public class MessagePanel extends JPanel { super(); setBackground(background); - setLines(1); - setBorder(BorderFactory.createLoweredBevelBorder()); - + setBorder(new EmptyBorder(0,0,0,0)); + message = new JLabel(""); message.setBackground(background); message.setVerticalAlignment(SwingConstants.CENTER); message.setHorizontalAlignment(SwingConstants.CENTER); message.setOpaque(true); + add(message); message.setVisible(true); setVisible(true); @@ -101,8 +106,4 @@ public class MessagePanel extends JPanel { updateMessageText(); } - public void setLines(int numberOfLines) { - setSize(1000, numberOfLines * 12); - } - } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index aeb19e7..e8f8254 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -541,6 +541,8 @@ implements ActionListener, KeyListener, RevenueListener { f = revenue[i] = new Field(c.getLastRevenueModel()); addField(f, revXOffset, revYOffset + i, 1, 1, 0, visible); f = revenueSelect[i] = new Spinner(0, 0, 0, 10); + //zero-border so that size matches revenue field (thus, averting or panel resize) + f.setBorder(new javax.swing.border.EmptyBorder(0,0,0,0)); addField(f, revXOffset, revYOffset + i, 1, 1, 0, false); // deactived below, as this caused problems by gridpanel rowvisibility function -- sfy // revenue[i].addDependent(revenueSelect[i]); diff --git a/rails/ui/swing/ORWindow.java b/rails/ui/swing/ORWindow.java index c290ac2..dcef993 100644 --- a/rails/ui/swing/ORWindow.java +++ b/rails/ui/swing/ORWindow.java @@ -2,13 +2,17 @@ package rails.ui.swing; import java.awt.BorderLayout; +import java.awt.Dimension; import java.awt.Rectangle; import java.awt.event.*; import java.util.ArrayList; import java.util.List; +import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.border.EmptyBorder; import org.apache.log4j.Logger; @@ -61,7 +65,12 @@ public class ORWindow extends JFrame implements ActionPerformer { getContentPane().setLayout(new BorderLayout()); messagePanel = new MessagePanel(); - getContentPane().add(messagePanel, BorderLayout.NORTH); + JScrollPane slider = new JScrollPane(messagePanel); + slider.setBorder(BorderFactory.createLoweredBevelBorder()); + slider.getVerticalScrollBar().setUnitIncrement(MessagePanel.scrollUnit); + slider.setPreferredSize(new Dimension(100,MessagePanel.fixedHeight)); + + getContentPane().add(slider, BorderLayout.NORTH); mapPanel = new MapPanel(gameUIManager); getContentPane().add(mapPanel, BorderLayout.CENTER); commit a0e77366eec4ee4652011cb0e06722878d3c1c57 Author: Frederick Weld <fre...@gm...> Date: Wed Jan 11 16:28:59 2012 +0100 Fixed bug in dirty region determination for train routes Bug could have caused the glitches (off-screen painting) observed before. diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index e862f6d..6029c93 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -155,7 +155,7 @@ public abstract class HexMap implements MouseListener, pathRect.x - margin, pathRect.y - margin, pathRect.width + margin * 2, - pathRect.y + margin * 2); + pathRect.height + margin * 2); if (r == null) { r = pathMarginRect; } else { |
From: Frederick W. <fre...@us...> - 2012-01-10 22:29:25
|
rails/ui/swing/ImageLoader.java | 3 +++ rails/ui/swing/MapPanel.java | 3 +++ rails/ui/swing/ORPanel.java | 7 +------ 3 files changed, 7 insertions(+), 6 deletions(-) New commits: commit 1f0b89df9bde415058747b361b366dec5fe6202c Author: Frederick Weld <fre...@gm...> Date: Tue Jan 10 23:25:06 2012 +0100 Fixed resize issues: tiles (adjustment zoom), routes (fit zoom) There is a buffer for tile scalings - it is now invalidated whenever the adjustmentZoomFactor is changed. (This tile buffer is the reason why maintaining zoom steps made sense in the past.) In addition, redrawal of routes is now also triggered upon auto-resize diff --git a/rails/ui/swing/ImageLoader.java b/rails/ui/swing/ImageLoader.java index f663639..fd64570 100644 --- a/rails/ui/swing/ImageLoader.java +++ b/rails/ui/swing/ImageLoader.java @@ -149,6 +149,9 @@ public class ImageLoader { for (int i = 0 ; i < zoomFactors.length ; i++) { zoomFactors[i] = 0; } + + //invalidate buffered tile scalings + if (tileMap != null) tileMap.clear(); } public void resetAdjustmentFactor() { diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index 23e4a24..66c81d6 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -138,6 +138,9 @@ public class MapPanel extends JPanel { if (mapImage != null) { mapImage.setBoundsAndResize(currentMapSize,map.getZoomStep()); } + //access from map panel to or panel not nice but currently necessary for route drawing + if (gameUIManager.getORUIManager() != null && gameUIManager.getORUIManager().getORPanel() != null) + gameUIManager.getORUIManager().getORPanel().redrawRoutes(); layeredPane.revalidate(); } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 959d644..aeb19e7 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -790,7 +790,7 @@ implements ActionListener, KeyListener, RevenueListener { disableRoutesDisplay(); } - private void redrawRoutes() { + public void redrawRoutes() { if (revenueAdapter != null && isDisplayRoutes()) { revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); } @@ -827,19 +827,16 @@ implements ActionListener, KeyListener, RevenueListener { fitToWidth.setSelected(false); fitToHeight.setSelected(false); orWindow.getMapPanel().zoom(true); - redrawRoutes(); } else if (source == zoomOut) { fitToWindow.setSelected(false); fitToWidth.setSelected(false); fitToHeight.setSelected(false); orWindow.getMapPanel().zoom(false); - redrawRoutes(); } else if (source == fitToWindow) { if (fitToWindow.isSelected()) { fitToWidth.setSelected(false); fitToHeight.setSelected(false); orWindow.getMapPanel().fitToWindow(); - redrawRoutes(); } else { orWindow.getMapPanel().removeFitToOption(); } @@ -848,7 +845,6 @@ implements ActionListener, KeyListener, RevenueListener { fitToWindow.setSelected(false); fitToHeight.setSelected(false); orWindow.getMapPanel().fitToWidth(); - redrawRoutes(); } else { orWindow.getMapPanel().removeFitToOption(); } @@ -857,7 +853,6 @@ implements ActionListener, KeyListener, RevenueListener { fitToWindow.setSelected(false); fitToWidth.setSelected(false); orWindow.getMapPanel().fitToHeight(); - redrawRoutes(); } else { orWindow.getMapPanel().removeFitToOption(); } |
From: Frederick W. <fre...@us...> - 2012-01-10 21:23:50
|
LocalisedText.properties | 1 data/18AL/Map.xml | 2 - data/Properties.xml | 1 rails/ui/swing/MapPanel.java | 42 ++++++++++++++++++---- rails/ui/swing/ORPanel.java | 63 +++++++++++++++++++++++++-------- rails/ui/swing/hexmap/HexMapImage.java | 16 +++++++- 6 files changed, 101 insertions(+), 24 deletions(-) New commits: commit fe8675fe0c3ec8691b2460593f331a8535f872a4 Author: Frederick Weld <fre...@gm...> Date: Tue Jan 10 22:17:48 2012 +0100 Transformed fit-to zoom from one-time zoom to permanent auto-zoom The fit-to-xyz zoom options are now check box menu items. The selected option is permanent in the sense that MapPanel resizing will lead automatically lead to the selected/active fit-to-xyz option. In addition, added a new map config option to define what the default zoom option is when starting a game. Furthermore, fixed a legacy issue with initial mapImage resizing that had been marked with FIXME. diff --git a/LocalisedText.properties b/LocalisedText.properties index b3875f2..6deba63 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -182,6 +182,7 @@ Config.label.font.ui.style=Font style Config.label.local.player.name=Local player (for pbem) Config.label.locale=Language setting Config.label.map.autoscroll=Map autoscroll +Config.label.map.defaultZoomFitOption=Default zoom fit option Config.label.map.displayCurrentRoutes=Display routes of active company Config.label.map.image.display=Display background map Config.label.map.highlightHexes=Highlight company locations diff --git a/data/18AL/Map.xml b/data/18AL/Map.xml index 8bf10ff..b04770f 100644 --- a/data/18AL/Map.xml +++ b/data/18AL/Map.xml @@ -1,5 +1,5 @@ <Map tileOrientation="NS" letterOrientation="vertical" even="A"> - <Image file="18AL/18AL_Map_gamekit.svg" x="-2" y="-24" scale="0.384"/> + <Image file="18AL/18AL_Map_gamekit.svg" x="-2" y="-25" scale="0.386"/> <Hex name="A2" tile="0"/> <Hex name="A4" tile="-912" orientation="2" value="40,50" city="Nashville"/> <Hex name="B1" tile="-901" value="40,30" city="Corinth"/> diff --git a/data/Properties.xml b/data/Properties.xml index 13cb9ff..6f89262 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -30,6 +30,7 @@ <Section name="Map"> <Property name="map.autoscroll" type="BOOLEAN" /> <Property name="map.zoomstep" type="INTEGER" /> + <Property name="map.defaultZoomFitOption" type="LIST" values="none,fit to window,fit to width,fit to height" /> <Property name="map.image.display" type="BOOLEAN" /> <Property name="map.displayCurrentRoutes" type="BOOLEAN" /> <Property name="map.highlightHexes" type="BOOLEAN" /> diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index 6175b9b..23e4a24 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -2,6 +2,8 @@ package rails.ui.swing; import java.awt.*; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; import java.awt.event.KeyEvent; import java.util.List; @@ -33,6 +35,10 @@ public class MapPanel extends JPanel { private JLayeredPane layeredPane; private Dimension originalMapSize; private Dimension currentMapSize; + + //active fit-to zoom options + private boolean fitToWidth = false; + private boolean fitToHeight = false; protected static Logger log = Logger.getLogger(MapPanel.class.getPackage().getName()); @@ -78,6 +84,14 @@ public class MapPanel extends JPanel { setSize(originalMapSize); setLocation(25, 25); + //add listener for auto fit upon resize events + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + super.componentResized(e); + zoomFit (fitToWidth, fitToHeight); + } + }); } @@ -122,15 +136,13 @@ public class MapPanel extends JPanel { layeredPane.setPreferredSize(currentMapSize); map.setBounds(0, 0, currentMapSize.width, currentMapSize.height); if (mapImage != null) { - mapImage.setBounds(0, 0, currentMapSize.width, currentMapSize.height); - mapImage.setPreferredSize(currentMapSize); - mapImage.zoom(map.getZoomStep()); - // FIXME setBounds() seems to be sufficient to resize a JSVGCanvas, but it doesn't always work... + mapImage.setBoundsAndResize(currentMapSize,map.getZoomStep()); } layeredPane.revalidate(); } public void zoom (boolean in) { + removeFitToOption(); map.zoom(in); adjustToNewMapZoom(); } @@ -141,6 +153,8 @@ public class MapPanel extends JPanel { * determined on top of that. */ private void zoomFit (boolean fitToWidth, boolean fitToHeight) { + if (!fitToWidth && !fitToHeight) return; + ImageLoader imageLoader = GameUIManager.getImageLoader(); int zoomStep = map.getZoomStep(); @@ -212,16 +226,30 @@ public class MapPanel extends JPanel { adjustToNewMapZoom(); } + private void fitToOption (boolean fitToWidth, boolean fitToHeight) { + //ignore if nothing has changed + if (this.fitToWidth == fitToWidth && this.fitToHeight == fitToHeight ) return; + + this.fitToWidth = fitToWidth; + this.fitToHeight = fitToHeight; + zoomFit(fitToWidth, fitToHeight); + } + public void fitToWindow () { - zoomFit (true, true); + fitToOption (true, true); } public void fitToWidth () { - zoomFit (true, false); + fitToOption (true, false); } public void fitToHeight () { - zoomFit (false, true); + fitToOption (false, true); + } + + public void removeFitToOption () { + fitToWidth = false; + fitToHeight = false; } public void keyPressed(KeyEvent e) { diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 03bbc19..959d644 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -214,17 +214,14 @@ implements ActionListener, KeyListener, RevenueListener { zoomOut.addActionListener(this); zoomOut.setEnabled(true); zoomMenu.add(zoomOut); - fitToWindow = new JMenuItem("Fit to window"); - fitToWindow.addActionListener(this); - fitToWindow.setEnabled(true); + fitToWindow = createFitToMenuItem("Fit to window"); + if (fitToWindow.isSelected()) orWindow.getMapPanel().fitToWindow(); zoomMenu.add(fitToWindow); - fitToWidth = new JMenuItem("Fit to width"); - fitToWidth.addActionListener(this); - fitToWidth.setEnabled(true); + fitToWidth = createFitToMenuItem("Fit to width"); + if (fitToWidth.isSelected()) orWindow.getMapPanel().fitToWidth(); zoomMenu.add(fitToWidth); - fitToHeight = new JMenuItem("Fit to height"); - fitToHeight.addActionListener(this); - fitToHeight.setEnabled(true); + fitToHeight = createFitToMenuItem("Fit to height"); + if (fitToHeight.isSelected()) orWindow.getMapPanel().fitToHeight(); zoomMenu.add(fitToHeight); calibrateMap = new JMenuItem("CalibrateMap"); calibrateMap.addActionListener(this); @@ -239,6 +236,18 @@ implements ActionListener, KeyListener, RevenueListener { addKeyListener(this); } + private JCheckBoxMenuItem createFitToMenuItem(String name) { + JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(name); + menuItem.addActionListener(this); + menuItem.setEnabled(true); + + //check whether this is the default fit to option + if (name.equalsIgnoreCase(Config.get("map.defaultZoomFitOption"))) { + menuItem.setSelected(true); + } + return menuItem; + } + public void recreate(OperatingRound or) { log.debug("ORPanel.recreate() called"); @@ -814,20 +823,44 @@ implements ActionListener, KeyListener, RevenueListener { orUIManager.processAction(command, executedActions); } else if (source == zoomIn) { + fitToWindow.setSelected(false); + fitToWidth.setSelected(false); + fitToHeight.setSelected(false); orWindow.getMapPanel().zoom(true); redrawRoutes(); } else if (source == zoomOut) { + fitToWindow.setSelected(false); + fitToWidth.setSelected(false); + fitToHeight.setSelected(false); orWindow.getMapPanel().zoom(false); redrawRoutes(); } else if (source == fitToWindow) { - orWindow.getMapPanel().fitToWindow(); - redrawRoutes(); + if (fitToWindow.isSelected()) { + fitToWidth.setSelected(false); + fitToHeight.setSelected(false); + orWindow.getMapPanel().fitToWindow(); + redrawRoutes(); + } else { + orWindow.getMapPanel().removeFitToOption(); + } } else if (source == fitToWidth) { - orWindow.getMapPanel().fitToWidth(); - redrawRoutes(); + if (fitToWidth.isSelected()) { + fitToWindow.setSelected(false); + fitToHeight.setSelected(false); + orWindow.getMapPanel().fitToWidth(); + redrawRoutes(); + } else { + orWindow.getMapPanel().removeFitToOption(); + } } else if (source == fitToHeight) { - orWindow.getMapPanel().fitToHeight(); - redrawRoutes(); + if (fitToHeight.isSelected()) { + fitToWindow.setSelected(false); + fitToWidth.setSelected(false); + orWindow.getMapPanel().fitToHeight(); + redrawRoutes(); + } else { + orWindow.getMapPanel().removeFitToOption(); + } } else if (source == calibrateMap) { MapManager mapManager = orUIManager.getMap().getMapManager(); String offsetX = JOptionPane.showInputDialog(this, "Change translation in X-dimension", mapManager.getMapXOffset()); diff --git a/rails/ui/swing/hexmap/HexMapImage.java b/rails/ui/swing/hexmap/HexMapImage.java index 06a7af5..ec64685 100644 --- a/rails/ui/swing/hexmap/HexMapImage.java +++ b/rails/ui/swing/hexmap/HexMapImage.java @@ -34,6 +34,8 @@ public final class HexMapImage extends JSVGCanvas { private double zoomFactor = 1; // defined dynamically if zoomStep changed private int zoomStep = 10; // default value, can be overwritten in config private boolean initialized = false; + private Dimension initialMapSize = null; + private int initialZoomStep = 0; public void init(MapManager mapManager,HexMap hexMap) { @@ -82,8 +84,10 @@ public final class HexMapImage extends JSVGCanvas { if (!initialized) { // store the rendering Transform initialTransform = getRenderingTransform(); - scaleMap(); initialized = true; + + //catch up on setting the bounds (if bounds setting were called before rendering prepare) + if (initialMapSize != null) setBoundsAndResize(initialMapSize,initialZoomStep); } addGVTTreeRendererListener(null); } @@ -108,6 +112,16 @@ public final class HexMapImage extends JSVGCanvas { setRenderingTransform (at, true); } + public void setBoundsAndResize (Dimension currentMapSize,int zoomStep) { + if (initialized) { + setBounds(0, 0, currentMapSize.width, currentMapSize.height); + setPreferredSize(currentMapSize); + zoom(zoomStep); + } else { + initialMapSize = currentMapSize; + initialZoomStep = zoomStep; + } + } public void zoom (boolean in) { if (in) zoomStep++; else zoomStep--; zoom(); |
From: Frederick W. <fre...@us...> - 2012-01-10 11:22:28
|
rails/ui/swing/ImageLoader.java | 22 +++++++++- rails/ui/swing/MapPanel.java | 81 ++++++++++++++++++++++++++++++++++++-- rails/ui/swing/hexmap/HexMap.java | 44 ++------------------ 3 files changed, 105 insertions(+), 42 deletions(-) New commits: commit 38e4a6e05fae1349af459ed47c438271dc7373da Author: Frederick Weld <fre...@gm...> Date: Tue Jan 10 12:16:54 2012 +0100 Added round-off to the fit-to-xyz zoom (continuous zoom, scroll bar) The current logic of discrete zoom steps is still valid - but it is complemented by a continuous adjustment factor ("last mile adjustment"). In addition, the appearance and width of the scroll bar is now considered. diff --git a/rails/ui/swing/ImageLoader.java b/rails/ui/swing/ImageLoader.java index b22bcbf..f663639 100644 --- a/rails/ui/swing/ImageLoader.java +++ b/rails/ui/swing/ImageLoader.java @@ -27,6 +27,9 @@ public class ImageLoader { private static Map<Integer, Document> svgMap; private static double[] zoomFactors = new double[21]; + //defines adjustment of zoom factor (should be close to 1) + //(used for perfect-fit sizing that requires arbitrary zoom) + private static double zoomAdjustmentFactor = 1; private static double svgWidth = 75; private static double svgHeight = svgWidth * 0.5 * Math.sqrt(3.0); @@ -129,11 +132,28 @@ public class ImageLoader { if (zoomStep < 0) zoomStep = 0; else if (zoomStep > 20) zoomStep = 20; if (zoomFactors[zoomStep] == 0.0) { - zoomFactors[zoomStep] = 1.0 * Math.pow(2.0, 0.25*(zoomStep-10)); + zoomFactors[zoomStep] = zoomAdjustmentFactor * Math.pow(2.0, 0.25*(zoomStep-10)); } return zoomFactors[zoomStep]; } + + /** + * @param zoomAdjustmentFactor Additional factor applied to zoom factor. Used + * for precisely adjusting zoom-step based zoom factors for perfect fit requirements. + */ + public void setZoomAdjustmentFactor (double zoomAdjustmentFactor) { + ImageLoader.zoomAdjustmentFactor = zoomAdjustmentFactor; + + //invalidate buffered zoom step zoom factors + for (int i = 0 ; i < zoomFactors.length ; i++) { + zoomFactors[i] = 0; + } + } + + public void resetAdjustmentFactor() { + setZoomAdjustmentFactor(1); + } public ImageLoader() { directories.add(tileRootDir + svgTileDir); diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index e1be54b..6175b9b 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -20,11 +20,14 @@ import rails.ui.swing.hexmap.*; public class MapPanel extends JPanel { private static final long serialVersionUID = 1L; + //defines how many pixels should be left as safety margin when calculating fit zooms + private static final int zoomFitSafetyMargin = 4; + private MapManager mmgr; private HexMap map; private HexMapImage mapImage; private JScrollPane scrollPane; - + private GameUIManager gameUIManager; private JLayeredPane layeredPane; @@ -132,8 +135,80 @@ public class MapPanel extends JPanel { adjustToNewMapZoom(); } - private void zoomFit (boolean fitWidth, boolean fitHeight) { - map.zoomFit (getSize(), fitWidth, fitHeight); + /** + * Zoom-to-fit functionality is based on the discrete zoom steps. + * In order to achieve correctly fitting zoom, continuous adjustment factors are + * determined on top of that. + */ + private void zoomFit (boolean fitToWidth, boolean fitToHeight) { + ImageLoader imageLoader = GameUIManager.getImageLoader(); + int zoomStep = map.getZoomStep(); + + //reset adjustment factor + imageLoader.resetAdjustmentFactor(); + + //determine the available size to fit to + //(double needed for subsequent calculations) + double width = getSize().width - zoomFitSafetyMargin; + double height = getSize().height - zoomFitSafetyMargin; + + double idealFactorWidth = width / originalMapSize.width; + double idealFactorHeight = height / originalMapSize.height; + + //determine which dimension will be the critical one for the resize + boolean isWidthCritical = ( !fitToHeight + || (fitToWidth && idealFactorWidth < idealFactorHeight)); + + //check whether scrollbar will appear in the fit-to dimension and + //reduce available size accordingly (not relevant for fit-to-window) + if (isWidthCritical && idealFactorWidth > idealFactorHeight) { + width -= scrollPane.getVerticalScrollBar().getPreferredSize().width; + idealFactorWidth = width / originalMapSize.width; + } + if (!isWidthCritical && idealFactorWidth < idealFactorHeight) { + height -= scrollPane.getHorizontalScrollBar().getPreferredSize().height; + idealFactorHeight = height / originalMapSize.height; + } + + //abort resize if no space available + if (width < 0 || height < 0) return; + + //increase zoomFactor until constraints do not hold + //OR zoom cannot be increased any more + while + ( + ( + (!fitToWidth || idealFactorWidth > imageLoader.getZoomFactor(zoomStep)) + && + (!fitToHeight || idealFactorHeight > imageLoader.getZoomFactor(zoomStep)) + ) + && + imageLoader.getZoomFactor(zoomStep+1) != imageLoader.getZoomFactor(zoomStep) + ) + zoomStep++; + + //decrease zoomFactor until constraints do hold + //OR zoom cannot be decreased any more + while + ( + ( + (fitToWidth && idealFactorWidth < imageLoader.getZoomFactor(zoomStep)) + || + (fitToHeight && idealFactorHeight < imageLoader.getZoomFactor(zoomStep)) + ) + && + imageLoader.getZoomFactor(zoomStep-1) != imageLoader.getZoomFactor(zoomStep) + ) + zoomStep--; + + //Determine and apply adjustment factor for precise fit + double idealFactor = isWidthCritical ? idealFactorWidth : idealFactorHeight; + imageLoader.setZoomAdjustmentFactor ( + idealFactor / imageLoader.getZoomFactor(zoomStep)); + + //trigger zoom execution + map.setZoomStep(zoomStep); + adjustToNewMapZoom(); } diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index 0dc3c1a..e862f6d 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -562,43 +562,15 @@ public abstract class HexMap implements MouseListener, zoom(); } -/** - * Zoom-to-fit functionality is based on the discrete zoom steps. - * This means that no pixel precision is to be expected - */ - public void zoomFit (Dimension availableSize, boolean fitToWidth, boolean fitToHeight) { - double idealFactorWidth = availableSize.getWidth() / originalSize.width; - double idealFactorHeight = availableSize.getHeight() / originalSize.height; - //increase zoomFactor until constraints do not hold - //OR zoom cannot be increased any more - while - ( - ( - (!fitToWidth || idealFactorWidth > GameUIManager.getImageLoader().getZoomFactor(zoomStep)) - && - (!fitToHeight || idealFactorHeight > GameUIManager.getImageLoader().getZoomFactor(zoomStep)) - ) - && - GameUIManager.getImageLoader().getZoomFactor(zoomStep+1) != GameUIManager.getImageLoader().getZoomFactor(zoomStep) - ) - zoomStep++; - //decrease zoomFactor until constraints do hold - //OR zoom cannot be decreased any more - while - ( - ( - (fitToWidth && idealFactorWidth < GameUIManager.getImageLoader().getZoomFactor(zoomStep)) - || - (fitToHeight && idealFactorHeight < GameUIManager.getImageLoader().getZoomFactor(zoomStep)) - ) - && - GameUIManager.getImageLoader().getZoomFactor(zoomStep-1) != GameUIManager.getImageLoader().getZoomFactor(zoomStep) - ) - zoomStep--; - //trigger zoom execution + public void setZoomStep (int zoomStep) { + this.zoomStep = zoomStep; zoom(); } + public int getZoomStep () { + return zoomStep; + } + private void zoom() { zoomFactor = GameUIManager.getImageLoader().getZoomFactor(zoomStep); log.debug("HexMap: zoomStep = "+ zoomStep); @@ -614,10 +586,6 @@ public abstract class HexMap implements MouseListener, scale = (Scale.get() * zoomFactor); } - public int getZoomStep () { - return zoomStep; - } - public Dimension getOriginalSize() { return originalSize; } |
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] |
From: Erik V. <ev...@us...> - 2012-01-06 21:13:10
|
rails/game/StockRound.java | 81 ++++++++----- tools/ListAndFixSavedFiles.java | 245 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 286 insertions(+), 40 deletions(-) New commits: commit 613f819a7535e35d16d19b757019e170e0311fa5 Author: Erik Vos <eri...@xs...> Date: Fri Jan 6 22:06:25 2012 +0100 ListAndFixSavedFiles: added Correct options for BuyTrain and LayTile. A framework was added to create dialogs to update client action settings. The dialogs are internal classes. Dialogs for BuyTrain and LayTile now exist. Other action types can be added easily. diff --git a/tools/ListAndFixSavedFiles.java b/tools/ListAndFixSavedFiles.java index 6a66c25..6b63471 100644 --- a/tools/ListAndFixSavedFiles.java +++ b/tools/ListAndFixSavedFiles.java @@ -2,7 +2,7 @@ package tools; import java.awt.*; import java.awt.event.*; -import java.io.*; +import java.io.File; import java.util.*; import java.util.List; @@ -15,7 +15,7 @@ import rails.common.LocalText; import rails.common.parser.Config; import rails.common.parser.ConfigurationException; import rails.game.*; -import rails.game.action.PossibleAction; +import rails.game.action.*; import rails.ui.swing.elements.ActionMenuItem; import rails.util.GameFileIO; import rails.util.Util; @@ -32,7 +32,10 @@ implements ActionListener, KeyListener { private JMenuBar menuBar; private JMenu fileMenu, editMenu; private JMenuItem saveItem, loadItem; - private JMenuItem trimItem, deleteItem; + private JMenuItem trimItem, deleteItem, correctItem; + + private int correctedIndex; + private PossibleAction correctedAction; private StringBuffer headerText = new StringBuffer(); @@ -42,6 +45,7 @@ implements ActionListener, KeyListener { private static String saveDirectory; private String filepath; + private GameManagerI gameManager; protected static Logger log; @@ -78,9 +82,9 @@ implements ActionListener, KeyListener { messagePanel = new JPanel(new GridBagLayout()); messageScroller = - new JScrollPane(reportText, - ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + new JScrollPane(reportText, + ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); vbar = messageScroller.getVerticalScrollBar(); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = gbc.gridy = 0; @@ -130,6 +134,15 @@ implements ActionListener, KeyListener { deleteItem.setEnabled(true); editMenu.add(deleteItem); + correctItem = new ActionMenuItem("Correct"); + correctItem.setActionCommand("CORRECT"); + correctItem.setMnemonic(KeyEvent.VK_C); + correctItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, + ActionEvent.ALT_MASK)); + correctItem.addActionListener(this); + correctItem.setEnabled(true); + editMenu.add(correctItem); + menuBar.add(fileMenu); menuBar.add(editMenu); @@ -156,16 +169,16 @@ implements ActionListener, KeyListener { JFileChooser jfc = new JFileChooser(); jfc.setCurrentDirectory(new File(saveDirectory)); - + if (jfc.showOpenDialog(getContentPane()) == JFileChooser.APPROVE_OPTION) { File selectedFile = jfc.getSelectedFile(); filepath = selectedFile.getPath(); saveDirectory = selectedFile.getParent(); - + // clear header text headerText = new StringBuffer(); - + // use GameLoader object to load game fileIO = new GameFileIO(); @@ -175,15 +188,17 @@ implements ActionListener, KeyListener { fileIO.initGame(); fileIO.loadActionsAndComments(); setReportText(true); - + } catch (ConfigurationException e) { log.fatal("Load failed", e); DisplayBuffer.add(LocalText.getText("LoadFailed", e.getMessage())); } + + gameManager = fileIO.getGame().getGameManager(); } } - + public void add (String text) { if (text.length() > 0) { headerText.append(text); @@ -269,6 +284,16 @@ implements ActionListener, KeyListener { log.error("Number format exception for '"+result+"'", e); } } + } else if ("CORRECT".equalsIgnoreCase(command)) { + String result = JOptionPane.showInputDialog("Enter action number to be corrected"); + if (Util.hasValue(result)) { + try { + int index = Integer.parseInt(result); + correct (index); + } catch (NumberFormatException e) { + log.error("Number format exception for '"+result+"'", e); + } + } } else if ("SAVE".equalsIgnoreCase(command)) { save(); } else if ("LOAD".equalsIgnoreCase(command)) { @@ -291,6 +316,202 @@ implements ActionListener, KeyListener { } + private void correct (int index) { + correctedAction = fileIO.getActions().get(index); + correctedIndex = index; + if (correctedAction instanceof BuyTrain) { + new BuyTrainDialog ((BuyTrain)correctedAction); + } else if (correctedAction instanceof LayTile) { + new LayTileDialog ((LayTile)correctedAction); + } else { + JOptionPane.showMessageDialog(this, "Action type '" + correctedAction.getClass().getSimpleName() + + "' cannot yet be edited"); + } + } + + protected void processCorrections (PossibleAction newAction) { + if (newAction != null && !newAction.equalsAsAction(correctedAction)) { + fileIO.getActions().set(correctedIndex, newAction); + setReportText(false); + } + } + + private abstract class EditDialog extends JDialog implements ActionListener { + + private static final long serialVersionUID = 1L; + List<Object> originalValues = new ArrayList<Object>(); + List<JComponent> inputElements = new ArrayList<JComponent>(); + GridBagConstraints gc = new GridBagConstraints(); + int length = 0; + JButton okButton, cancelButton; + + EditDialog (String title) { + super((Frame) null, title, false); // Non-modal + getContentPane().setLayout(new GridBagLayout()); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + } + + void finish() { + + addField (this, okButton = new JButton("OK"), ++length, 0); + okButton.addActionListener(this); + addField (this, cancelButton = new JButton("Cancel"), length, 1); + cancelButton.addActionListener(this); + pack(); + + // Center on window + int x = (int) messageWindow.getLocationOnScreen().getX() + + (messageWindow.getWidth() - getWidth()) / 2; + int y = (int) messageWindow.getLocationOnScreen().getY() + + (messageWindow.getHeight() - getHeight()) / 2; + setLocation(x, y); + + setVisible(true); + setAlwaysOnTop(true); + } + + public void actionPerformed(ActionEvent arg0) { + + if (arg0.getSource().equals(okButton)) { + PossibleAction newAction = processInput(); + if (newAction != null) messageWindow.processCorrections(newAction); + } else if (arg0.getSource().equals(cancelButton)) {; + + } + this.setVisible(false); + this.dispose(); + + } + + abstract PossibleAction processInput(); + } + + private class BuyTrainDialog extends EditDialog { + + private static final long serialVersionUID = 1L; + BuyTrain action; + + BuyTrainDialog (BuyTrain action) { + super ("Edit BuyTrain"); + this.action = action; + addLabel (this, "Train UID", null, action.getTrain().getUniqueId()); // 0 + addLabel (this, "From Portfolio", null, action.getFromPortfolio().getName()); // 1 + addTextField (this, "Price paid", + new Integer(action.getPricePaid()), + String.valueOf(action.getPricePaid())); // 2 + addTextField (this, "Added cash", + new Integer(action.getAddedCash()), + String.valueOf(action.getAddedCash())); // 3 + addTextField (this, "Exchange train UID", + action.getExchangedTrain(), + action.getExchangedTrain() != null ? action.getExchangedTrain().getUniqueId() : ""); // 4 + finish(); + } + + @Override + PossibleAction processInput() { + + log.debug("Action was "+action); + try { + int pricePaid = Integer.parseInt(((JTextField)inputElements.get(2)).getText()); + action.setPricePaid(pricePaid); + } catch (NumberFormatException e) { + } + try { + int addedCash = Integer.parseInt(((JTextField)inputElements.get(3)).getText()); + action.setAddedCash(addedCash); + } catch (NumberFormatException e) { + } + String exchangedTrainID = ((JTextField)inputElements.get(4)).getText(); + TrainI exchangedTrain = gameManager.getTrainManager().getTrainByUniqueId(exchangedTrainID); + if (exchangedTrain != null) action.setExchangedTrain(exchangedTrain); + + log.debug("Action is "+action); + return action; + + } + } + + private class LayTileDialog extends EditDialog { + + private static final long serialVersionUID = 1L; + LayTile action; + + LayTileDialog (LayTile action) { + super ("Edit LayTile"); + this.action = action; + addTextField (this, "Tile laid", + action.getLaidTile(), + action.getLaidTile().getName()); // 0 + addTextField (this, "Hex laid", + action.getChosenHex(), + action.getChosenHex().getName()); // 1 + addTextField (this, "Orientation", + new Integer(action.getOrientation()), + String.valueOf(action.getOrientation())); // 2 + finish(); + } + + @Override + PossibleAction processInput() { + + log.debug("Action was "+action); + try { + int tileID = Integer.parseInt(((JTextField)inputElements.get(0)).getText()); + TileI tile = gameManager.getTileManager().getTile(tileID); + if (tileID > 0 && tile != null) action.setLaidTile(tile); + } catch (NumberFormatException e) { + } + String hexID = ((JTextField)inputElements.get(1)).getText(); + MapHex hex = gameManager.getMapManager().getHex(hexID); + if (hexID != null && hex != null) action.setChosenHex(hex); + try { + int orientation = Integer.parseInt(((JTextField)inputElements.get(2)).getText()); + action.setOrientation(orientation); + } catch (NumberFormatException e) { + } + + log.debug("Action is "+action); + return action; + + } + } + + protected void addLabel (EditDialog owner, String caption, Object initialObject, String initialValue) { + + JComponent element = new JLabel (initialValue); + int index = owner.length++; + addField (owner, new JLabel (caption), index, 0); + addField (owner, element, index, 1); + owner.originalValues.add(initialObject); + owner.inputElements.add(element); + } + + protected void addTextField (EditDialog owner, String caption, Object initialObject, String initialValue) { + + JComponent element = new JTextField (initialValue); + int index = owner.length++; + addField (owner, new JLabel (caption), index, 0); + addField (owner, element, index, 1); + owner.originalValues.add(initialObject); + owner.inputElements.add(element); + } + + protected void addField(EditDialog owner, JComponent comp, int y, int x) { + + GridBagConstraints gbc = owner.gc; + gbc.gridx = x; + gbc.gridy = y; + gbc.gridwidth = 1; + gbc.gridheight = 1; + gbc.weightx = gbc.weighty = 0.5; + gbc.fill = GridBagConstraints.BOTH; + + owner.getContentPane().add(comp, gbc); + + comp.setVisible(true); + } + public void keyPressed(KeyEvent e) { } @@ -298,4 +519,6 @@ implements ActionListener, KeyListener { public void keyTyped(KeyEvent e) {} + } + commit 73886c53437f48e72a2bc3868d075be322e4ddbd Author: Erik Vos <eri...@xs...> Date: Fri Jan 6 16:51:04 2012 +0100 Enforce selling over-limit shares first. Being over limits was announced but immediate selling was not enforced. diff --git a/rails/game/StockRound.java b/rails/game/StockRound.java index 8728af0..ca25bf3 100644 --- a/rails/game/StockRound.java +++ b/rails/game/StockRound.java @@ -59,6 +59,10 @@ public class StockRound extends Round { protected int sequenceRule; protected boolean raiseIfSoldOut = false; + /* Temporary variables */ + protected boolean isOverLimits = false; + protected String overLimitsDetail = null; + /** * Constructor with the GameManager, will call super class (Round's) Constructor to initialize * @@ -88,7 +92,7 @@ public class StockRound extends Round { getStockRoundNumber())); BackgroundMusicManager.notifyOfStockRoundStart(); - + setCurrentPlayerIndex(gameManager.getPriorityPlayer().getIndex()); startingPlayer = getCurrentPlayer(); // For the Report ReportBuffer.add(LocalText.getText("HasPriority", @@ -116,13 +120,9 @@ public class StockRound extends Round { setSellableShares(); - // check certification limits and display warning - if (isPlayerOverLimits (currentPlayer)) { - DisplayBuffer.add(LocalText.getText("ExceedCertificateLimit" - , currentPlayer.getName() - , isPlayerOverLimitsDetail(currentPlayer) - ) - ); + // Certificate limits must be obeyed by selling excess shares + // before any other action is allowed. + if (isOverLimits) { return true; } @@ -358,6 +358,7 @@ public class StockRound extends Round { * @return List of sellable certificates. */ public void setSellableShares() { + if (!mayCurrentPlayerSellAnything()) return; String compName; @@ -368,6 +369,9 @@ public class StockRound extends Round { int extraSingleShares = 0; boolean choiceOfPresidentExchangeCerts = false; Portfolio playerPortfolio = currentPlayer.getPortfolio(); + isOverLimits = false; + overLimitsDetail = null; + StringBuilder violations = new StringBuilder(); /* * First check of which companies the player owns stock, and what @@ -389,6 +393,22 @@ public class StockRound extends Round { - pool.getShare(company)); if (maxShareToSell == 0) continue; + // Is player over the hold limit of this company? + if (!checkAgainstHoldLimit(currentPlayer, company, 0)) { + // The first time this happens, remove all non-over-limits sell options + if (!isOverLimits) possibleActions.clear(); + isOverLimits = true; + violations.append(LocalText.getText("ExceedCertificateLimitCompany", + company.getName(), + playerPortfolio.getShare(company), + getGameParameterAsInt(GameDef.Parm.PLAYER_SHARE_LIMIT) + )); + + } else { + // If within limits, but an over-limits situation exists: correct that first. + if (isOverLimits) continue; + } + /* * If the current Player is president, check if he can dump the * presidency onto someone else. @@ -486,6 +506,23 @@ public class StockRound extends Round { } } } + + // Is player over the total certificate hold limit? + float certificateCount = playerPortfolio.getCertificateCount(); + int certificateLimit = gameManager.getPlayerCertificateLimit(currentPlayer); + if (certificateCount > certificateLimit) { + violations.append(LocalText.getText("ExceedCertificateLimitTotal", + certificateCount, + certificateLimit)); + isOverLimits = true; + } + + if (isOverLimits) { + DisplayBuffer.add(LocalText.getText("ExceedCertificateLimit" + , currentPlayer.getName() + , violations.toString() + )); + } } protected void setSpecialActions() { @@ -1434,7 +1471,6 @@ public class StockRound extends Round { hasSoldThisTurnBeforeBuying.set(false); hasActed.set(false); if (currentPlayer == startingPlayer) ReportBuffer.add(""); - } /** @@ -1492,44 +1528,31 @@ public class StockRound extends Round { /** * Can the current player do any buying? + * <p>Note: requires sellable shares to be checked BEFORE buyable shares * * @return True if any buying is allowed. */ public boolean mayCurrentPlayerBuyAnything() { - return !isPlayerOverLimits(currentPlayer) - && companyBoughtThisTurnWrapper.get() == null; + return !isOverLimits && companyBoughtThisTurnWrapper.get() == null; } + // Only used now to check if Autopass must be reset. protected boolean isPlayerOverLimits(Player player) { - return (isPlayerOverLimitsDetail(player) != null); - } - - protected String isPlayerOverLimitsDetail(Player player) { - StringBuffer violations = new StringBuffer(); // Over the total certificate hold Limit? if (player.getPortfolio().getCertificateCount() > gameManager.getPlayerCertificateLimit(player)) { - violations.append(LocalText.getText("ExceedCertificateLimitTotal", - player.getPortfolio().getCertificateCount(), - gameManager.getPlayerCertificateLimit(player))); + return true; } // Over the hold limit of any company? for (PublicCompanyI company : companyManager.getAllPublicCompanies()) { if (company.hasStarted() && company.hasStockPrice() && !checkAgainstHoldLimit(player, company, 0)) { - violations.append(LocalText.getText("ExceedCertificateLimitCompany", - company.getName(), - player.getPortfolio().getShare(company), - getGameParameterAsInt(GameDef.Parm.PLAYER_SHARE_LIMIT) - )); + return true; } } - if (violations.length() != 0) { - return violations.toString(); - } else { - return null; - } + + return false; } /** |
From: Erik V. <ev...@us...> - 2012-01-05 14:29:07
|
rails/ui/swing/StartRoundWindow.java | 89 +++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 24 deletions(-) New commits: commit 985d6827aa5b9d985ef97d0fd9f18165f388ff55 Author: Erik Vos <eri...@xs...> Date: Thu Jan 5 15:27:02 2012 +0100 Change president share price setting in Start rounds to use non-modal pop-up. The popup is the same RadioButtonDialog that is already used when setting a start share price in stock rounds. diff --git a/rails/ui/swing/StartRoundWindow.java b/rails/ui/swing/StartRoundWindow.java index d27294b..2282593 100644 --- a/rails/ui/swing/StartRoundWindow.java +++ b/rails/ui/swing/StartRoundWindow.java @@ -19,8 +19,9 @@ import rails.ui.swing.elements.*; /** * This displays the Auction Window */ -public class StartRoundWindow extends JFrame implements ActionListener, -KeyListener, ActionPerformer { +public class StartRoundWindow extends JFrame +implements ActionListener, KeyListener, ActionPerformer, DialogOwner { + private static final long serialVersionUID = 1L; // Gap sizes between screen cells, in pixels @@ -81,6 +82,11 @@ KeyListener, ActionPerformer { private StartRound round; private GameUIManager gameUIManager; + // For the non-modal dialog to ask for a company starting share price. + protected JDialog currentDialog = null; + protected PossibleAction currentDialogAction = null; + protected int[] startPrices = null; + private StartItem si; private JComponent f; @@ -516,7 +522,7 @@ KeyListener, ActionPerformer { StartItemAction action = (StartItemAction) nextAction; if (action instanceof BuyStartItem) { requestStartPrice((BuyStartItem) action); - return process(action); + return false; } } } @@ -577,8 +583,7 @@ KeyListener, ActionPerformer { if (source == buyButton) { if (activeItem instanceof BuyStartItem && ((BuyStartItem) activeItem).hasSharePriceToSet()) { - if (requestStartPrice((BuyStartItem) activeItem)) - process(activeItem); + if (requestStartPrice((BuyStartItem) activeItem)) return; } else { process(activeItem); } @@ -611,34 +616,70 @@ KeyListener, ActionPerformer { List<StockSpaceI> startSpaces = stockMarket.getStartSpaces(); Map<Integer, StockSpaceI> spacePerPrice = new HashMap<Integer, StockSpaceI>(); - int[] prices = new int[startSpaces.size()]; - StockSpaceI[] options = new StockSpaceI[startSpaces.size()]; + startPrices = new int[startSpaces.size()]; + String[] options = new String[startSpaces.size()]; for (int i = 0; i < startSpaces.size(); i++) { - prices[i] = startSpaces.get(i).getPrice(); - spacePerPrice.put(prices[i], startSpaces.get(i)); + startPrices[i] = startSpaces.get(i).getPrice(); + spacePerPrice.put(startPrices[i], startSpaces.get(i)); } - Arrays.sort(prices); + Arrays.sort(startPrices); for (int i = 0; i < startSpaces.size(); i++) { - options[i] = spacePerPrice.get(prices[i]); + options[i] = Bank.format(spacePerPrice.get(startPrices[i]).getPrice()); } - StockSpace sp = - (StockSpace) JOptionPane.showInputDialog(this, - LocalText.getText("WHICH_START_PRICE", - activeItem.getPlayerName(), - compName), - LocalText.getText("WHICH_PRICE"), - JOptionPane.QUESTION_MESSAGE, null, options, - options[0]); - if (sp == null) { - return false; - } - int price = sp.getPrice(); - activeItem.setAssociatedSharePrice(price); + RadioButtonDialog dialog = new RadioButtonDialog(this, + this, + LocalText.getText("PleaseSelect"), + LocalText.getText("WHICH_START_PRICE", + getSRPlayer(), + compName), + options, + -1); + setCurrentDialog (dialog, activeItem); + } return true; } + public JDialog getCurrentDialog() { + return currentDialog; + } + + public PossibleAction getCurrentDialogAction () { + return currentDialogAction; + } + + public void setCurrentDialog (JDialog dialog, PossibleAction action) { + if (currentDialog != null) { + currentDialog.dispose(); + } + currentDialog = dialog; + currentDialogAction = action; + } + + public void dialogActionPerformed () { + + if (currentDialog instanceof RadioButtonDialog + && currentDialogAction instanceof BuyStartItem) { + + RadioButtonDialog dialog = (RadioButtonDialog) currentDialog; + BuyStartItem action = (BuyStartItem) currentDialogAction; + + int index = dialog.getSelectedOption(); + if (index >= 0) { + int price = startPrices[index]; + action.setAssociatedSharePrice(price); + process (action); + } else { + // No selection done - no action + return; + } + + } else { + return; + } + } + public void close() { this.dispose(); } |
From: Stefan F. <ste...@us...> - 2012-01-05 10:40:04
|
rails/algorithms/RevenueAdapter.java | 3 rails/ui/swing/ORPanel.java | 137 ++++++++++++++++------------------- 2 files changed, 68 insertions(+), 72 deletions(-) New commits: commit ccf5b2aa3e251ab06f29ec95cf90307ae77427f5 Author: Frederick Weld <fre...@gm...> Date: Wed Jan 4 17:07:03 2012 +0100 Routes of current company calculated asynchronously Polished the handling of route calculations. This was needed as a follow-up to introducing persistent route display of the current company. Achieved the following: - All route calculations are performed asynchronously (as it was already the case before for set-revenue route calculations). - ORPanel now only uses one revenue adapter for both use cases (current route display and set-revenue calculation). Signed-off-by: Stefan Frey <ste...@we...> diff --git a/rails/algorithms/RevenueAdapter.java b/rails/algorithms/RevenueAdapter.java index 9df031a..a08d47b 100644 --- a/rails/algorithms/RevenueAdapter.java +++ b/rails/algorithms/RevenueAdapter.java @@ -651,7 +651,8 @@ public final class RevenueAdapter implements Runnable { EventQueue.invokeLater( new Runnable() { public void run() { - revenueListener.revenueUpdate(revenue, finalResult); + //listener could have deregistered himself in the meantime + if (revenueListener != null) revenueListener.revenueUpdate(revenue, finalResult); } }); } diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 6c1be18..c29ca74 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -116,10 +116,7 @@ implements ActionListener, KeyListener, RevenueListener { private PublicCompanyI orComp = null; - //for displaying routes of the currently active company - private RevenueAdapter currentRoutesRevenueAdapter = null; - - //for displaying routes of the "set revenue" step + private boolean isRevenueValueToBeSet = false; private RevenueAdapter revenueAdapter = null; private Thread revenueThread = null; @@ -718,7 +715,6 @@ implements ActionListener, KeyListener, RevenueListener { orUIManager.getMap().setTrainPaths(null); //but retain paths already existing before if (revenueAdapter != null) revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - if (currentRoutesRevenueAdapter != null) currentRoutesRevenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); orUIManager.getMap().repaint(); } } @@ -738,19 +734,14 @@ implements ActionListener, KeyListener, RevenueListener { undoButton.setEnabled(false); redoButton.setEnabled(false); - removeCurrentRoutes(); + disableRoutesDisplay(); } private void redrawRoutes() { - if (revenueAdapter != null && displayRevenueRoutes()) { + if (revenueAdapter != null && isDisplayRoutes()) { revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); orUIManager.getMap().repaint(); } - if (currentRoutesRevenueAdapter != null && displayCurrentRoutes()) { - currentRoutesRevenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); - } - } public void actionPerformed(ActionEvent actor) { @@ -864,13 +855,14 @@ implements ActionListener, KeyListener, RevenueListener { /** * - * @return True if route calculation is active and if the routes of the currently - * active company are not displayed all the time (only if this is not the case, - * it makes sense to display routes for the set revenue step) + * @return True if route should be displayed (at least for the set revenue step) */ - private boolean displayRevenueRoutes() { - return (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.ROUTE_HIGHLIGHT) - && "no".equalsIgnoreCase(Config.get("map.displayCurrentRoutes"))); + private boolean isDisplayRoutes() { + return (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.ROUTE_HIGHLIGHT)); + } + + private boolean isSuggestRevenue() { + return (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.REVENUE_SUGGEST)); } /** @@ -878,39 +870,56 @@ implements ActionListener, KeyListener, RevenueListener { * @return True if the routes of the currently active company should be displayed. * As a prerequisite of this feature, route highlighting has to be enabled/supported. */ - private boolean displayCurrentRoutes() { - return (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.ROUTE_HIGHLIGHT) + private boolean isDisplayCurrentRoutes() { + return (isDisplayRoutes() && "yes".equalsIgnoreCase(Config.get("map.displayCurrentRoutes"))); } /** - * routes of the current company are removed from the map + * any routes currently displayed on the map are removed + * In addition, revenue adapter and its thread are interrupted / removed. */ - private void removeCurrentRoutes() { - if (currentRoutesRevenueAdapter != null) { - orUIManager.getMap().setTrainPaths(null); - currentRoutesRevenueAdapter = null; - orUIManager.getMap().repaint(); + private void disableRoutesDisplay() { + clearRevenueAdapter(); + orUIManager.getMap().setTrainPaths(null); + orUIManager.getMap().repaint(); + } + + private void clearRevenueAdapter() { + if (revenueThread != null) { + revenueThread.interrupt(); + revenueThread = null; + } + if (revenueAdapter != null) { + revenueAdapter.removeRevenueListener(); + revenueAdapter = null; } } - private void updateCurrentRoutes() { + private void updateCurrentRoutes(boolean isSetRevenueStep) { - //remove current routes also if display option is not active - //(as it could have just been turned off) - removeCurrentRoutes(); + // initialize and start the revenue adapter if routes to be displayed + // or revenue to be suggested in the revenue step + if (isDisplayCurrentRoutes() || (isSuggestRevenue() && isSetRevenueStep)) { + + //only consider revenue quantification for the set revenue step and only + //if suggest option is on + isRevenueValueToBeSet = isSetRevenueStep ? isSuggestRevenue() : false; - //calculate routes for the current company - if (displayCurrentRoutes()) { GameManagerI gm = orUIManager.getGameUIManager().getGameManager(); - currentRoutesRevenueAdapter = RevenueAdapter.createRevenueAdapter( - gm, orComp, gm.getCurrentPhase()); - currentRoutesRevenueAdapter.initRevenueCalculator(true); - currentRoutesRevenueAdapter.calculateRevenue(); - currentRoutesRevenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); + revenueAdapter = RevenueAdapter.createRevenueAdapter(gm, orComp, gm.getCurrentPhase()); + revenueAdapter.initRevenueCalculator(true); + revenueAdapter.addRevenueListener(this); + revenueThread = new Thread(revenueAdapter); + revenueThread.start(); + } else { + + //remove current routes also if display option is not active + //(as it could have just been turned off) + clearRevenueAdapter(); + disableRoutesDisplay(); } - + } public void initORCompanyTurn(PublicCompanyI orComp, int orCompIndex) { @@ -929,13 +938,15 @@ implements ActionListener, KeyListener, RevenueListener { button2.setEnabled(false); button3.setEnabled(false); - updateCurrentRoutes(); + updateCurrentRoutes(false); + } public void initTileLayingStep() { tileCaption.setHighlight(true); button1.setVisible(false); + } public void initTokenLayingStep() { @@ -944,6 +955,7 @@ implements ActionListener, KeyListener, RevenueListener { button1.setEnabled(false); button1.setVisible(false); button3.setEnabled(false); + } public void initRevenueEntryStep(int orCompIndex, SetDividend action) { @@ -959,46 +971,29 @@ implements ActionListener, KeyListener, RevenueListener { button1.setMnemonic(KeyEvent.VK_R); button1.setEnabled(true); button1.setVisible(true); - - // initialize and start the revenue adapter - if (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.REVENUE_SUGGEST)) { - revenueAdapter = initRevenueCalculation(orComp); - revenueThread = new Thread(revenueAdapter); - revenueThread.start(); - } + + //indicate interest in setting revenue values (and not only displaying routes) + updateCurrentRoutes(true); } - private RevenueAdapter initRevenueCalculation(PublicCompanyI company){ - GameManagerI gm = orUIManager.getGameUIManager().getGameManager(); - RevenueAdapter ra = RevenueAdapter.createRevenueAdapter(gm, company, gm.getCurrentPhase()); - ra.initRevenueCalculator(true); - ra.addRevenueListener(this); - return ra; - } - public void revenueUpdate(int bestRevenue, boolean finalResult) { - revenueSelect[orCompIndex].setValue(bestRevenue); + if (isRevenueValueToBeSet) { + revenueSelect[orCompIndex].setValue(bestRevenue); + } if (finalResult) { - if (displayRevenueRoutes()) { - revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); + 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))); + orUIManager.addDetail(Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(true))); } - orUIManager.addInformation("Best Run Value = " + bestRevenue + - " with " + Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(false))); - orUIManager.addDetail(Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(true))); } } public void stopRevenueUpdate() { - if (displayRevenueRoutes()) orUIManager.getMap().setTrainPaths(null); - if (revenueThread != null) { - revenueThread.interrupt(); - revenueThread = null; - } - if (revenueAdapter != null) { - revenueAdapter.removeRevenueListener(); - revenueAdapter = null; - } + isRevenueValueToBeSet = false; } |
From: Stefan F. <ste...@us...> - 2012-01-04 14:18:32
|
LocalisedText.properties | 5 + data/Properties.xml | 5 + rails/ui/swing/ORPanel.java | 111 ++++++++++++++++++++++++++------------ rails/ui/swing/hexmap/GUIHex.java | 7 ++ rails/ui/swing/hexmap/HexMap.java | 40 +++++++++---- 5 files changed, 119 insertions(+), 49 deletions(-) New commits: commit b219711f9415088441fe6cbc9d356cdce079e9d9 Author: Frederick Weld <fre...@gm...> Date: Tue Jan 3 21:15:32 2012 +0100 Added option to display optimal routes of currently active company If this option is chosen, optimal routes are displayed for each OR step. This option replaces prior keyboard shortcut Ctrl+N which had some disadvantages (popup, optimal route display only temporary). The config section "map/report" has been split as it contained too many items after adding aforementioned option. Signed-off-by: Stefan Frey <ste...@we...> diff --git a/LocalisedText.properties b/LocalisedText.properties index a3fdd12..8a1f4f7 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.map.displayCurrentRoutes=If enabled, optimal train routes are displayed for the company which is currently taking its turn. 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 @@ -180,6 +181,7 @@ Config.label.font.ui.style=Font style Config.label.local.player.name=Local player (for pbem) 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.zoomstep=Map zoomstep Config.label.money_format=Money format @@ -209,9 +211,10 @@ Config.section.Format=Format/Colors Config.section.General=General Config.section.Log=Log Config.section.Font=Fonts +Config.section.Map=Map Config.section.Save=Save Config.section.Sound=Sound -Config.section.UI=Map/Report +Config.section.Windows=Windows ConfirmToken=Press Lay Token to confirm token, click another city hex, or press the No Token button. connected=connected CorrectCashAddMoney=CORRECTION: {0} receives {1} from the bank diff --git a/data/Properties.xml b/data/Properties.xml index 231e6e6..29e377f 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -27,10 +27,13 @@ <Property name="font.ui.style" type="LIST" values="plain,bold" initClass="rails.ui.swing.GameUIManager" initMethod="updateUILookAndFeel" initParameter="no" /> </Section> - <Section name="UI"> + <Section name="Map"> <Property name="map.autoscroll" type="BOOLEAN" /> <Property name="map.zoomstep" type="INTEGER" /> <Property name="map.image.display" type="BOOLEAN" /> + <Property name="map.displayCurrentRoutes" type="BOOLEAN" /> + </Section> + <Section name="Windows"> <Property name="report.window.type" type="LIST" values="static,dynamic" /> <Property name="report.window.open" type="BOOLEAN" /> <Property name="report.window.editable" type="BOOLEAN" /> diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index e88b788..6c1be18 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -15,6 +15,7 @@ import org.jgrapht.graph.SimpleGraph; import rails.algorithms.*; import rails.common.GuiDef; import rails.common.LocalText; +import rails.common.parser.Config; import rails.game.*; import rails.game.action.*; import rails.ui.swing.elements.*; @@ -115,6 +116,10 @@ implements ActionListener, KeyListener, RevenueListener { private PublicCompanyI orComp = null; + //for displaying routes of the currently active company + private RevenueAdapter currentRoutesRevenueAdapter = null; + + //for displaying routes of the "set revenue" step private RevenueAdapter revenueAdapter = null; private Thread revenueThread = null; @@ -713,6 +718,7 @@ implements ActionListener, KeyListener, RevenueListener { orUIManager.getMap().setTrainPaths(null); //but retain paths already existing before if (revenueAdapter != null) revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + if (currentRoutesRevenueAdapter != null) currentRoutesRevenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); orUIManager.getMap().repaint(); } } @@ -732,8 +738,21 @@ implements ActionListener, KeyListener, RevenueListener { undoButton.setEnabled(false); redoButton.setEnabled(false); + removeCurrentRoutes(); } + private void redrawRoutes() { + if (revenueAdapter != null && displayRevenueRoutes()) { + revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + orUIManager.getMap().repaint(); + } + if (currentRoutesRevenueAdapter != null && displayCurrentRoutes()) { + currentRoutesRevenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + orUIManager.getMap().repaint(); + } + + } + public void actionPerformed(ActionEvent actor) { // What kind action has been taken? @@ -762,34 +781,19 @@ implements ActionListener, KeyListener, RevenueListener { orUIManager.processAction(command, executedActions); } else if (source == zoomIn) { orWindow.getMapPanel().zoom(true); - if (revenueAdapter != null) { - revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); - } + redrawRoutes(); } else if (source == zoomOut) { orWindow.getMapPanel().zoom(false); - if (revenueAdapter != null) { - revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); - } + redrawRoutes(); } else if (source == fitToWindow) { orWindow.getMapPanel().fitToWindow(); - if (revenueAdapter != null) { - revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); - } + redrawRoutes(); } else if (source == fitToWidth) { orWindow.getMapPanel().fitToWidth(); - if (revenueAdapter != null) { - revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); - } + redrawRoutes(); } else if (source == fitToHeight) { orWindow.getMapPanel().fitToHeight(); - if (revenueAdapter != null) { - revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); - } + redrawRoutes(); } else if (source == calibrateMap) { MapManager mapManager = orUIManager.getMap().getMapManager(); String offsetX = JOptionPane.showInputDialog(this, "Change translation in X-dimension", mapManager.getMapXOffset()); @@ -859,19 +863,54 @@ implements ActionListener, KeyListener, RevenueListener { } /** - * Sets the keyboard shortcut (CTRL+N) for displaying routes of the given company + * + * @return True if route calculation is active and if the routes of the currently + * active company are not displayed all the time (only if this is not the case, + * it makes sense to display routes for the set revenue step) */ - private void setKeyboardShortcutForNetwork(PublicCompanyI orComp) { - if (networkInfoMenu == null) return; - for (int i=0 ; i<networkInfoMenu.getItemCount(); i++) { - JMenuItem item = networkInfoMenu.getItem(i); - if (item.getAccelerator() != null) item.setAccelerator(null); - if (item.getText().equals(orComp.getName())) { - item.setAccelerator(KeyStroke.getKeyStroke( - KeyEvent.VK_N , ActionEvent.CTRL_MASK )); - } + private boolean displayRevenueRoutes() { + return (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.ROUTE_HIGHLIGHT) + && "no".equalsIgnoreCase(Config.get("map.displayCurrentRoutes"))); + } + + /** + * + * @return True if the routes of the currently active company should be displayed. + * As a prerequisite of this feature, route highlighting has to be enabled/supported. + */ + private boolean displayCurrentRoutes() { + return (orUIManager.gameUIManager.getGameParameterAsBoolean(GuiDef.Parm.ROUTE_HIGHLIGHT) + && "yes".equalsIgnoreCase(Config.get("map.displayCurrentRoutes"))); + } + + /** + * routes of the current company are removed from the map + */ + private void removeCurrentRoutes() { + if (currentRoutesRevenueAdapter != null) { + orUIManager.getMap().setTrainPaths(null); + currentRoutesRevenueAdapter = null; + orUIManager.getMap().repaint(); } - + } + + private void updateCurrentRoutes() { + + //remove current routes also if display option is not active + //(as it could have just been turned off) + removeCurrentRoutes(); + + //calculate routes for the current company + if (displayCurrentRoutes()) { + GameManagerI gm = orUIManager.getGameUIManager().getGameManager(); + currentRoutesRevenueAdapter = RevenueAdapter.createRevenueAdapter( + gm, orComp, gm.getCurrentPhase()); + currentRoutesRevenueAdapter.initRevenueCalculator(true); + currentRoutesRevenueAdapter.calculateRevenue(); + currentRoutesRevenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + orUIManager.getMap().repaint(); + } + } public void initORCompanyTurn(PublicCompanyI orComp, int orCompIndex) { @@ -890,7 +929,7 @@ implements ActionListener, KeyListener, RevenueListener { button2.setEnabled(false); button3.setEnabled(false); - setKeyboardShortcutForNetwork(orComp); + updateCurrentRoutes(); } public void initTileLayingStep() { @@ -940,8 +979,10 @@ implements ActionListener, KeyListener, RevenueListener { public void revenueUpdate(int bestRevenue, boolean finalResult) { revenueSelect[orCompIndex].setValue(bestRevenue); if (finalResult) { - revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); - orUIManager.getMap().repaint(); + if (displayRevenueRoutes()) { + revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + orUIManager.getMap().repaint(); + } orUIManager.addInformation("Best Run Value = " + bestRevenue + " with " + Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(false))); orUIManager.addDetail(Util.convertToHtml(revenueAdapter.getOptimalRunPrettyPrint(true))); @@ -949,7 +990,7 @@ implements ActionListener, KeyListener, RevenueListener { } public void stopRevenueUpdate() { - orUIManager.getMap().setTrainPaths(null); + if (displayRevenueRoutes()) orUIManager.getMap().setTrainPaths(null); if (revenueThread != null) { revenueThread.interrupt(); revenueThread = null; commit 3edaa4dd563f7638f5cd13c758d4ffa757a2f3c6 Author: Frederick Weld <fre...@gm...> Date: Tue Jan 3 20:05:42 2012 +0100 Fixed hexmap layering (tokens and text now displayed on top of routes) Before, route strokes were placed on top of the map, thus hiding potentially valuable information. This has been adjusted: Train routes are now drawn on top of the hexes but below any further map information (tokens, home bases, texts for costs, special tokens) Signed-off-by: Stefan Frey <ste...@we...> diff --git a/rails/ui/swing/hexmap/GUIHex.java b/rails/ui/swing/hexmap/GUIHex.java index e083c44..0ed9017 100644 --- a/rails/ui/swing/hexmap/GUIHex.java +++ b/rails/ui/swing/hexmap/GUIHex.java @@ -332,7 +332,7 @@ public class GUIHex implements ViewObject { return polygon; } - public void paint(Graphics g) { + public void paintHexagon(Graphics g) { Graphics2D g2 = (Graphics2D) g; tilePainted = provisionalGUITile != null && hexMap.isTilePainted(provisionalGUITile.getTileId()) @@ -389,6 +389,11 @@ public class GUIHex implements ViewObject { } if (tilePainted) paintOverlay(g2); + } + + public void paintTokensAndText(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + paintStationTokens(g2); paintOffStationTokens(g2); diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index 7ae00c8..09d2492 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -301,7 +301,7 @@ public abstract class HexMap extends JComponent implements MouseListener, if (g.hitClip(hexrect.x, hexrect.y, hexrect.width, hexrect.height)) { - hex.paint(g); + hex.paintHexagon(g); } } @@ -315,17 +315,35 @@ public abstract class HexMap extends JComponent implements MouseListener, } } - // paint train paths Graphics2D g2 = (Graphics2D) g; - Stroke trainStroke = - new BasicStroke((int)(strokeWidth * zoomFactor), strokeCap, strokeJoin); - g2.setStroke(trainStroke); - - Color[] trainColors = new Color[]{colour1, colour2, colour3, colour4}; - int color = 0; - for (GeneralPath path:trainPaths) { - g2.setColor(trainColors[color++ % trainColors.length]); - g2.draw(path); + + // paint train paths + if (trainPaths != null) { + Stroke oldStroke = g2.getStroke(); + Color oldColor = g2.getColor(); + Stroke trainStroke = + new BasicStroke((int)(strokeWidth * zoomFactor), strokeCap, strokeJoin); + g2.setStroke(trainStroke); + + Color[] trainColors = new Color[]{colour1, colour2, colour3, colour4}; + int color = 0; + for (GeneralPath path:trainPaths) { + g2.setColor(trainColors[color++ % trainColors.length]); + g2.draw(path); + } + g2.setStroke(oldStroke); + g2.setColor(oldColor); + } + + // Paint station tokens only after the train paths + // (so that the path strokes do not hide token information) + for (GUIHex hex : hexes) { + Rectangle hexrect = hex.getBounds(); + + if (g.hitClip(hexrect.x, hexrect.y, hexrect.width, + hexrect.height)) { + hex.paintTokensAndText(g2); + } } } catch (NullPointerException ex) { |
From: Stefan F. <ste...@us...> - 2012-01-02 18:42:02
|
LocalisedText.properties | 2 ++ rails/ui/swing/ORPanel.java | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) New commits: commit 39ac84492244350708aa503a7c23c81997e2955f Author: Frederick Weld <fre...@gm...> Date: Fri Dec 30 21:19:13 2011 +0100 Added user-friendly network info including keyboard shortcut Provided for a non-developer version of the network info menu. Differences to the developer-only version (available before): - omitting the menu item for the complete network graph - providing a localized dialog text for the dialog - omitting train run information and train simulation Applied further extensions to network info menu (also valid for the developer-only version): - Keyboard shortcut (Ctrl+N) dynamically assigned to the network info menu item of the currently operating company - Network info run visualization takes care of potential conflicts with the visualization of the set revenue step - Network info run visualization is turned off after the dialog Provided functionality covers the use case described in feature request 3064835. Signed-off-by: Stefan Frey <ste...@we...> diff --git a/LocalisedText.properties b/LocalisedText.properties index 26b182e..a3fdd12 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -400,6 +400,8 @@ MustWithholdUntilPermanent={0} must withhold revenue until it owns a permanent t NamesTrain={0} names {1}-train as {2} NegativeAmountNotAllowed=Negative amount {0} not allowed NetworkInfo=Network Info +NetworkInfoDialogTitle=Network Info for Company {0} +NetworkInfoDialogMessage={0} could run for a revenue of {1} NEW=New NewGame=New Game NextPlayerMessage=Message(s) from previous player''s ({0}) turn: diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index ffcb997..e88b788 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -611,7 +611,7 @@ implements ActionListener, KeyListener, RevenueListener { if (networkInfoMenu != null) infoMenu.remove(networkInfoMenu); networkInfoMenu = createNetworkInfo(); if (networkInfoMenu == null) return; - networkInfoMenu.setEnabled(Game.getDevelop()); + networkInfoMenu.setEnabled(true); infoMenu.add(networkInfoMenu); } @@ -624,7 +624,8 @@ implements ActionListener, KeyListener, RevenueListener { JMenu networkMenu = new JMenu(LocalText.getText("NetworkInfo")); - if (route_highlight) { + //network graphs only for developers + if (route_highlight && Game.getDevelop()) { JMenuItem item = new JMenuItem("Network"); item.addActionListener(this); item.setActionCommand(NETWORK_INFO_CMD); @@ -683,6 +684,17 @@ implements ActionListener, KeyListener, RevenueListener { 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 + JOptionPane.showMessageDialog(this, + LocalText.getText("NetworkInfoDialogMessage",company.getName(),Bank.format(revenueValue)) , + LocalText.getText("NetworkInfoDialogTitle",company.getName()), + JOptionPane.INFORMATION_MESSAGE); + //train simulation only for developers + break; + } + JOptionPane.showMessageDialog(orWindow, "RevenueValue = " + revenueValue + "\nRevenueRun = \n" + ra.getOptimalRunPrettyPrint(true)); @@ -697,7 +709,11 @@ implements ActionListener, KeyListener, RevenueListener { } } - revenueAdapter = ra; + //clean up the paths on the map + orUIManager.getMap().setTrainPaths(null); + //but retain paths already existing before + if (revenueAdapter != null) revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + orUIManager.getMap().repaint(); } } @@ -842,6 +858,21 @@ implements ActionListener, KeyListener, RevenueListener { setSelect(revenue[orCompIndex], revenueSelect[orCompIndex], false); } + /** + * Sets the keyboard shortcut (CTRL+N) for displaying routes of the given company + */ + private void setKeyboardShortcutForNetwork(PublicCompanyI orComp) { + if (networkInfoMenu == null) return; + for (int i=0 ; i<networkInfoMenu.getItemCount(); i++) { + JMenuItem item = networkInfoMenu.getItem(i); + if (item.getAccelerator() != null) item.setAccelerator(null); + if (item.getText().equals(orComp.getName())) { + item.setAccelerator(KeyStroke.getKeyStroke( + KeyEvent.VK_N , ActionEvent.CTRL_MASK )); + } + } + + } public void initORCompanyTurn(PublicCompanyI orComp, int orCompIndex) { @@ -858,6 +889,8 @@ implements ActionListener, KeyListener, RevenueListener { button1.setEnabled(false); button2.setEnabled(false); button3.setEnabled(false); + + setKeyboardShortcutForNetwork(orComp); } public void initTileLayingStep() { |
From: Brett L. <wak...@us...> - 2012-01-01 14:43:20
|
data/1856/MapImage.svg | 14 ++++++-- rails/ui/swing/GUIToken.java | 57 +++++++++++++++++++-------------- rails/ui/swing/TokenIcon.java | 15 ++------ rails/ui/swing/hexmap/GUIHex.java | 17 +-------- rails/ui/swing/hexmap/HexMapImage.java | 3 + 5 files changed, 54 insertions(+), 52 deletions(-) New commits: commit 1aa084787dd2f2aca84acd3fef125f904e672860 Author: Frederick Weld <fre...@gm...> Date: Sun Jan 1 10:36:37 2012 +0100 Added precise sizing and positioning of token labels Introduced a generic logic that provides for precise sizing/positioning for any label text length and zoom factor. Replaces prior heuristic that, among others, placed labels partly outside of the tokens. diff --git a/rails/ui/swing/GUIToken.java b/rails/ui/swing/GUIToken.java index 1e5d8ec..5a02f08 100644 --- a/rails/ui/swing/GUIToken.java +++ b/rails/ui/swing/GUIToken.java @@ -3,6 +3,7 @@ package rails.ui.swing; import java.awt.*; import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; import javax.swing.JPanel; @@ -21,9 +22,12 @@ public class GUIToken extends JPanel { public static final int DEFAULT_X_COORD = 1; public static final int DEFAULT_Y_COORD = 1; - private static final Font smallTokenFont = new Font("Helvetica", Font.BOLD, 8); - private static final Font tokenFont = new Font("Helvetica", Font.BOLD, 10); - private static final Font largeTokenFont = new Font("Helvetica", Font.BOLD, 12); + private static final Font tokenFontTemplate = new Font("Helvetica", Font.BOLD, 10); + /** + * defined by the ratio of margin to diameter + * (eg., 0.2 means that 20% of the diameter is used as margin) + */ + private static final double tokenTextMargin = 0.15; @Override public void paintComponent(Graphics g) { @@ -35,24 +39,17 @@ public class GUIToken extends JPanel { } public void drawToken(Graphics2D g2d) { - Color oldColor = g2d.getColor(); - Font oldFont = g2d.getFont(); - double tokenScale = diameter / DEFAULT_DIAMETER; + Color oldColor = g2d.getColor(); g2d.setColor(Color.BLACK); g2d.draw(circle); g2d.setColor(bgColor); g2d.fill(circle); - - Font font = getTokenFont(name.length()); - g2d.setFont(new Font("Helvetica", Font.BOLD, - (int) (font.getSize() * tokenScale))); - g2d.setColor(fgColor); - g2d.drawString(name, (int) (circle.x + (12 - 3*name.length()) * tokenScale), - (int) (circle.y + 14 * tokenScale)); - g2d.setColor(oldColor); - g2d.setFont(oldFont); + + drawTokenText(name, g2d, fgColor, + new Point((int)(circle.x + diameter/2),(int)(circle.y + diameter/2)), + diameter); } protected void clear(Graphics g) { @@ -110,13 +107,27 @@ public class GUIToken extends JPanel { return name; } - public static Font getTokenFont (int size) { - if (size <= 2) { - return largeTokenFont; - } else if (size <= 4) { - return tokenFont; - } else { - return smallTokenFont; - } + public static void drawTokenText (String text, Graphics g, Color c, Point tokenCenter, double tokenDiameter) { + + //first calculate font size + double allowedTextDiameter = tokenDiameter * (1 - tokenTextMargin); + Rectangle2D textBoundsInTemplate = g.getFontMetrics(tokenFontTemplate).getStringBounds(text, g); + double fontScalingX = allowedTextDiameter / textBoundsInTemplate.getWidth(); + double fontScalingY = allowedTextDiameter / textBoundsInTemplate.getHeight(); + double fontScaling = (fontScalingX < fontScalingY) ? fontScalingX : fontScalingY; + int fontSize = (int) Math.floor(fontScaling * tokenFontTemplate.getSize()); + + //draw text + Color oldColor = g.getColor(); + Font oldFont = g.getFont(); + g.setColor(c); + g.setFont(tokenFontTemplate.deriveFont((float)fontSize)); //float needed to indicate size (not style) + Rectangle2D textBounds = g.getFontMetrics().getStringBounds(text, g); + g.drawString(text, + tokenCenter.x - (int)textBounds.getCenterX(), + tokenCenter.y - (int)textBounds.getCenterY()); + g.setColor(oldColor); + g.setFont(oldFont); + } } diff --git a/rails/ui/swing/TokenIcon.java b/rails/ui/swing/TokenIcon.java index 0f8f1d3..448eb2b 100644 --- a/rails/ui/swing/TokenIcon.java +++ b/rails/ui/swing/TokenIcon.java @@ -2,9 +2,9 @@ package rails.ui.swing; import java.awt.Color; import java.awt.Component; -import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.geom.Ellipse2D; import javax.swing.Icon; @@ -33,23 +33,16 @@ class TokenIcon implements Icon { new Ellipse2D.Double(x, y, diameter, diameter); Graphics2D g2d = (Graphics2D) g; Color oldColour = g2d.getColor(); - Font oldFont = g2d.getFont(); - double tokenScale = diameter / DEFAULT_DIAMETER; g2d.setColor(bgColour); g2d.fill(circle); g2d.setColor(Color.BLACK); g2d.draw(circle); - g2d.setFont(new Font("Helvetica", Font.BOLD, (int) (8 * tokenScale))); - g2d.setColor(fgColour); - // g2d.drawString(name, 3, 14); - g2d.drawString(text, (int) (circle.x + 2 * tokenScale), - (int) (circle.y + 14 * tokenScale)); - g2d.setColor(oldColour); - g2d.setFont(oldFont); - + GUIToken.drawTokenText(text, g, fgColour, + new Point((int)(circle.x + diameter/2),(int)(circle.y + diameter/2)), + diameter); } public int getIconWidth() { diff --git a/rails/ui/swing/hexmap/GUIHex.java b/rails/ui/swing/hexmap/GUIHex.java index 91b06d2..e083c44 100644 --- a/rails/ui/swing/hexmap/GUIHex.java +++ b/rails/ui/swing/hexmap/GUIHex.java @@ -578,25 +578,12 @@ public class GUIHex implements ViewObject { diameter, diameter); token.drawToken(g2); + } private void drawHome (Graphics2D g2, PublicCompanyI co, Point origin) { - Font oldFont = g2.getFont(); - Color oldColor = g2.getColor(); - - double scale = 0.5 * zoomFactor; - String name = co.getName(); - - Font font = GUIToken.getTokenFont(name.length()); - g2.setFont(new Font("Helvetica", Font.BOLD, - (int) (font.getSize() * zoomFactor * 0.75))); - g2.setColor(Color.BLACK); - g2.drawString(name, (int) (origin.x + (-4 - 3*name.length()) * scale), - (int) (origin.y + 4 * scale)); - - g2.setColor(oldColor); - g2.setFont(oldFont); + GUIToken.drawTokenText(co.getName(), g2, Color.BLACK, origin, tokenDiameter); } private void drawBonusToken(Graphics2D g2, BonusToken bt, Point origin) { commit c873a449f712e7934e80a467069af09807e0dd05 Author: Frederick Weld <fre...@gm...> Date: Sun Jan 1 07:01:15 2012 +0100 Fixed 1856 background map's mini-map (Windsor area) diff --git a/data/1856/MapImage.svg b/data/1856/MapImage.svg index 01dda31..595254a 100644 --- a/data/1856/MapImage.svg +++ b/data/1856/MapImage.svg @@ -150,12 +150,12 @@ inkscape:cx="2556" inkscape:cy="1957.5" inkscape:document-units="px" - inkscape:current-layer="layer3" + inkscape:current-layer="layer6" showgrid="false" inkscape:object-nodes="false" inkscape:window-width="1737" inkscape:window-height="1047" - inkscape:window-x="1452" + inkscape:window-x="172" inkscape:window-y="-11" inkscape:window-maximized="1" borderlayer="true" @@ -1558,6 +1558,16 @@ d="m 1316.1025,687.05754 c 11.3544,-9.50442 24.1951,-17.25146 37.7619,-23.13985 6.2666,-1.10258 11.5539,-4.50634 15.843,-9.11459 5.1019,-4.93631 11.9991,-7.33276 17.1024,-12.28326 3.9779,-3.49579 7.8596,-7.15447 12.7095,-9.4214 6.6475,-3.43833 12.4263,-8.89027 20.0869,-9.98548 6.6565,-1.63694 13.7417,-0.0944 20.2432,-2.34671" id="path3981" inkscape:connector-curvature="0" /> + <path + style="fill:#ffeaea;fill-opacity:1;stroke:none" + d="m 777.21379,820.08532 c -0.51563,-0.18361 -4.45313,-1.69384 -8.75,-3.35606 -4.29688,-1.66222 -10.20313,-3.49521 -13.125,-4.0733 -6.3968,-1.26562 -7.98154,-2.16641 -12.99328,-7.38562 -5.83181,-6.07323 -6.47767,-9.05655 -3.1495,-14.54801 2.4301,-4.00964 5.77457,-5.97601 12.52268,-7.36267 7.54706,-1.55084 10.51302,-1.32889 15.72195,1.1765 2.47731,1.19154 6.53809,2.51521 9.02396,2.94149 l 4.51977,0.77505 -0.16654,15.96477 c -0.16114,15.44732 -0.20706,15.9686 -1.41654,16.08323 -0.6875,0.0652 -1.67188,-0.0318 -2.1875,-0.21538 z" + id="path4752" + inkscape:connector-curvature="0" /> + <path + style="fill:#ffeaea;fill-opacity:1;stroke:none" + d="" + id="path4754" + inkscape:connector-curvature="0" /> </g> <g inkscape:groupmode="layer" commit 2c822f0d3923720ff5f7d989e8c9a64667e261e4 Author: Frederick Weld <fre...@gm...> Date: Sat Dec 31 13:03:26 2011 +0100 Fixed the glitch of initially displaying map images in the wrong scale Glitch description: If the scale factor of the background map image differs from 1, the map is initially displayed in the wrong scale for a second before resizing eventually corrects this (especially applies to 1856/1889 background images as their scale is lower than 0.2). diff --git a/rails/ui/swing/hexmap/HexMapImage.java b/rails/ui/swing/hexmap/HexMapImage.java index 171642e..5ad44af 100644 --- a/rails/ui/swing/hexmap/HexMapImage.java +++ b/rails/ui/swing/hexmap/HexMapImage.java @@ -76,7 +76,8 @@ public final class HexMapImage extends JSVGCanvas { } addGVTTreeRendererListener (new GVTTreeRendererAdapter() { - public void gvtRenderingCompleted(GVTTreeRendererEvent e) { + //prepare: map scaling has to occur before displaying it for the first time + public void gvtRenderingPrepare(GVTTreeRendererEvent e) { if (!initialized) { // store the rendering Transform initialTransform = getRenderingTransform(); |
From: Stefan F. <ste...@us...> - 2011-12-31 15:36:39
|
rails/common/parser/ComponentManager.java | 9 - rails/common/parser/GameFileParser.java | 5 rails/game/Company.java | 6 rails/game/CompanyManager.java | 2 rails/game/Game.java | 6 rails/game/GameManager.java | 51 +++-- rails/game/OperatingRound.java | 38 ++-- rails/game/PrivateCompany.java | 4 rails/game/Round.java | 4 rails/game/ShareSellingRound.java | 4 rails/game/StartRound.java | 2 rails/game/StartRound_1830.java | 4 rails/game/StartRound_1835.java | 2 rails/game/StockRound.java | 12 - rails/game/TreasuryShareRound.java | 6 rails/game/correct/CashCorrectionManager.java | 2 rails/game/correct/CorrectionManager.java | 2 rails/game/correct/MapCorrectionManager.java | 2 rails/game/model/AbstractModel.java | 14 - rails/game/model/AbstractOwnable.java | 10 + rails/game/model/CertificatesModel.java | 2 rails/game/model/DirectOwner.java | 28 +-- rails/game/model/Holder.java | 37 ---- rails/game/model/HolderModel.java | 86 --------- rails/game/model/Model.java | 10 - rails/game/model/Owner.java | 6 rails/game/model/Owners.java | 2 rails/game/model/Portfolio.java | 10 - rails/game/model/PortfolioOwner.java | 13 - rails/game/model/PrivatesModel.java | 2 rails/game/model/SingleOwner.java | 24 +- rails/game/model/Storage.java | 37 ++++ rails/game/model/StorageModel.java | 86 +++++++++ rails/game/model/TrainsModel.java | 4 rails/game/specific/_1835/GameManager_1835.java | 5 rails/game/specific/_1835/OperatingRound_1835.java | 4 rails/game/specific/_1835/PrussianFormationRound.java | 13 - rails/game/specific/_1856/CGRFormationRound.java | 9 - rails/game/specific/_1856/GameManager_1856.java | 5 rails/game/specific/_1856/PublicCompany_CGR.java | 2 rails/game/specific/_1880/StartRound_1880.java | 4 rails/game/specific/_1889/OperatingRound_1889.java | 4 rails/game/specific/_18AL/OperatingRound_18AL.java | 2 rails/game/specific/_18EU/FinalMinorExchangeRound.java | 2 rails/game/specific/_18EU/GameManager_18EU.java | 5 rails/game/specific/_18EU/StartRound_18EU.java | 6 rails/game/specific/_18EU/StockRound_18EU.java | 9 - rails/game/state/AbstractContext.java | 57 ++++-- rails/game/state/AbstractItem.java | 66 +++++-- rails/game/state/AbstractState.java | 82 ++++++--- rails/game/state/ActionChangeSet.java | 36 ++++ rails/game/state/ArrayListMultimapState.java | 5 rails/game/state/ArrayListState.java | 10 - rails/game/state/AutoChangeSet.java | 31 +++ rails/game/state/BooleanState.java | 10 - rails/game/state/ChangeSet.java | 30 +-- rails/game/state/ChangeStack.java | 143 +++++++++------- rails/game/state/Context.java | 11 - rails/game/state/GameContext.java | 52 +++++ rails/game/state/GameItem.java | 99 +++++++++++ rails/game/state/GenericState.java | 8 rails/game/state/HashMapState.java | 10 - rails/game/state/HashMultimapState.java | 10 - rails/game/state/HashSetState.java | 10 - rails/game/state/IntegerState.java | 10 - rails/game/state/Item.java | 30 +++ rails/game/state/State.java | 19 +- rails/game/state/StateManager.java | 151 ++++++++++++----- rails/game/state/StringState.java | 10 - rails/util/Util.java | 2 70 files changed, 980 insertions(+), 514 deletions(-) New commits: commit 45e0cd79d366f99855e666ec701ff3a22d8b0122 Author: Stefan Frey <ste...@we...> Date: Thu Dec 15 18:33:37 2011 +0100 improved context and item mechanisms diff --git a/rails/common/parser/ComponentManager.java b/rails/common/parser/ComponentManager.java index 0e48411..6c55bea 100644 --- a/rails/common/parser/ComponentManager.java +++ b/rails/common/parser/ComponentManager.java @@ -8,6 +8,7 @@ import org.apache.log4j.Logger; import rails.common.LocalText; import rails.common.parser.XMLTags; +import rails.game.state.GameContext; /** * ComponentManage - an implementation of ComponentManagerI, which handles the @@ -26,7 +27,7 @@ public class ComponentManager { private Map<String, ConfigurableComponentI> mComponentMap = new HashMap<String, ConfigurableComponentI>(); - public ComponentManager(String gameName, Tag tag, Map<String, String> gameOptions) + public ComponentManager(GameContext context, String gameName, Tag tag, Map<String, String> gameOptions) throws ConfigurationException { this.gameName = gameName; @@ -34,12 +35,12 @@ public class ComponentManager { for (Tag component : componentTags) { String compName = component.getAttributeAsString("name"); log.debug("Found component " + compName); - configureComponent(component); + configureComponent(context, component); component.setGameOptions(gameOptions); } } - private void configureComponent(Tag componentTag) + private void configureComponent(GameContext context, Tag componentTag) throws ConfigurationException { // Extract the attributes of the Component @@ -69,7 +70,7 @@ public class ComponentManager { Class.forName(clazz).asSubclass( ConfigurableComponentI.class); Constructor<? extends ConfigurableComponentI> compCons = - compClass.getConstructor(new Class[0]); + compClass.getConstructor(new Class[0]); component = compCons.newInstance(new Object[0]); } catch (Exception ex) { // There are MANY things that could go wrong here. diff --git a/rails/common/parser/GameFileParser.java b/rails/common/parser/GameFileParser.java index b1347f3..afc7e18 100644 --- a/rails/common/parser/GameFileParser.java +++ b/rails/common/parser/GameFileParser.java @@ -18,6 +18,7 @@ import rails.game.PlayerManager; import rails.game.StockMarketI; import rails.game.TileManager; import rails.game.TrainManager; +import rails.game.state.GameContext; public class GameFileParser extends XMLParser { private static String GAME_XML_FILE = "Game.xml"; @@ -36,7 +37,7 @@ public class GameFileParser extends XMLParser { private RevenueManager revenueManager; private Bank bank; - public GameFileParser(String name, Map<String, String> gameOptions) { + public GameFileParser(GameContext context, String name, Map<String, String> gameOptions) { directories.add("data/" + name); @@ -45,7 +46,7 @@ public class GameFileParser extends XMLParser { componentManagerTag.setGameOptions(gameOptions); //XXX: Ultimately calls everyone's configureFromXML() methods. - componentManager = new ComponentManager(name, componentManagerTag, gameOptions); + componentManager = new ComponentManager(context, name, componentManagerTag, gameOptions); playerManager = (PlayerManager) componentManager.findComponent("PlayerManager"); bank = (Bank) componentManager.findComponent("Bank"); diff --git a/rails/game/Company.java b/rails/game/Company.java index 588c73e..6483953 100644 --- a/rails/game/Company.java +++ b/rails/game/Company.java @@ -10,7 +10,7 @@ import rails.common.parser.ConfigurableComponentI; import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; import rails.game.model.DirectOwner; -import rails.game.model.HolderModel; +import rails.game.model.StorageModel; import rails.game.model.Portfolio; import rails.game.special.SpecialPropertyI; import rails.game.state.BooleanState; @@ -58,7 +58,7 @@ Cloneable, Comparable<Company> { protected BooleanState closedObject; // Moved here from PrivayeCOmpany on behalf of 1835 - protected HolderModel<SpecialPropertyI> specialProperties = null; + protected StorageModel<SpecialPropertyI> specialProperties = null; protected static Logger log = Logger.getLogger(Company.class.getPackage().getName()); @@ -94,7 +94,7 @@ Cloneable, Comparable<Company> { System.exit(-1); } if (specialProperties == null) { - specialProperties = HolderModel.create(this, SpecialPropertyI.class); + specialProperties = StorageModel.create(this, SpecialPropertyI.class); } sp.configureFromXML(spTag); sp.moveTo(this); diff --git a/rails/game/CompanyManager.java b/rails/game/CompanyManager.java index 455f565..f6e6766 100644 --- a/rails/game/CompanyManager.java +++ b/rails/game/CompanyManager.java @@ -1 +1 @@ -package rails.game; import java.util.*; import org.apache.log4j.Logger; import rails.common.LocalText; import rails.common.parser.ConfigurableComponentI; import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; public class CompanyManager implements CompanyManagerI, ConfigurableComponentI { /** A List with all private companies */ private List<PrivateCompany> lPrivateCompanies = new ArrayList<PrivateCompany>(); /** A List with all public companies */ private List<PublicCompany> lPublicCompanies = new ArrayList<PublicCompany>(); /** A map with all private companies by name */ private Map<String, PrivateCompany> mPrivateCompanies = new HashMap<String, PrivateCompany>(); /** A map with all public (i.e. non-private) companies by name */ private Map<String, PublicCompany> mPublicCompanies = new HashMap<String, PublicCompany>(); /** A map of all type names to maps of companies of that type by name */ // TODO Redundant, current usage can be replaced. private Map<String, Map<String, Company>> mCompaniesByTypeAndName = new HashMap<String, Map<String, Company>>(); /** A list of all company types */ private List<CompanyTypeI> lCompanyTypes = new ArrayList<CompanyTypeI>(); /** A list of all start packets (usually one) */ private List<StartPacket> startPackets = new ArrayList<StartPacket>(); /** A map of all start packets, keyed by name. Default name is "Initial" */ private Map<String, StartPacket> startPacketMap = new HashMap<String, StartPacket>(); /** A map to enable translating aliases to names */ protected Map<String, String> aliases = null; private int numberOfPublicCompanies = 0; protected static Logger log = Logger.getLogger(CompanyManager.class.getPackage().getName()); protected GameManager gameManager; /* * NOTES: 1. we don't have a map over all companies, because some games have * duplicate nam |
From: Brett L. <wak...@us...> - 2011-12-27 19:09:14
|
rails/game/GameManager.java | 13 +++++++------ rails/ui/swing/GameSetupWindow.java | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) New commits: commit ee46d990d508904fc6a542f20f8b4c30c53f4203 Author: frederickweld <fre...@gm...> Date: Tue Dec 27 19:41:21 2011 +0100 Fixed retrieval of default game options (if options pane was not opened) Game options have to be read from GamesList.xml and not from the respective game's Games.xml GameOption tags. Before the fix, this was not the case if the options pane had not been opened (which is the moment at which the GamesList's default options were loaded). This fix also solves Bug 3448429, as the reported missing 18EU route calculation was due to inconsistent defaulting between GamesList (default=suggest) and Games (default=deactivate). Now, the defaults are always taken from GamesList. diff --git a/rails/ui/swing/GameSetupWindow.java b/rails/ui/swing/GameSetupWindow.java index 3f282b1..d9652ec 100644 --- a/rails/ui/swing/GameSetupWindow.java +++ b/rails/ui/swing/GameSetupWindow.java @@ -477,10 +477,11 @@ public class GameSetupWindow extends JDialog implements ActionListener { log.info("Game option " + option.getName() + " set to " + value); } } else { - // No options selected: take the defaults GameOption option; String value; + // No options selected: take the defaults (from the games list!) + availableOptions = this.getSelectedGameInfo().getOptions(); for (int i = 0; i < availableOptions.size(); i++) { option = availableOptions.get(i); value = option.getDefaultValue(); commit 9d832d70a9f91944f1e1d8fba124f97c00f097cd Author: frederickweld <fre...@gm...> Date: Tue Dec 27 17:48:19 2011 +0100 Fixed autosave functionality (handling of 18xx_autosave.xxx files) Target design is that (1) new temp file (.tmp) is created (2) former autosave (.rails) becomes the backup autosave (.rails.bak) (3) temp file (.tmp) becomes the new autosave (.rails) Prior to the fix, the implementation did not process step (2) correctly, as backup autosaves were never dropped. This meant that autosave resulted in an error message and three files in the autosave folder (.tmp , .rails , .rails.bak). That's why autosave had never worked for me (and I doubt that it could have worked for others). diff --git a/rails/game/GameManager.java b/rails/game/GameManager.java index 486b24a..8046968 100644 --- a/rails/game/GameManager.java +++ b/rails/game/GameManager.java @@ -1102,7 +1102,7 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { // rename the temp file to the recover file File recoveryFile = null; - boolean result; + boolean result = false; try { log.debug("Created temporary recovery file, path = " + tempFile.getPath()); // check if previous save file exists @@ -1111,11 +1111,12 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { if (recoveryFile.exists()) { log.debug("Potential recovery filePath = " + recoveryFile.getPath()); File backupFile = new File(filePath + ".bak"); - if (recoveryFile.renameTo(backupFile)) { - result = tempFile.renameTo(recoveryFile); - } else { - result = backupFile.renameTo(recoveryFile); - } + //delete backup file if existing + if (backupFile.exists()) backupFile.delete(); + //old recovery file becomes new backup file + recoveryFile.renameTo(backupFile); + //temp file becomes new recoveryFile + result = tempFile.renameTo(recoveryFile); } else { log.debug("Tries to rename temporary file"); result = tempFile.renameTo(recoveryFile); |
From: Brett L. <wak...@us...> - 2011-12-26 14:03:24
|
data/1889/Map.xml | 53 data/1889/MapImage.svg | 4259 ++++++++++++++++++++++++++++++++ data/18AL/Game.xml | 12 data/GamesList.xml | 3 rails/ui/swing/MapPanel.java | 29 rails/ui/swing/ORPanel.java | 32 rails/ui/swing/ReportWindowDynamic.java | 24 rails/ui/swing/hexmap/HexMap.java | 37 rails/ui/swing/hexmap/HexMapImage.java | 5 9 files changed, 4408 insertions(+), 46 deletions(-) New commits: commit b26560a6877bcff52d78bdd686f86a06174bf879 Author: frederickweld <fre...@gm...> Date: Mon Dec 26 09:29:41 2011 +0100 1889: Aligned hex tooltip with style of background map The background map displays all names in Kanji and Romaji (latin alphabet). However, the hex tooltip only displayed the Romaji. Hence, the Kanji have been added to the Map.xml. diff --git a/data/1889/Map.xml b/data/1889/Map.xml index 19ea9a4..2f42650 100644 --- a/data/1889/Map.xml +++ b/data/1889/Map.xml @@ -1,72 +1,72 @@ <Map tileOrientation="NS" letterOrientation="horizontal" even="A"> <Image file="1889/MapImage.svg" x="6" y="5" scale="0.1632" /> <Hex name="A8" tile="0" cost="80"/> - <Hex name="A10" tile="-10" city="Sukomo"/> + <Hex name="A10" tile="-10" city="宿毛 - Sukomo"/> - <Hex name="B3" tile="-89030" orientation="0" city="Yawatahama"/> <!--NEW TILE:-890030--> + <Hex name="B3" tile="-89030" orientation="0" city="八幡浜 - Yawatahama"/> <!--NEW TILE:-890030--> <Hex name="B5" tile="0"/> - <Hex name="B7" tile="-89511" orientation="0" city="Uwajima"/> <!--NEW TILE:-89511--> + <Hex name="B7" tile="-89511" orientation="0" city="宇和島 - Uwajima"/> <!--NEW TILE:-89511--> <Hex name="B9" tile="0" cost="80"/> - <Hex name="B11" tile="-1" city="Nakamura"/> + <Hex name="B11" tile="-1" city="中村 - Nakamura"/> - <Hex name="C4" tile="-89115" orientation="0" city="Ohzu"/> + <Hex name="C4" tile="-89115" orientation="0" city="大洲 - Ohzu"/> <Hex name="C6" tile="0" cost="80"/> <Hex name="C8" tile="0"/> - <Hex name="C10" tile="-10" city="Kubokawa"/> + <Hex name="C10" tile="-10" city="窪川 - Kubokawa"/> <Hex name="D3" tile="0"/> <Hex name="D5" tile="0" cost="80"/> <Hex name="D7" tile="0" cost="80"/> <Hex name="D9" tile="0"/> - <Hex name="E2" tile="-10" city="Matsuyama"/> + <Hex name="E2" tile="-10" city="松山 - Matsuyama"/> <Hex name="E4" tile="0" cost="80"/> <Hex name="E6" tile="0" cost="80"/> <Hex name="E8" tile="0"/> - <Hex name="F1" tile="-902" orientation="2" value="30,60" city="Imabari"> + <Hex name="F1" tile="-902" orientation="2" value="30,60" city="今治 - Imabari"> <RevenueBonus value="40"> <Vertex id="-1"/> <Train type="D"/> </RevenueBonus> </Hex> - <Hex name="F3" tile="-10" city="Saijou"/> + <Hex name="F3" tile="-10" city="西條 - Saijou"/> <Hex name="F5" tile="0" cost="80"/> <Hex name="F7" tile="0" cost="80"/> - <Hex name="F9" tile="-89015" orientation="0" city="Kouchi" cost="80"/> <!--NEW TILE:-89015--> + <Hex name="F9" tile="-89015" orientation="0" city="高知 - Kouchi" cost="80"/> <!--NEW TILE:-89015--> - <Hex name="G4" tile="-10" city="Niihama"/> + <Hex name="G4" tile="-10" city="新居浜 - Niihama"/> <Hex name="G6" tile="0" cost="80"/> <Hex name="G8" tile="0" cost="80"/> - <Hex name="G10" tile="-1" city="Nangoku"/> - <Hex name="G12" tile="-10" city="Nahari"/> - <Hex name="G14" tile="-89031" orientation="0" city="Muroto"/> <!--NEW TILE:-890031--> + <Hex name="G10" tile="-1" city="南国 - Nangoku"/> + <Hex name="G12" tile="-10" city="奈半利 - Nahari"/> + <Hex name="G14" tile="-89031" orientation="0" city="室戸 - Muroto"/> <!--NEW TILE:-890031--> <Hex name="H3" tile="0"/> <Hex name="H5" tile="0" cost="80" label="River"/> - <Hex name="H7" tile="-10" city="Ikeda"/> + <Hex name="H7" tile="-10" city="池田 - Ikeda"/> <Hex name="H9" tile="0" cost="80"/> <Hex name="H11" tile="0" cost="80"/> <Hex name="H13" tile="0" cost="80"/> - <Hex name="I2" tile="-10" city="Marugame"/> - <Hex name="I4" tile="-89010" orientation="0" city="Kotohira" cost="80,80,80"/> <!-- NEW TILE: -89010 --> + <Hex name="I2" tile="-10" city="丸亀 - Marugame"/> + <Hex name="I4" tile="-89010" orientation="0" city="琴平 - Kotohira" cost="80,80,80"/> <!-- NEW TILE: -89010 --> <Hex name="I6" tile="0" cost="80" label="River"/> <Hex name="I8" tile="0"/> <Hex name="I10" tile="0"/> - <Hex name="I12" tile="-1" city="Muki"/> + <Hex name="I12" tile="-1" city="牟岐 - Muki"/> - <Hex name="J1" tile="-902" orientation="2" value="20,40" city="Sakaide & Okoyama"> + <Hex name="J1" tile="-902" orientation="2" value="20,40" city="坂出 & 岡山 - Sakaide & Okoyama"> <RevenueBonus value="40"> <Vertex id="-1"/> <Train type="D"/> </RevenueBonus> </Hex> <Hex name="J3" tile="0"/> - <Hex name="J5" tile="-1" city="Ritsurin Kouen"/> + <Hex name="J5" tile="-1" city="栗林公園 - Ritsurin Kouen"/> <Hex name="J7" tile="-8" orientation="2" label="River"/> - <Hex name="J9" tile="-1" city="Komatsujima"/> - <Hex name="J11" tile="-10" city="Anan"/> + <Hex name="J9" tile="-1" city="小松島 - Komatsujima"/> + <Hex name="J11" tile="-10" city="阿南 - Anan"/> - <Hex name="K4" tile="-89012" orientation="0" city="Takamatsu"/> <!--NEW TILE: -89012--> + <Hex name="K4" tile="-89012" orientation="0" city="高松 - Takamatsu"/> <!--NEW TILE: -89012--> <Hex name="K6" tile="0" cost="80" lablel="River"/> - <Hex name="K8" tile="-10" city="Tokushima"/> + <Hex name="K8" tile="-10" city="徳島 - Tokushima"/> - <Hex name="L7" tile="-902" orientation="3" value="20,40" city="Naruto & Awaji"> + <Hex name="L7" tile="-902" orientation="3" value="20,40" city="鳴門 & 淡路 - Naruto & Awaji"> <RevenueBonus value="40"> <Vertex id="-1"/> <Train type="D"/> </RevenueBonus> </Hex> commit 3f368dedba48e5422709ac1d0c7794d6f4fe619a Author: frederickweld <fre...@gm...> Date: Mon Dec 26 08:58:24 2011 +0100 Added option to start 2-player 18AL games Although the 18AL rules do not state that 2-player games are allowed, there is no reason why rails should prohibit this setup if the rails user has chosen so. The initial cash / certificate limit was set in accordance to the ones of 18GA. diff --git a/data/18AL/Game.xml b/data/18AL/Game.xml index fe35706..8cc9911 100644 --- a/data/18AL/Game.xml +++ b/data/18AL/Game.xml @@ -11,9 +11,18 @@ <GameOption name="Obsolete4Trains" type="toggle" default="yes"/> <GameOption name="LeaveAuctionOnPass" type="toggle" default="no"/> <GameOption name="SeparateSalesAtSamePrice" type="toggle" default="yes"/> + <GameOption name="TwoPlayersCertLimit70Percent" type="toggle" default="yes"/> <GameParameters> <OperatingRound class="rails.game.specific._18AL.OperatingRound_18AL"/> - <PlayerShareLimit percentage="60"/> + <PlayerShareLimit percentage="60"> + <!-- Option "NumberOfPlayers" is automatically set + by the game engine --> + <IfOption name="NumberOfPlayers" value="2"> + <IfOption name="TwoPlayersCertLimit70Percent" value="yes"> + <Attributes percentage="70"/> + </IfOption> + </IfOption> + </PlayerShareLimit> <BankPoolLimit percentage="50"/> <StockRound> <NoSaleInFirstSR/> @@ -33,6 +42,7 @@ </EndOfGame> </Component> <Component name="PlayerManager" class="rails.game.PlayerManager"> + <Players number="2" cash="810" certLimit="20"/> <Players number="3" cash="600" certLimit="15"/> <Players number="4" cash="500" certLimit="12"/> <Players number="5" cash="400" certLimit="10"/> diff --git a/data/GamesList.xml b/data/GamesList.xml index 4286a01..10d120d 100644 --- a/data/GamesList.xml +++ b/data/GamesList.xml @@ -146,7 +146,8 @@ Limitation: <Option name="Obsolete4Trains" type="toggle" default="yes"/> <Option name="LeaveAuctionOnPass" type="toggle" default="no"/> <Option name="SeparateSalesAtSamePrice" type="toggle" default="yes"/> - <Players minimum="3" maximum="5"/> + <Option name="TwoPlayersCertLimit70Percent" type="toggle" default="no"/> + <Players minimum="2" maximum="5"/> </Game> <Game name="18EU"> commit 7452a5cd9c641d61c08972e4a533c734a490e331 Author: frederickweld <fre...@gm...> Date: Mon Dec 26 07:33:51 2011 +0100 Added zoom options fit-to-window/width/height The current zoom step concept has not been altered. The new zoom options are not pixel based but, instead of that, the code determines the appropriate zoom step and triggers the existing zoom logic. Minor refactoring was needed in order to avoid code duplication. diff --git a/rails/ui/swing/MapPanel.java b/rails/ui/swing/MapPanel.java index b8a3acd..632203b 100644 --- a/rails/ui/swing/MapPanel.java +++ b/rails/ui/swing/MapPanel.java @@ -113,8 +113,7 @@ public class MapPanel extends JPanel { map.setAllowedTokenLays(allowedTokenLays); } - public void zoom (boolean in) { - map.zoom(in); + private void adjustToNewMapZoom () { currentMapSize = map.getCurrentSize(); log.debug("Map.size = " +currentMapSize); layeredPane.setPreferredSize(currentMapSize); @@ -122,12 +121,34 @@ public class MapPanel extends JPanel { if (mapImage != null) { mapImage.setBounds(0, 0, currentMapSize.width, currentMapSize.height); mapImage.setPreferredSize(currentMapSize); - mapImage.zoom(in); + mapImage.zoom(map.getZoomStep()); // FIXME setBounds() seems to be sufficient to resize a JSVGCanvas, but it doesn't always work... } layeredPane.revalidate(); } - + + public void zoom (boolean in) { + map.zoom(in); + adjustToNewMapZoom(); + } + + private void zoomFit (boolean fitWidth, boolean fitHeight) { + map.zoomFit (getSize(), fitWidth, fitHeight); + adjustToNewMapZoom(); + } + + public void fitToWindow () { + zoomFit (true, true); + } + + public void fitToWidth () { + zoomFit (true, false); + } + + public void fitToHeight () { + zoomFit (false, true); + } + public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_F1) { HelpWindow.displayHelp(gameUIManager.getHelp()); diff --git a/rails/ui/swing/ORPanel.java b/rails/ui/swing/ORPanel.java index 0eaba7e..ffcb997 100644 --- a/rails/ui/swing/ORPanel.java +++ b/rails/ui/swing/ORPanel.java @@ -56,7 +56,7 @@ implements ActionListener, KeyListener, RevenueListener { private JMenu specialMenu; private JMenu loansMenu; private JMenu zoomMenu; - private JMenuItem zoomIn, zoomOut, calibrateMap; + private JMenuItem zoomIn, zoomOut, fitToWindow, fitToWidth, fitToHeight, calibrateMap; private ActionMenuItem takeLoans; private ActionMenuItem repayLoans; @@ -211,6 +211,18 @@ implements ActionListener, KeyListener, RevenueListener { zoomOut.addActionListener(this); zoomOut.setEnabled(true); zoomMenu.add(zoomOut); + fitToWindow = new JMenuItem("Fit to window"); + fitToWindow.addActionListener(this); + fitToWindow.setEnabled(true); + zoomMenu.add(fitToWindow); + fitToWidth = new JMenuItem("Fit to width"); + fitToWidth.addActionListener(this); + fitToWidth.setEnabled(true); + zoomMenu.add(fitToWidth); + fitToHeight = new JMenuItem("Fit to height"); + fitToHeight.addActionListener(this); + fitToHeight.setEnabled(true); + zoomMenu.add(fitToHeight); calibrateMap = new JMenuItem("CalibrateMap"); calibrateMap.addActionListener(this); calibrateMap.setEnabled(Game.getDevelop()); @@ -744,6 +756,24 @@ implements ActionListener, KeyListener, RevenueListener { revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); orUIManager.getMap().repaint(); } + } else if (source == fitToWindow) { + orWindow.getMapPanel().fitToWindow(); + if (revenueAdapter != null) { + revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + orUIManager.getMap().repaint(); + } + } else if (source == fitToWidth) { + orWindow.getMapPanel().fitToWidth(); + if (revenueAdapter != null) { + revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + orUIManager.getMap().repaint(); + } + } else if (source == fitToHeight) { + orWindow.getMapPanel().fitToHeight(); + if (revenueAdapter != null) { + revenueAdapter.drawOptimalRunAsPath(orUIManager.getMap()); + orUIManager.getMap().repaint(); + } } else if (source == calibrateMap) { MapManager mapManager = orUIManager.getMap().getMapManager(); String offsetX = JOptionPane.showInputDialog(this, "Change translation in X-dimension", mapManager.getMapXOffset()); diff --git a/rails/ui/swing/hexmap/HexMap.java b/rails/ui/swing/hexmap/HexMap.java index ddfd1d4..7ae00c8 100644 --- a/rails/ui/swing/hexmap/HexMap.java +++ b/rails/ui/swing/hexmap/HexMap.java @@ -346,6 +346,43 @@ public abstract class HexMap extends JComponent implements MouseListener, zoom(); } +/** + * Zoom-to-fit functionality is based on the discrete zoom steps. + * This means that no pixel precision is to be expected + */ + public void zoomFit (Dimension availableSize, boolean fitToWidth, boolean fitToHeight) { + double idealFactorWidth = availableSize.getWidth() / originalSize.width; + double idealFactorHeight = availableSize.getHeight() / originalSize.height; + //increase zoomFactor until constraints do not hold + //OR zoom cannot be increased any more + while + ( + ( + (!fitToWidth || idealFactorWidth > GameUIManager.getImageLoader().getZoomFactor(zoomStep)) + && + (!fitToHeight || idealFactorHeight > GameUIManager.getImageLoader().getZoomFactor(zoomStep)) + ) + && + GameUIManager.getImageLoader().getZoomFactor(zoomStep+1) != GameUIManager.getImageLoader().getZoomFactor(zoomStep) + ) + zoomStep++; + //decrease zoomFactor until constraints do hold + //OR zoom cannot be decreased any more + while + ( + ( + (fitToWidth && idealFactorWidth < GameUIManager.getImageLoader().getZoomFactor(zoomStep)) + || + (fitToHeight && idealFactorHeight < GameUIManager.getImageLoader().getZoomFactor(zoomStep)) + ) + && + GameUIManager.getImageLoader().getZoomFactor(zoomStep-1) != GameUIManager.getImageLoader().getZoomFactor(zoomStep) + ) + zoomStep--; + //trigger zoom execution + zoom(); + } + private void zoom() { zoomFactor = GameUIManager.getImageLoader().getZoomFactor(zoomStep); log.debug("HexMap: zoomStep = "+ zoomStep); diff --git a/rails/ui/swing/hexmap/HexMapImage.java b/rails/ui/swing/hexmap/HexMapImage.java index a1435e6..171642e 100644 --- a/rails/ui/swing/hexmap/HexMapImage.java +++ b/rails/ui/swing/hexmap/HexMapImage.java @@ -111,6 +111,11 @@ public final class HexMapImage extends JSVGCanvas { zoom(); } + public void zoom (int zoomStep) { + this.zoomStep = zoomStep; + zoom(); + } + private void zoom() { zoomFactor = GameUIManager.getImageLoader().getZoomFactor(zoomStep); log.debug("ImageMap zoomStep = " + zoomStep); commit dc1a96cdf357f43cb8cf219eb14063bf7e77376a Author: frederickweld <fre...@gm...> Date: Sun Dec 25 13:16:31 2011 +0100 Added background map for 1889 diff --git a/data/1889/Map.xml b/data/1889/Map.xml index 68d38a4..19ea9a4 100644 --- a/data/1889/Map.xml +++ b/data/1889/Map.xml @@ -1,5 +1,6 @@ <Map tileOrientation="NS" letterOrientation="horizontal" even="A"> - <Hex name="A8" tile="0" cost="80"/> + <Image file="1889/MapImage.svg" x="6" y="5" scale="0.1632" /> + <Hex name="A8" tile="0" cost="80"/> <Hex name="A10" tile="-10" city="Sukomo"/> <Hex name="B3" tile="-89030" orientation="0" city="Yawatahama"/> <!--NEW TILE:-890030--> diff --git a/data/1889/MapImage.svg b/data/1889/MapImage.svg new file mode 100644 index 0000000..7e02ff2 --- /dev/null +++ b/data/1889/MapImage.svg @@ -0,0 +1,4259 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="3698" + height="2703" + id="svg2" + version="1.1" + inkscape:version="0.48.2 r9819" + sodipodi:docname="MapImage.svg"> + <defs + id="defs4"> + <linearGradient + id="linearGradient4411"> + <stop + style="stop-color:#3584cf;stop-opacity:0.27450982;" + offset="0" + id="stop4413" /> + <stop + style="stop-color:#3584cf;stop-opacity:1;" + offset="1" + id="stop4415" /> + </linearGradient> + <polygon + id="pt" + points="-0.16245985,0 0,-0.5 0.16245985,0 " + transform="scale(0.0616,0.0616)" + style="fill:#ffffff" /> + <g + id="star"> + <use + xlink:href="#pt" + transform="matrix(-0.80901699,-0.58778525,0.58778525,-0.80901699,0,0)" + id="use4787" + x="0" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#pt" + transform="matrix(0.30901699,-0.95105652,0.95105652,0.30901699,0,0)" + id="use4789" + x="0" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#pt" + id="use4791" + x="0" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#pt" + transform="matrix(0.30901699,0.95105652,-0.95105652,0.30901699,0,0)" + id="use4793" + x="0" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#pt" + transform="matrix(-0.80901699,0.58778525,-0.58778525,-0.80901699,0,0)" + id="use4795" + x="0" + y="0" + width="5112" + height="3915" /> + </g> + <g + id="s5"> + <use + xlink:href="#star" + x="-0.252" + id="use4798" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#star" + x="-0.126" + id="use4800" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#star" + id="use4802" + x="0" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#star" + x="0.126" + id="use4804" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#star" + x="0.252" + id="use4806" + y="0" + width="5112" + height="3915" /> + </g> + <g + id="s6"> + <use + xlink:href="#s5" + x="-0.063000001" + id="use4809" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#star" + x="0.315" + id="use4811" + y="0" + width="5112" + height="3915" /> + </g> + <g + id="x4"> + <use + xlink:href="#s6" + id="use4814" + x="0" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#s5" + y="0.054000001" + id="use4816" + x="0" + width="5112" + height="3915" /> + <use + xlink:href="#s6" + y="0.108" + id="use4818" + x="0" + width="5112" + height="3915" /> + <use + xlink:href="#s5" + y="0.162" + id="use4820" + x="0" + width="5112" + height="3915" /> + </g> + <g + id="u"> + <use + xlink:href="#x4" + y="-0.21600001" + id="use4823" + x="0" + width="5112" + height="3915" /> + <use + xlink:href="#x4" + id="use4825" + x="0" + y="0" + width="5112" + height="3915" /> + <use + xlink:href="#s6" + y="0.21600001" + id="use4827" + x="0" + width="5112" + height="3915" /> + </g> + <rect + id="stripe" + width="1235" + height="50" + x="0" + y="0" + style="fill:#b22234" /> + <inkscape:perspective + id="perspective64" + inkscape:persp3d-origin="479.5 : 197.66667 : 1" + inkscape:vp_z="959 : 296.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 296.5 : 1" + sodipodi:type="inkscape:persp3d" /> + <filter + inkscape:collect="always" + id="filter9017"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="5.4802153" + id="feGaussianBlur9019" /> + </filter> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4411" + id="linearGradient4417" + x1="2255.0874" + y1="5269.3853" + x2="3294.2241" + y2="5269.3853" + gradientUnits="userSpaceOnUse" + spreadMethod="pad" /> + <filter + color-interpolation-filters="sRGB" + inkscape:collect="always" + id="filter23757"> + <feGaussianBlur + inkscape:collect="always" + stdDeviation="5.8877422" + id="feGaussianBlur23759" /> + </filter> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#ff6666" + borderopacity="1" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.28967814" + inkscape:cx="1386.4176" + inkscape:cy="1357.2216" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:object-nodes="false" + inkscape:window-width="1737" + inkscape:window-height="1047" + inkscape:window-x="1452" + inkscape:window-y="-11" + inkscape:window-maximized="1" + borderlayer="true" + showguides="true" + inkscape:guide-bbox="true" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:groupmode="layer" + id="layer2" + inkscape:label="Geo" + style="display:inline" + transform="translate(0,-4297.3599)"> + <rect + style="fill:#a1c6e9;fill-opacity:1;stroke:none" + id="rect5187" + width="3698.0801" + height="2696.8806" + x="3.0000001e-007" + y="4303.4795" /> + <path + inkscape:connector-curvature="0" + style="fill:#348d4c;fill-opacity:1;stroke:#000000;stroke-width:5.95329189;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.86369991;stroke-dasharray:none" + d="m 2898.9121,4306.4953 1.7674,9.5811 -9.55,28.8052 -9.8292,13.3949 -0.5891,40.8669 16.1855,11.3175 7.8757,29.9214 c -0.6394,-27.5779 11.457,-47.6508 23.069,-72.6177 l 36.2469,-0.155 -1.2402,10.1391 c 15.4632,24.7539 22.6196,39.0043 29.0842,72.2457 l 14.6973,9.9222 -2.5427,16.4646 17.674,12.6817 15.5963,-15.5963 -6.7285,23.8441 12.9609,-2.9766 -0.1551,-7.6897 10.0151,-5.7362 -0.341,-15.3484 17.0228,-18.0769 4.4028,4.1239 21.3637,-17.7668 0.2481,11.5345 8.7129,0.5581 10.6663,-42.7583 c 11.6971,-14.5281 28.0225,-22.3652 41.58,-21.5497 l 9.023,15.9375 -8.2168,22.4798 4.8681,23.3481 7.0384,-8.4958 -3.3487,-21.9528 10.0151,-5.7363 4,-15.0692 c 7.5557,-8.7468 15.1742,-15.9748 24.2472,-18.8521 l 7.8137,26.1076 11.3485,-12.0306 4.527,7.9688 2.6976,-8.7749 5.7362,-2.1705 2.6355,-12.6197 15.5965,-15.5964 14.6351,6.0773 c 3.8592,-16.7652 7.2568,-33.6019 10.5114,-50.4479 l -2.6667,-5.3022 -122.8176,0 -2.0775,3.2557 -3.5037,-3.2557 -250.2554,0 z m 400.1108,0 -4.1858,11.4105 21.5186,-10.0772 5.9224,5.4882 c -12.5135,4.6136 -24.2009,14.4428 -32.6812,29.7975 l 6.2324,20.8675 15.9375,-0.217 -0.8992,25.5185 27.534,-0.7442 11.9066,14.8523 17.1776,-10.3563 11.6585,3.3177 11.2555,-15.8755 8.775,4.403 15.5963,-15.5654 0.4031,19.1932 18.914,2.5426 c 10.783,-13.934 23.9181,-22.66 37.1152,-25.6736 l -10.3563,-9.6431 7.9687,-34.0144 5.7363,-2.1704 7.8137,26.1076 18.573,-12.8368 -0.186,-7.6896 18.9761,6.3563 -3.0387,-6.5734 7.0695,-8.4959 4.5271,7.9688 20.1853,-3.7828 -5.8603,-14.1081 -243.5889,0 z m 248.426,0 6.6044,4.2789 3.5658,-4.2789 -10.1702,0 z m 18.201,0 1.3952,1.3023 3.4418,-1.3023 -4.837,0 z m 12.9608,0 0.093,4.62 6.4494,-4.62 -6.5423,0 z m 99.8416,0 1.9534,16.4646 15.5964,-4.9921 0,-11.4725 -17.5498,0 z m -47.1613,2044.8627 -5.6741,6.0154 -1.5504,-5.2091 -7.2245,0.8061 1.7364,12.8678 -7.1626,4.651 -11.8135,-11.0073 -7.1317,4.6199 4.8371,23.3481 -11.2554,15.8754 -7.3176,-3.0386 -1.2092,10.1392 35.0685,13.829 -1.3022,6.2944 c -13.9861,-1.3348 -28.8538,0.5228 -43.2854,8.6508 l -1.2403,10.1392 -28.9913,-0.6201 -4.2789,3.534 |
From: Brett L. <wak...@us...> - 2011-12-23 13:13:26
|
.classpath | 3 LocalisedText.properties | 6 build.xml | 3 buildRails.xml | 2 data/1856/Game.xml | 12 + data/GamesList.xml | 3 data/Properties.xml | 8 + lib/JLayer1.0.1/jl1.0.1.jar |binary manifest | 4 rails/game/Game.java | 9 + rails/game/GameManager.java | 1 rails/game/OperatingRound.java | 3 rails/game/Phase.java | 4 rails/game/StockRound.java | 3 rails/game/specific/_1856/CGRFormationRound.java | 3 rails/sound/BackgroundMusicManager.java | 174 +++++++++++++++++++++++ 16 files changed, 232 insertions(+), 6 deletions(-) New commits: commit cef11684f468baebb8631b0b09b900fc0d1d446e Author: frederickweld <fre...@gm...> Date: Sun Dec 18 20:36:05 2011 +0100 Fix: Music can now be disabled/enabled during the game (config window). diff --git a/rails/sound/BackgroundMusicManager.java b/rails/sound/BackgroundMusicManager.java index de4b411..751d7b0 100644 --- a/rails/sound/BackgroundMusicManager.java +++ b/rails/sound/BackgroundMusicManager.java @@ -47,7 +47,7 @@ public class BackgroundMusicManager { private static final int ROUND_STOCK = 0; private static final int ROUND_OPERATING = 1; private static final String PHASENAME_DEFAULT = ""; - private static Map<Context,String> contextToMusicFileMapping = new HashMap<Context,String>(); + private static Map<Context,String> contextToMusicFileMapping; private static boolean isDisabled = true; private static boolean isMute = false; private static boolean isPlaying = false; @@ -77,6 +77,7 @@ public class BackgroundMusicManager { String enablement = Config.get("sound.backgroundMusic"); if (enablement != null && enablement.equals("enabled")) { isDisabled = false; + contextToMusicFileMapping = new HashMap<Context,String>(); setContextToMusicFileMapping( Config.get("sound.backgroundMusic.stockRound"), new Context(ROUND_STOCK,PHASENAME_DEFAULT) @@ -87,6 +88,7 @@ public class BackgroundMusicManager { ); playNewMusic(); } else { + stopMusic(); isDisabled = true; } @@ -114,14 +116,12 @@ public class BackgroundMusicManager { stopMusic(); } public static void unMute() { - if (!isDisabled) { isMute = false; playNewMusic(); - } } - + private static void playNewMusic() { - if (!isMute) { + if (!isMute && !isDisabled) { if (isPlaying) stopMusic(); if (contextToMusicFileMapping != null) { String newMusicFileName = (String)contextToMusicFileMapping.get(context); @@ -135,14 +135,16 @@ public class BackgroundMusicManager { // run music playing in new thread to play in background playingThread = new Thread() { Player player; + boolean isKilled = false; public void run() { try { - while (!Thread.interrupted()) { + while (!isKilled) { FileInputStream fis = new FileInputStream(currentMusicFileName); BufferedInputStream bis = new BufferedInputStream(fis); player = new Player(bis); log.info("Now playing: "+currentMusicFileName); player.play(); + player.close(); } } catch (Exception e) { @@ -152,6 +154,7 @@ public class BackgroundMusicManager { } public void interrupt() { super.interrupt(); + isKilled = true; if (player!=null) player.close(); } }; @@ -165,6 +168,7 @@ public class BackgroundMusicManager { if (isPlaying) { playingThread.interrupt(); isPlaying = false; + currentMusicFileName = null; } } } commit 717c70611fd8038222338cda45b77ad853487011 Author: frederickweld <fre...@gm...> Date: Sun Dec 18 17:17:05 2011 +0100 Feature 3454269 (background music) available - Some details on the design/implementation Rails is now capable of playing background music depending on the context (phase, round type). So, as for SimTex's 1830, if a new phase begins (or in case of a OR-SR switch), rails plays a different mp3 in the background. As a result, experiencing/triggering context changes (eg, rusting others' trains) is now much more fun. The end user can configure which mp3 track is used for which context in the configuration window (new tab "Sound"). There, he can also define assignment of mp3 tracks to several contexts (e.g., the same SR music independent of the phase - as it is done in SimTex's 1830). For copyright reasons, no default mp3 tracks are included in rails. During testing, I had configured rails to access SimTex's mp3 files but, as I understand, rails would not be allowed to redistribute them. Therefore, the end user has to provide mp3 files on his own. Note however, that I couldn't commit the change yet due to missing permissions. But Brett has already been contacted for that. ========================================== Some more details about the implementation ========================================== Playing mp3 is based on the lib JLayer which is now added to the rails lib. This should be ok for all of you as: - lib licencse is LGPL - lib size is only 100kb All the logic regarding the background music is found in rails.sound.BackgroundMusicManager. Some comments about the most important design decisions: - Manager is a static class - there may only be one background music at a time. - Manager is notified of context changes by adding notification calls from the context-changing parts of the game: - rails.game.Phase - rails.game.StockRound - rails.game.OperatingRound (I would have loved to subscribe to such kind of information but, since there are no such interfaces available and you apparently aim at refactoring for 2.0, this was not possible.) - Manager is started/configured by calls from rails.game.Game I hope this is ok for all of you. If you find bugs in the new code, don't hesitate to contact me. diff --git a/.classpath b/.classpath index 744d0a0..c705fd7 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry excluding="lib/batik-1.7/|lib/batik-1.7/|lib/batik-1.7/lib/|lib/batik-1.7/lib/|lib/jgraph5/|lib/jgraph5/|lib/jgrapht-0.7.3/|lib/jgrapht-0.7.3/|lib/junit-4.8.2|lib/log4j-1.2/|lib/log4j-1.2/" kind="src" path=""/> + <classpathentry excluding="lib/JLayer1.0.1/|lib/batik-1.7/|lib/batik-1.7/|lib/batik-1.7/lib/|lib/batik-1.7/lib/|lib/jgraph5/|lib/jgraph5/|lib/jgrapht-0.7.3/|lib/jgrapht-0.7.3/|lib/junit-4.8.2|lib/log4j-1.2/|lib/log4j-1.2/" kind="src" path=""/> <classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry exported="true" kind="lib" path="lib/log4j-1.2/log4j-1.2.14.jar"/> <classpathentry exported="true" kind="lib" path="lib/jgrapht-0.7.3/jgrapht-jdk1.5.jar"/> @@ -22,6 +22,7 @@ <classpathentry kind="lib" path="lib/batik-1.7/lib/batik-svg-dom.jar"/> <classpathentry kind="lib" path="lib/batik-1.7/lib/batik-xml.jar"/> <classpathentry kind="lib" path="lib/batik-1.7/lib/js.jar"/> + <classpathentry kind="lib" path="lib/JLayer1.0.1/jl1.0.1.jar"/> <classpathentry kind="lib" path="lib/batik-1.7/lib/xerces_2_5_0.jar"/> <classpathentry kind="lib" path="lib/batik-1.7/lib/xml-apis-ext.jar"/> <classpathentry kind="lib" path="lib/batik-1.7/lib/batik-anim.jar"/> diff --git a/LocalisedText.properties b/LocalisedText.properties index ac33c51..26b182e 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -170,6 +170,8 @@ 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.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 Config.label.default_players=Default players Config.label.font.ui.name=Font selection @@ -192,6 +194,9 @@ Config.label.route.colour.1=Route color for first train Config.label.route.colour.2=Route color for second train Config.label.route.colour.3=Route color for third train Config.label.route.colour.4=Route color for fourth train +Config.label.sound.backgroundMusic=Background Music +Config.label.sound.backgroundMusic.stockRound=Music files for the Stock Round +Config.label.sound.backgroundMusic.operatingRound=Music files for the Operating Round Config.label.stockchart.window.open=Stockchart open Config.label.save.directory=Save folder Config.label.save.filename.date_time_pattern=Filename date pattern @@ -205,6 +210,7 @@ Config.section.General=General Config.section.Log=Log Config.section.Font=Fonts Config.section.Save=Save +Config.section.Sound=Sound Config.section.UI=Map/Report ConfirmToken=Press Lay Token to confirm token, click another city hex, or press the No Token button. connected=connected diff --git a/build.xml b/build.xml index 45e1e35..f58cc8f 100644 --- a/build.xml +++ b/build.xml @@ -17,6 +17,7 @@ <pathelement location="lib/jgrapht-0.7.3/jgrapht-jdk1.5.jar"/> <pathelement location="lib/jgraph5/jgraph.jar"/> <pathelement location="lib/junit-4.8.2/junit.jar"/> + <pathelement location="lib/JLayer1.0.1/jl1.0.1.jar"/> <pathelement location="lib/batik-1.7/lib/batik-transcoder.jar"/> <pathelement location="lib/batik-1.7/lib/batik-dom.jar"/> <pathelement location="lib/batik-1.7/lib/batik-swing.jar"/> @@ -48,6 +49,7 @@ <exclude name="lib/batik-1.7/"/> <exclude name="lib/batik-1.7/lib/"/> <exclude name="lib/batik-1.7/lib/"/> + <exclude name="lib/JLayer1.0.1"/> <exclude name="lib/jgraph5/"/> <exclude name="lib/jgraph5/"/> <exclude name="lib/jgrapht-0.7.3/"/> @@ -72,6 +74,7 @@ <exclude name="lib/batik-1.7/"/> <exclude name="lib/batik-1.7/lib/"/> <exclude name="lib/batik-1.7/lib/"/> + <exclude name="lib/JLayer1.0.1"/> <exclude name="lib/jgraph5/"/> <exclude name="lib/jgraph5/"/> <exclude name="lib/jgrapht-0.7.3/"/> diff --git a/buildRails.xml b/buildRails.xml index d7dd74f..e656d8a 100644 --- a/buildRails.xml +++ b/buildRails.xml @@ -64,6 +64,7 @@ <include name="jgrapht-0.7.3/jgrapht-jdk1.5.jar" /> <include name="jgraph5/jgraph.jar" /> <include name="junit-4.8.2/junit.jar" /> + <include name="JLayer1.0.1/jl1.0.1.jar"/> <include name="batik-1.7/lib/batik-transcoder.jar" /> <include name="batik-1.7/lib/batik-dom.jar" /> <include name="batik-1.7/lib/batik-swing.jar" /> @@ -108,6 +109,7 @@ ./lib/jgrapht-0.7.3/jgrapht-jdk1.5.jar ./lib/jgraph5/jgraph.jar ./lib/junit-4.8.2/junit.jar + ./lib/JLayer1.0.1/jl1.0.1.jar ./lib/batik-1.7/lib/batik-transcoder.jar ./lib/batik-1.7/lib/batik-dom.jar ./lib/batik-1.7/lib/batik-swing.jar diff --git a/data/Properties.xml b/data/Properties.xml index eb95d4c..231e6e6 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -53,4 +53,12 @@ <Property name="report.filename.date_time_pattern" type="STRING" /> <Property name="report.filename.extension" type="STRING" /> </Section> + <Section name="Sound"> + <Property name="sound.backgroundMusic" type="LIST" values="disabled,enabled" + initClass="rails.sound.BackgroundMusicManager" initMethod="init"/> + <Property name="sound.backgroundMusic.stockRound" type="STRING" + initClass="rails.sound.BackgroundMusicManager" initMethod="init"/> + <Property name="sound.backgroundMusic.operatingRound" type="STRING" + initClass="rails.sound.BackgroundMusicManager" initMethod="init"/> + </Section> </Properties> \ No newline at end of file diff --git a/lib/JLayer1.0.1/jl1.0.1.jar b/lib/JLayer1.0.1/jl1.0.1.jar new file mode 100644 index 0000000..bd5fb8b Binary files /dev/null and b/lib/JLayer1.0.1/jl1.0.1.jar differ diff --git a/manifest b/manifest index aadab34..924042b 100644 --- a/manifest +++ b/manifest @@ -1,3 +1,3 @@ Manifest-Version: 1.0 -Class-Path: ./my.properties ./LocalisedText.properties ./lib/log4j-1.2/log4j-1.2.14.jar ./lib/batik-1.6/lib/batik-transcoder.jar ./lib/batik-1.6/batik.jar ./lib/batik-1.6/lib/batik-util.jar ./lib/batik-1.6/lib/batik-script.jar ./lib/batik-1.6/lib/batik-bridge.jar ./lib/batik-1.6/lib/batik-ext.jar ./lib/batik-1.6/lib/batik-awt-util.jar ./lib/batik-1.6/lib/batik-dom.jar ./lib/batik-1.6/lib/batik-gvt.jar -Main-Class: rails.test.GameTest +Class-Path: ./my.properties ./LocalisedText.properties ./lib/log4j-1.2/log4j-1.2.14.jar ./lib/JLayer1.0.1/jl1.0.1.jar ./lib/batik-1.6/lib/batik-transcoder.jar ./lib/batik-1.6/batik.jar ./lib/batik-1.6/lib/batik-util.jar ./lib/batik-1.6/lib/batik-script.jar ./lib/batik-1.6/lib/batik-bridge.jar ./lib/batik-1.6/lib/batik-ext.jar ./lib/batik-1.6/lib/batik-awt-util.jar ./lib/batik-1.6/lib/batik-dom.jar ./lib/batik-1.6/lib/batik-gvt.jar +Main-Class: rails.util.runGame diff --git a/rails/game/Game.java b/rails/game/Game.java index de85c55..3f7dfa8 100644 --- a/rails/game/Game.java +++ b/rails/game/Game.java @@ -11,6 +11,7 @@ import rails.common.DisplayBuffer; import rails.common.LocalText; import rails.common.parser.*; import rails.game.action.PossibleAction; +import rails.sound.BackgroundMusicManager; import rails.util.GameFileIO; public class Game { @@ -89,6 +90,7 @@ public class Game { log.info("========== Start of rails.game " + name + " =========="); log.info("Rails version "+version); ReportBuffer.add(LocalText.getText("GameIs", name)); + } public String start() { @@ -100,6 +102,7 @@ public class Game { } gameManager.startGame(gameOptions); + return null; } @@ -144,12 +147,16 @@ public class Game { return false; } + BackgroundMusicManager.init(); + return true; } public static Game load(String filepath) { + BackgroundMusicManager.mute(); + // use GameLoader object to load game GameFileIO gameLoader = new GameFileIO(); gameLoader.loadGameData(filepath); @@ -167,6 +174,8 @@ public class Game { DisplayBuffer.add(LocalText.getText("LoadFailed", e.getMessage())); } + BackgroundMusicManager.unMute(); + return gameLoader.getGame(); } diff --git a/rails/game/GameManager.java b/rails/game/GameManager.java index 8507931..486b24a 100644 --- a/rails/game/GameManager.java +++ b/rails/game/GameManager.java @@ -17,6 +17,7 @@ import rails.game.move.*; import rails.game.special.SpecialPropertyI; import rails.game.special.SpecialTokenLay; import rails.game.state.*; +import rails.sound.BackgroundMusicManager; import rails.util.GameFileIO; import rails.util.Util; diff --git a/rails/game/OperatingRound.java b/rails/game/OperatingRound.java index d799ad9..c7099a7 100644 --- a/rails/game/OperatingRound.java +++ b/rails/game/OperatingRound.java @@ -11,6 +11,7 @@ import rails.game.correct.OperatingCost; import rails.game.move.*; import rails.game.special.*; import rails.game.state.*; +import rails.sound.BackgroundMusicManager; import rails.util.SequenceUtil; /** @@ -106,6 +107,8 @@ public class OperatingRound extends Round implements Observer { ReportBuffer.add(LocalText.getText("START_OR", thisOrNumber)); + BackgroundMusicManager.notifyOfOperatingRoundStart(); + for (Player player : gameManager.getPlayers()) { player.setWorthAtORStart(); } diff --git a/rails/game/Phase.java b/rails/game/Phase.java index 5b50f25..2e3f7b3 100644 --- a/rails/game/Phase.java +++ b/rails/game/Phase.java @@ -8,6 +8,7 @@ import org.apache.log4j.Logger; import rails.common.LocalText; import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; +import rails.sound.BackgroundMusicManager; import rails.util.Util; public class Phase implements PhaseI { @@ -313,11 +314,14 @@ public class Phase implements PhaseI { } } + BackgroundMusicManager.setPhase(name); + if (actions != null && !actions.isEmpty()) { for (String actionName : actions.keySet()) { gameManager.processPhaseAction (actionName, actions.get(actionName)); } } + } public void setLastTrainBuyer(Portfolio lastTrainBuyer) { diff --git a/rails/game/StockRound.java b/rails/game/StockRound.java index 03bb17a..8728af0 100644 --- a/rails/game/StockRound.java +++ b/rails/game/StockRound.java @@ -8,6 +8,7 @@ import rails.game.action.*; import rails.game.move.*; import rails.game.special.*; import rails.game.state.*; +import rails.sound.BackgroundMusicManager; /** * Implements a basic Stock Round. <p> A new instance must be created for each @@ -86,6 +87,8 @@ public class StockRound extends Round { ReportBuffer.add(LocalText.getText("StartStockRound", getStockRoundNumber())); + BackgroundMusicManager.notifyOfStockRoundStart(); + setCurrentPlayerIndex(gameManager.getPriorityPlayer().getIndex()); startingPlayer = getCurrentPlayer(); // For the Report ReportBuffer.add(LocalText.getText("HasPriority", diff --git a/rails/sound/BackgroundMusicManager.java b/rails/sound/BackgroundMusicManager.java new file mode 100644 index 0000000..de4b411 --- /dev/null +++ b/rails/sound/BackgroundMusicManager.java @@ -0,0 +1,170 @@ +/** + * + */ +package rails.sound; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.util.*; + +import javazoom.jl.player.Player; +import org.apache.log4j.Logger; + +import rails.common.parser.Config; + +/** + * This is a static class as there should never be two + * background musics playing at the same time. + * + * This class is notified of: + * - phase changes (eg., 2-train -> 3-train) + * - round changes (eg., SR -> OR) + * + * Based on this information, the appropriate background music (mp3) is played + * in the background. + */ +public class BackgroundMusicManager { + private static class Context { + public int round; + public String phaseName; + public Context(int round, String phaseName) { + this.round = round; + this.phaseName = phaseName; + } + public boolean equals(Object o) { + if (!(o instanceof Context)) return false; + Context c = (Context)o; + return ((round == c.round) && (phaseName.equals(c.phaseName))); + } + public int hashCode() { + return round+phaseName.hashCode(); + } + public Context clone() { + return new Context(round,phaseName); + } + } + private static final int ROUND_UNDEFINED = -1; + private static final int ROUND_STOCK = 0; + private static final int ROUND_OPERATING = 1; + private static final String PHASENAME_DEFAULT = ""; + private static Map<Context,String> contextToMusicFileMapping = new HashMap<Context,String>(); + private static boolean isDisabled = true; + private static boolean isMute = false; + private static boolean isPlaying = false; + private static String currentMusicFileName; + private static Thread playingThread; + private static Context context = new Context(ROUND_UNDEFINED,PHASENAME_DEFAULT); + private static Logger log = Logger.getLogger(BackgroundMusicManager.class.getPackage().getName()); + + private static void setContextToMusicFileMapping (String config,Context defaultContext) { + if (config == null || config.equals("")) return; + String[] assignments = config.split(","); + for ( int i = 0 ; i < assignments.length ; i++ ) { + String[] assignment = assignments[i].split("="); + Context c = defaultContext.clone(); + if (assignment.length == 1) { + //default assignment (meaning, phase-independent) + contextToMusicFileMapping.put(c, assignment[0]); + } + else if (assignment.length == 2) { + //phase-dependent assignment + c.phaseName = assignment[0]; + contextToMusicFileMapping.put(c, assignment[1]); + } + } + } + public static void init() { + String enablement = Config.get("sound.backgroundMusic"); + if (enablement != null && enablement.equals("enabled")) { + isDisabled = false; + setContextToMusicFileMapping( + Config.get("sound.backgroundMusic.stockRound"), + new Context(ROUND_STOCK,PHASENAME_DEFAULT) + ); + setContextToMusicFileMapping( + Config.get("sound.backgroundMusic.operatingRound"), + new Context(ROUND_OPERATING,PHASENAME_DEFAULT) + ); + playNewMusic(); + } else { + isDisabled = true; + } + + } + public static void setPhase(String name) { + if (!context.phaseName.equals(name)) { + context.phaseName = name; + playNewMusic(); + } + } + public static void notifyOfStockRoundStart() { + if (context.round != ROUND_STOCK) { + context.round = ROUND_STOCK; + playNewMusic(); + } + } + public static void notifyOfOperatingRoundStart() { + if (context.round != ROUND_OPERATING) { + context.round = ROUND_OPERATING; + playNewMusic(); + } + } + public static void mute() { + isMute = true; + stopMusic(); + } + public static void unMute() { + if (!isDisabled) { + isMute = false; + playNewMusic(); + } + } + + private static void playNewMusic() { + if (!isMute) { + if (isPlaying) stopMusic(); + if (contextToMusicFileMapping != null) { + String newMusicFileName = (String)contextToMusicFileMapping.get(context); + if (newMusicFileName == null) { + //try phase-defaulting if nothing was found + newMusicFileName = (String)contextToMusicFileMapping.get(new Context(context.round,PHASENAME_DEFAULT)); + } + //only restart/change the music if a new music file is to be played + if (newMusicFileName != null && !newMusicFileName.equals(currentMusicFileName)) { + currentMusicFileName = newMusicFileName; + // run music playing in new thread to play in background + playingThread = new Thread() { + Player player; + public void run() { + try { + while (!Thread.interrupted()) { + FileInputStream fis = new FileInputStream(currentMusicFileName); + BufferedInputStream bis = new BufferedInputStream(fis); + player = new Player(bis); + log.info("Now playing: "+currentMusicFileName); + player.play(); + } + } + catch (Exception e) { + //if anything goes wrong, don't play anything + log.error(e); + } + } + public void interrupt() { + super.interrupt(); + if (player!=null) player.close(); + } + }; + playingThread.start(); + isPlaying = true; + } + } + } + } + private static void stopMusic() { + if (isPlaying) { + playingThread.interrupt(); + isPlaying = false; + } + } +} commit 0c14f32279f83c1ce5cc5574a5b09570316be8c4 Author: frederickweld <fre...@gm...> Date: Sat Dec 17 15:01:12 2011 +0100 Added option to play 1856 as a 2-player game. The standard rules do not define cert limit & starting cap for this setting. Reasonable values were chosen for these parameters. diff --git a/data/1856/Game.xml b/data/1856/Game.xml index 3a13eb9..330ac4d 100644 --- a/data/1856/Game.xml +++ b/data/1856/Game.xml @@ -8,6 +8,7 @@ <!-- <Option name="NoMapMode" type="toggle" default="no" /> --> <GameOption name="UnlimitedBonusTokens" type="toggle" default="no"/> <GameOption name="LeaveAuctionOnPass" type="toggle" default="no"/> + <GameOption name="TwoPlayersCertLimit70Percent" type="toggle" default="yes"/> <GameOption name="SeparateSalesAtSamePrice" type="toggle" default="yes"/> <GameOption name="1856THBHomeBlocked" type="toggle" default="no" /> <GameParameters> @@ -20,7 +21,15 @@ <EmergencyTrainBuying mustBuyCheapestTrain="yes" mayBuyFromCompany="no"/> </OperatingRound> <ShareSellingRound class="rails.game.specific._1856.ShareSellingRound_1856"/> - <PlayerShareLimit percentage="60"/> + <PlayerShareLimit percentage="60"> + <!-- Option "NumberOfPlayers" is automatically set + by the game engine --> + <IfOption name="NumberOfPlayers" value="2"> + <IfOption name="TwoPlayersCertLimit70Percent" value="yes"> + <Attributes percentage="70"/> + </IfOption> + </IfOption> + </PlayerShareLimit> <BankPoolLimit percentage="50"/> </GameParameters> <GuiClasses> @@ -33,6 +42,7 @@ </EndOfGame> </Component> <Component name="PlayerManager" class="rails.game.PlayerManager"> + <Players number="2" cash="750" certLimit="28"/> <Players number="3" cash="500" certLimit="20"/> <Players number="4" cash="375" certLimit="16"/> <Players number="5" cash="300" certLimit="13"/> diff --git a/data/GamesList.xml b/data/GamesList.xml index 0e0c25e..4286a01 100644 --- a/data/GamesList.xml +++ b/data/GamesList.xml @@ -102,7 +102,8 @@ Limitation: <Option name="LeaveAuctionOnPass" type="toggle" default="no"/> <Option name="SeparateSalesAtSamePrice" type="toggle" default="yes"/> <Option name="1856THBHomeBlocked" type="toggle" default="no" /> - <Players minimum="3" maximum="6"/> + <Option name="TwoPlayersCertLimit70Percent" type="toggle" default="no"/> + <Players minimum="2" maximum="6"/> </Game> <Game name="1889"> diff --git a/rails/game/specific/_1856/CGRFormationRound.java b/rails/game/specific/_1856/CGRFormationRound.java index f7066e7..2df04f8 100644 --- a/rails/game/specific/_1856/CGRFormationRound.java +++ b/rails/game/specific/_1856/CGRFormationRound.java @@ -44,6 +44,7 @@ public class CGRFormationRound extends SwitchableUIRound { public static final int STEP_EXCHANGE_TOKENS = 3; private static int[][] certLimitsTable = { + {14, 19, 21, 26, 29, 31, 36, 40}, {10, 13, 15, 18, 20, 22, 25, 28}, {8, 10, 12, 14, 16, 18, 20, 22}, {7, 8, 10, 11, 13, 15, 16, 18}, @@ -511,7 +512,7 @@ public class CGRFormationRound extends SwitchableUIRound { int numCompanies = Math.min(11, 12-mergingCompanies.size()); int numPlayers = gameManager.getNumberOfPlayers(); // Need some checks here... - int newCertLimit = certLimitsTable[numPlayers-3][numCompanies-4]; + int newCertLimit = certLimitsTable[numPlayers-2][numCompanies-4]; gameManager.setPlayerCertificateLimit(newCertLimit); message = LocalText.getText("CertificateLimit", newCertLimit, |
From: Stefan F. <ste...@us...> - 2011-12-23 10:49:34
|
Tag 'v1.6.0' created by Stefan Frey <ste...@we...> at 2011-12-23 10:53 +0000 Rails release 1.6.0: This release celebrates that 1835 is declared fully playable. Warning this release might not work with existing save files (see below). Contributors: Martin Brumm, Stefan Frey, Erik Vos, Frederick Weld List of bugs fixed and further changes: - 18EU: Fixed that share price could raise at the end of the merger round - 1825: Update to Minors - Background map: Fixed glitches at 18GA display - All games: Fixes to make entering special tile lays more efficient WARNING: The last fix might make existing save files unloadable. Note: To show a background map, the option has to be switched on in Configuration => Map/Report => Display background map. Background maps are only available for 1856, 18EU, 18GA (incl. Cotton Port) and 18AL so far. Changes since v1.5.0-79: --- 0 files changed --- |