mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 03:38:01 +00:00
*Merged from trunk up to r22981
This commit is contained in:
16
.gitattributes
vendored
16
.gitattributes
vendored
@@ -5371,6 +5371,7 @@ res/cardsfolder/i/ikiral_outrider.txt svneol=native#text/plain
|
||||
res/cardsfolder/i/ill_gotten_gains.txt svneol=native#text/plain
|
||||
res/cardsfolder/i/illness_in_the_ranks.txt -text
|
||||
res/cardsfolder/i/illuminate.txt -text
|
||||
res/cardsfolder/i/illuminated_folio.txt -text
|
||||
res/cardsfolder/i/illuminated_wings.txt svneol=native#text/plain
|
||||
res/cardsfolder/i/illumination.txt svneol=native#text/plain
|
||||
res/cardsfolder/i/illusion_reality.txt -text
|
||||
@@ -14990,6 +14991,11 @@ src/main/java/forge/gui/match/views/VPicture.java -text
|
||||
src/main/java/forge/gui/match/views/VPlayers.java -text
|
||||
src/main/java/forge/gui/match/views/VStack.java -text
|
||||
src/main/java/forge/gui/match/views/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/gui/menubar/FMenuBar.java -text
|
||||
src/main/java/forge/gui/menubar/IMenuProvider.java -text
|
||||
src/main/java/forge/gui/menubar/MenuUtil.java -text
|
||||
src/main/java/forge/gui/menus/ForgeMenu.java -text
|
||||
src/main/java/forge/gui/menus/HelpMenu.java -text
|
||||
src/main/java/forge/gui/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/gui/toolbox/CardFaceSymbols.java svneol=native#text/plain
|
||||
src/main/java/forge/gui/toolbox/FAbsolutePositioner.java -text
|
||||
@@ -15008,10 +15014,13 @@ src/main/java/forge/gui/toolbox/FSkin.java -text
|
||||
src/main/java/forge/gui/toolbox/FTabbedPane.java -text
|
||||
src/main/java/forge/gui/toolbox/FTextArea.java -text
|
||||
src/main/java/forge/gui/toolbox/FTextField.java -text
|
||||
src/main/java/forge/gui/toolbox/LayoutHelper.java -text
|
||||
src/main/java/forge/gui/toolbox/SaveOpenDialog.java -text
|
||||
src/main/java/forge/gui/toolbox/imaging/FImagePanel.java -text
|
||||
src/main/java/forge/gui/toolbox/imaging/FImageUtil.java -text
|
||||
src/main/java/forge/gui/toolbox/imaging/ImageUtil.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/CardManager.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/InventoryItemManager.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/ItemManager.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/ItemManagerContainer.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/ItemManagerModel.java -text
|
||||
@@ -15023,12 +15032,13 @@ src/main/java/forge/gui/toolbox/itemmanager/filters/CardColorFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/CardFormatFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/CardPowerFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/CardQuestWorldFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/CardSearchFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/CardSetFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/CardToughnessFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/CardTypeFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/ItemFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/ListLabelFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/TextFieldFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/TextSearchFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/ToggleButtonsFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/filters/ValueRangeFilter.java -text
|
||||
src/main/java/forge/gui/toolbox/itemmanager/package-info.java -text
|
||||
@@ -15103,6 +15113,7 @@ src/main/java/forge/net/protocol/toserver/IPacketSrv.java -text
|
||||
src/main/java/forge/net/protocol/toserver/IncorrectPacketSrv.java -text
|
||||
src/main/java/forge/net/protocol/toserver/package-info.java -text
|
||||
src/main/java/forge/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/properties/ForgeLookAndFeel.java -text
|
||||
src/main/java/forge/properties/ForgePreferences.java svneol=native#text/plain
|
||||
src/main/java/forge/properties/NewConstants.java svneol=native#text/plain
|
||||
src/main/java/forge/properties/Preferences.java svneol=native#text/plain
|
||||
@@ -15183,6 +15194,7 @@ src/main/java/forge/util/MyRandom.java svneol=native#text/plain
|
||||
src/main/java/forge/util/PredicateString.java -text
|
||||
src/main/java/forge/util/ReflectionUtil.java -text
|
||||
src/main/java/forge/util/TextUtil.java -text
|
||||
src/main/java/forge/util/TypeUtil.java -text
|
||||
src/main/java/forge/util/XmlUtil.java -text
|
||||
src/main/java/forge/util/maps/CollectionSuppliers.java -text
|
||||
src/main/java/forge/util/maps/EnumMapOfLists.java -text
|
||||
@@ -15197,6 +15209,8 @@ src/main/java/forge/util/package-info.java -text
|
||||
src/main/java/forge/util/storage/IStorage.java -text
|
||||
src/main/java/forge/util/storage/StorageBase.java -text
|
||||
src/main/java/forge/util/storage/StorageImmediatelySerialized.java svneol=native#text/plain
|
||||
src/main/java/forge/util/storage/StorageNestedFolders.java -text
|
||||
src/main/java/forge/util/storage/StorageReaderBase.java -text
|
||||
src/main/java/forge/util/storage/StorageReaderFile.java -text
|
||||
src/main/java/forge/util/storage/StorageReaderFileSections.java -text
|
||||
src/main/java/forge/util/storage/StorageReaderFolder.java -text
|
||||
|
||||
@@ -3,23 +3,13 @@ ManaCost:5 W W
|
||||
Types:Creature Angel
|
||||
PT:6/6
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ Tolstoy | Static$ True | TriggerDescription$ As CARDNAME enters the battlefield, each player chooses war or peace. Creatures controlled by players who chose war get +3/+0. Creatures controlled by players who chose peace get +0/+3.
|
||||
SVar:Tolstoy:AB$ GenericChoice | Cost$ 0 | Defined$ You | Choices$ WarChoice,PeaceChoice | SubAbility$ OppChoice
|
||||
SVar:OppChoice:DB$ GenericChoice | Cost$ 0 | Defined$ Opponent | Choices$ Attacking,Defensive
|
||||
SVar:WarChoice:DB$ Effect | Name$ Archangel War Effect | ChoiceDescription$ War | Duration$ UntilHostLeavesPlay | RememberEffect$ True
|
||||
SVar:PeaceChoice:DB$ Effect | Name$ Archangel Peace Effect | ChoiceDescription$ Peace | Duration$ UntilHostLeavesPlay | RememberEffect$ True
|
||||
SVar:Attacking:DB$ Effect | Name$ Archangel War Effect | ChoiceDescription$ War | EffectOwner$ Opponent | Duration$ UntilHostLeavesPlay | RememberEffect$ True
|
||||
SVar:Defensive:DB$ Effect | Name$ Archangel Peace Effect | ChoiceDescription$ Peace | EffectOwner$ Opponent | Duration$ UntilHostLeavesPlay | RememberEffect$ True
|
||||
S:Mode$ Continuous | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddPower$ 3 | CheckSVar$ WarYou | SVarCompare$ GE1 | References$ WarYou
|
||||
S:Mode$ Continuous | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddToughness$ 3 | CheckSVar$ PeaceYou | SVarCompare$ GE1 | References$ PeaceYou
|
||||
S:Mode$ Continuous | AffectedZone$ Battlefield | Affected$ Creature.YouDontCtrl | AddPower$ 3 | CheckSVar$ WarOpp | SVarCompare$ GE1 | References$ WarOpp
|
||||
S:Mode$ Continuous | AffectedZone$ Battlefield | Affected$ Creature.YouDontCtrl | AddToughness$ 3 | CheckSVar$ PeaceOpp | SVarCompare$ GE1 | References$ PeaceOpp
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Defined$ Self | Execute$ DBCleanup | Static$ True
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:WarYou:Count$ValidCommand Card.namedArchangel War Effect+YouCtrl+IsRemembered
|
||||
SVar:PeaceYou:Count$ValidCommand Card.namedArchangel Peace Effect+YouCtrl+IsRemembered
|
||||
SVar:WarOpp:Count$ValidCommand Card.namedArchangel War Effect+YouDontCtrl+IsRemembered
|
||||
SVar:PeaceOpp:Count$ValidCommand Card.namedArchangel Peace Effect+YouDontCtrl+IsRemembered
|
||||
K:ETBReplacement:Other:ChooseEach
|
||||
SVar:ChooseEach:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChoice | SpellDescription$ As CARDNAME enters the battlefield, each player chooses war or peace. Creatures controlled by players who chose war get +3/+0. Creatures controlled by players who chose peace get +0/+3.
|
||||
SVar:DBChoice:DB$ GenericChoice | Cost$ 0 | Defined$ Player.IsRemembered | Choices$ WarChoice,PeaceChoice
|
||||
SVar:WarChoice:DB$ Effect | Name$ Archangel War Effect | StaticAbilities$ WarPump | ChoiceDescription$ War | EffectOwner$ Player.IsRemembered | Duration$ UntilHostLeavesPlay
|
||||
SVar:PeaceChoice:DB$ Effect | Name$ Archangel Peace Effect | StaticAbilities$ PeacePump | ChoiceDescription$ Peace | EffectOwner$ Player.IsRemembered | Duration$ UntilHostLeavesPlay
|
||||
SVar:WarPump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddPower$ 3 | Description$ Creatures you control get +3/+0.
|
||||
SVar:PeacePump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddToughness$ 3 | Description$ Creatures you control get +0/+3.
|
||||
SVar:RemAIDeck:True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/archangel_of_strife.jpg
|
||||
Oracle:Flying\nAs Archangel of Strife enters the battlefield, each player chooses war or peace.\nCreatures controlled by players who chose war get +3/+0.\nCreatures controlled by players who chose peace get +0/+3.
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Exhume
|
||||
ManaCost:1 B
|
||||
Types:Sorcery
|
||||
A:SP$ ChangeZone | Cost$ 1 B | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouCtrl | ChangeNum$ 1 | Hidden$ True | SubAbility$ DBChangeZoneOpp | SpellDescription$ Each player puts a creature card from his or her graveyard onto the battlefield.
|
||||
SVar:DBChangeZoneOpp:DB$ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouDontCtrl | DefinedPlayer$ Opponent | ChangeNum$ 1 | Hidden$ True
|
||||
A:SP$ RepeatEach | Cost$ 1 B | RepeatSubAbility$ DBChangeZone | RepeatPlayers$ Player | SpellDescription$ Each player puts a creature card from his or her graveyard onto the battlefield.
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | ChangeNum$ 1 | Hidden$ True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/exhume.jpg
|
||||
Oracle:Each player puts a creature card from his or her graveyard onto the battlefield.
|
||||
@@ -3,6 +3,6 @@ ManaCost:R
|
||||
Types:Creature Goblin
|
||||
PT:1/1
|
||||
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigChange | TriggerDescription$ Whenever CARDNAME deals damage to a player, you may put a Goblin permanent card from your hand onto the battlefield.
|
||||
SVar:TrigChange:AB$ChangeZone | Cost$ 0 | Origin$ Hand | Destination$ Battlefield | ChangeType$ Permanent.Goblin | ChangeNum$ 1
|
||||
SVar:TrigChange:AB$ ChangeZone | Cost$ 0 | Origin$ Hand | Destination$ Battlefield | ChangeType$ Permanent.Goblin | ChangeNum$ 1
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/goblin_lackey.jpg
|
||||
Oracle:Whenever Goblin Lackey deals damage to a player, you may put a Goblin permanent card from your hand onto the battlefield.
|
||||
7
res/cardsfolder/i/illuminated_folio.txt
Normal file
7
res/cardsfolder/i/illuminated_folio.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Name:Illuminated Folio
|
||||
ManaCost:5
|
||||
Types:Artifact
|
||||
A:AB$ Draw | Cost$ 1 T Reveal<2/SameColor> | NumCards$ 1 | SpellDescription$ Draw a card.
|
||||
SVar:RemAIDeck:True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/illuminated_folio.jpg
|
||||
Oracle:{1}, {T}, Reveal two cards from your hand that share a color: Draw a card.
|
||||
@@ -1,10 +1,8 @@
|
||||
Name:Mana Breach
|
||||
ManaCost:2 U
|
||||
Types:Enchantment
|
||||
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigBounceYou | TriggerDescription$ Whenever a player casts a spell, that player returns a land he or she controls to its owner's hand.
|
||||
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ Opponent | TriggerZones$ Battlefield | Execute$ TrigBounceOpp | Secondary$ True | TriggerDescription$ Whenever a player casts a spell, that player returns a land he or she controls to its owner's hand.
|
||||
SVar:TrigBounceYou:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeNum$ 1 | ChangeType$ Land.YouCtrl | Mandatory$ True | DefinedPlayer$ You | Hidden$ True
|
||||
SVar:TrigBounceOpp:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeNum$ 1 | ChangeType$ Land.YouDontCtrl | Mandatory$ True | DefinedPlayer$ Opponent | Hidden$ True
|
||||
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ Player | TriggerZones$ Battlefield | Execute$ TrigBounce | TriggerDescription$ Whenever a player casts a spell, that player returns a land he or she controls to its owner's hand.
|
||||
SVar:TrigBounce:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeNum$ 1 | ChangeType$ Land | Mandatory$ True | DefinedPlayer$ TriggeredActivator | Chooser$ TriggeredActivator | Hidden$ True
|
||||
SVar:RemRandomDeck:True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/mana_breach.jpg
|
||||
Oracle:Whenever a player casts a spell, that player returns a land he or she controls to its owner's hand.
|
||||
@@ -1,12 +1,11 @@
|
||||
Name:Memory Jar
|
||||
ManaCost:5
|
||||
Types:Artifact
|
||||
A:AB$ ChangeZoneAll | Cost$ T Sac<1/CARDNAME> | ChangeType$ Card | Origin$ Hand | Destination$ Exile | ExileFaceDown$ True | RememberChanged$ True | SubAbility$ YouDraw | SpellDescription$ Each player exiles all cards from his or her hand face down and draws seven cards. At the beginning of the next end step, each player discards his or her hand and returns to his or her hand each card he or she exiled this way.
|
||||
SVar:YouDraw:DB$ Draw | Defined$ You | NumCards$ 7 | SubAbility$ OppDraw
|
||||
SVar:OppDraw:DB$ Draw | Defined$ Opponent | NumCards$ 7 | SubAbility$ DelayedReturn
|
||||
SVar:DelayedReturn:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ YouDiscard | TriggerDescription$ Both players discard their hands. Return exiled cards to their owners' hands.
|
||||
SVar:YouDiscard: AB$ Discard | Cost$ 0 | Defined$ You | Mode$ Hand | SubAbility$ OppDiscard
|
||||
SVar:OppDiscard: DB$ Discard | Defined$ Opponent | Mode$ Hand | SubAbility$ ReturnAll
|
||||
A:AB$ ChangeZoneAll | Cost$ T Sac<1/CARDNAME> | ChangeType$ Card | Origin$ Hand | Destination$ Exile | ExileFaceDown$ True | RememberChanged$ True | SubAbility$ DrawEach | SpellDescription$ Each player exiles all cards from his or her hand face down and draws seven cards. At the beginning of the next end step, each player discards his or her hand and returns to his or her hand each card he or she exiled this way.
|
||||
SVar:DrawEach:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBDraw | SubAbility$ DelayedReturn
|
||||
SVar:DBDraw:DB$ Draw | Defined$ Player.IsRemembered | NumCards$ 7
|
||||
SVar:DelayedReturn:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ DiscardEach | TriggerDescription$ Both players discard their hands. Return exiled cards to their owners' hands.
|
||||
SVar:DiscardEach:AB$ Discard | Cost$ 0 | Defined$ Each | Mode$ Hand | SubAbility$ ReturnAll
|
||||
SVar:ReturnAll:DB$ ChangeZone | Origin$ Exile | Destination$ Hand | Defined$ Remembered | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:RemAIDeck:True
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
Name:Overburden
|
||||
ManaCost:1 U
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonToken+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigBounceYou | TriggerDescription$ Whenever a player puts a nontoken creature onto the battlefield, that player returns a land he or she controls to its owner's hand.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonToken+YouDontCtrl | TriggerZones$ Battlefield | Execute$ TrigBounceOpp | Secondary$ True | TriggerDescription$ Whenever a player puts a nontoken creature onto the battlefield, that player returns a land he or she controls to its owner's hand.
|
||||
SVar:TrigBounceYou:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeType$ Land.YouCtrl | ChangeNum$ 1 | Mandatory$ True | DefinedPlayer$ You | Hidden$ True
|
||||
SVar:TrigBounceOpp:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeType$ Land.YouDontCtrl | ChangeNum$ 1 | Mandatory$ True | DefinedPlayer$ Opponent | Hidden$ True
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonToken | TriggerZones$ Battlefield | Execute$ TrigBounce | TriggerDescription$ Whenever a player puts a nontoken creature onto the battlefield, that player returns a land he or she controls to its owner's hand.
|
||||
SVar:TrigBounce:AB$ ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Hand | ChangeType$ Land | ChangeNum$ 1 | Mandatory$ True | DefinedPlayer$ TriggeredCardController | Chooser$ TriggeredCardController | Hidden$ True
|
||||
SVar:RemRandomDeck:True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/overburden.jpg
|
||||
Oracle:Whenever a player puts a nontoken creature onto the battlefield, that player returns a land he or she controls to its owner's hand.
|
||||
@@ -5,5 +5,6 @@ PT:2/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | IsPresent$ Gate.YouCtrl | PresentCompare$ GE2 | Execute$ TrigGainControl | TriggerDescription$ When CARDNAME enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. That creature gains haste until end of turn.
|
||||
SVar:TrigGainControl:AB$ GainControl | Cost$ 0 | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Untap$ True | LoseControl$ EOT | SubAbility$ DBPump
|
||||
SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ Haste
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/smelt_ward_gatekeepers.jpg
|
||||
Oracle:When Smelt-Ward Gatekeepers enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. It gains haste until end of turn.
|
||||
@@ -4,6 +4,6 @@ Types:Creature Human Assassin
|
||||
PT:1/1
|
||||
K:Fear
|
||||
T:Mode$ AttackerUnblocked | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPoison | TriggerDescription$ Whenever CARDNAME attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.)
|
||||
SVar:TrigPoison:AB$Poison | Cost$ 0 | Defined$ DefendingPlayer | Num$ 1
|
||||
SVar:TrigPoison:AB$ Poison | Cost$ 0 | Defined$ DefendingPlayer | Num$ 1
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/suqata_assassin.jpg
|
||||
Oracle:Fear (This creature can't be blocked except by artifact creatures and/or black creatures.)\nWhenever Suq'Ata Assassin attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.)
|
||||
@@ -4,6 +4,6 @@ Types:Creature Insect
|
||||
PT:0/1
|
||||
K:Flying
|
||||
T:Mode$ AttackerUnblocked | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPoison | TriggerDescription$ Whenever CARDNAME attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.)
|
||||
SVar:TrigPoison:AB$Poison | Cost$ 0 | Defined$ DefendingPlayer | Num$ 1
|
||||
SVar:TrigPoison:AB$ Poison | Cost$ 0 | Defined$ DefendingPlayer | Num$ 1
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/swamp_mosquito.jpg
|
||||
Oracle:Flying\nWhenever Swamp Mosquito attacks and isn't blocked, defending player gets a poison counter. (A player with ten or more poison counters loses the game.)
|
||||
@@ -4,7 +4,7 @@ Types:Creature Human Rebel
|
||||
PT:1/1
|
||||
K:Shadow
|
||||
T:Mode$ AttackerUnblocked | ValidCard$ Card.Self | Execute$ TrigDamage | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME attacks and isn't blocked, you may have it deal 1 damage to target creature. If you do, prevent all combat damage CARDNAME would deal this turn.
|
||||
SVar:TrigDamage:AB$DealDamage | Cost$ 0 | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | SubAbility$ DBPump
|
||||
SVar:TrigDamage:AB$ DealDamage | Cost$ 0 | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | SubAbility$ DBPump
|
||||
SVar:DBPump:DB$Pump | KW$ HIDDEN Prevent all combat damage that would be dealt by CARDNAME.
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/zealot_il_vec.jpg
|
||||
Oracle:Shadow (This creature can block or be blocked by only creatures with shadow.)\nWhenever Zealot il-Vec attacks and isn't blocked, you may have it deal 1 damage to target creature. If you do, prevent all combat damage Zealot il-Vec would deal this turn.
|
||||
@@ -109,6 +109,15 @@ public final class CardPredicates {
|
||||
};
|
||||
}
|
||||
|
||||
public static final Predicate<Card> sharesColorWith(final Card color) {
|
||||
return new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card c) {
|
||||
return c.sharesColorWith(color);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final Predicate<Card> possibleBlockers(final Card attacker) {
|
||||
return new Predicate<Card>() {
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.google.common.collect.Lists;
|
||||
|
||||
import forge.util.IItemReader;
|
||||
import forge.util.storage.StorageBase;
|
||||
import forge.util.storage.StorageReaderBase;
|
||||
|
||||
public final class EditionCollection extends StorageBase<CardEdition> {
|
||||
|
||||
@@ -107,7 +108,7 @@ public final class EditionCollection extends StorageBase<CardEdition> {
|
||||
*/
|
||||
public IItemReader<SealedProductTemplate> getBoosterGenerator() {
|
||||
// TODO Auto-generated method stub
|
||||
return new IItemReader<SealedProductTemplate>() {
|
||||
return new StorageReaderBase<SealedProductTemplate>(null) {
|
||||
|
||||
@Override
|
||||
public Map<String, SealedProductTemplate> readAll() {
|
||||
|
||||
@@ -188,11 +188,6 @@ public class EffectEffect extends SpellAbilityEffect {
|
||||
eff.setChosenColor(hostCard.getChosenColor());
|
||||
}
|
||||
|
||||
// Remember created effect
|
||||
if (sa.hasParam("RememberEffect")) {
|
||||
game.getCardState(hostCard).addRemembered(eff);
|
||||
}
|
||||
|
||||
// Duration
|
||||
final String duration = sa.getParam("Duration");
|
||||
if ((duration == null) || !duration.equals("Permanent")) {
|
||||
|
||||
@@ -192,30 +192,42 @@ public class CostDiscard extends CostPartWithList {
|
||||
}
|
||||
|
||||
return executePayment(ability, Aggregates.random(handList, c));
|
||||
|
||||
}
|
||||
if (discardType.contains("+WithSameName")) {
|
||||
String type = discardType.replace("+WithSameName", "");
|
||||
handList = CardLists.getValidCards(handList, type.split(";"), activator, ability.getSourceCard());
|
||||
final List<Card> landList2 = handList;
|
||||
handList = CardLists.filter(handList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
for (Card card : landList2) {
|
||||
if (!card.equals(c) && card.getName().equals(c.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (c == 0) return true;
|
||||
List<Card> discarded = new ArrayList<Card>();
|
||||
while (c > 0) {
|
||||
InputSelectCards inp = new InputSelectCardsFromList(1, 1, handList);
|
||||
inp.setMessage("Select one of the cards with the same name to discard. Already chosen: " + discarded);
|
||||
inp.setCancelAllowed(true);
|
||||
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
||||
if (inp.hasCancelled())
|
||||
return false;
|
||||
final Card first = inp.getSelected().get(0);
|
||||
discarded.add(first);
|
||||
handList = CardLists.filter(handList, CardPredicates.nameEquals(first.getName()));
|
||||
handList.remove(first);
|
||||
c--;
|
||||
}
|
||||
return executePayment(ability, discarded);
|
||||
} else {
|
||||
String type = new String(discardType);
|
||||
boolean sameName = false;
|
||||
if (type.contains("+WithSameName")) {
|
||||
sameName = true;
|
||||
type = type.replace("+WithSameName", "");
|
||||
}
|
||||
final String[] validType = type.split(";");
|
||||
handList = CardLists.getValidCards(handList, validType, activator, ability.getSourceCard());
|
||||
final List<Card> landList2 = handList;
|
||||
if (sameName) {
|
||||
handList = CardLists.filter(handList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
for (Card card : landList2) {
|
||||
if (!card.equals(c) && card.getName().equals(c.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (c == null) {
|
||||
final String sVar = ability.getSVar(amount);
|
||||
|
||||
@@ -20,10 +20,12 @@ package forge.card.cost;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
@@ -40,7 +42,7 @@ import forge.gui.input.InputSelectCardsFromList;
|
||||
*/
|
||||
public class CostReveal extends CostPartWithList {
|
||||
// Reveal<Num/Type/TypeDescription>
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new cost reveal.
|
||||
*
|
||||
@@ -83,6 +85,22 @@ public class CostReveal extends CostPartWithList {
|
||||
}
|
||||
} else if (this.getType().equals("Hand")) {
|
||||
return true;
|
||||
} else if (this.getType().equals("SameColor")) {
|
||||
if (amount == null) {
|
||||
return false;
|
||||
} else {
|
||||
for (final Card card : handList) {
|
||||
if (CardLists.filter(handList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.sharesColorWith(card);
|
||||
}
|
||||
}).size() >= amount) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ability.isSpell()) {
|
||||
handList.remove(source); // can't pay for itself
|
||||
@@ -117,6 +135,10 @@ public class CostReveal extends CostPartWithList {
|
||||
if (this.getType().equals("Hand"))
|
||||
return new PaymentDecision(new ArrayList<Card>(ai.getCardsIn(ZoneType.Hand)));
|
||||
|
||||
if (this.getType().equals("SameColor")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
hand = CardLists.getValidCards(hand, type.split(";"), ai, source);
|
||||
Integer c = this.convertAmount();
|
||||
if (c == null) {
|
||||
@@ -152,6 +174,37 @@ public class CostReveal extends CostPartWithList {
|
||||
for(Card c : activator.getCardsIn(ZoneType.Hand))
|
||||
executePayment(ability, c);
|
||||
return true;
|
||||
} else if (this.getType().equals("SameColor")) {
|
||||
Integer num = this.convertAmount();
|
||||
List<Card> handList = activator.getCardsIn(ZoneType.Hand);
|
||||
final List<Card> handList2 = handList;
|
||||
handList = CardLists.filter(handList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
for (Card card : handList2) {
|
||||
if (!card.equals(c) && card.sharesColorWith(c)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (num == 0) return true;
|
||||
List<Card> revealed = new ArrayList<Card>();
|
||||
while (num > 0) {
|
||||
InputSelectCards inp = new InputSelectCardsFromList(1, 1, handList);
|
||||
inp.setMessage("Select one of cards to reveal. Already chosen:" + revealed);
|
||||
inp.setCancelAllowed(true);
|
||||
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
||||
if (inp.hasCancelled())
|
||||
return false;
|
||||
final Card first = inp.getSelected().get(0);
|
||||
revealed.add(first);
|
||||
handList = CardLists.filter(handList, CardPredicates.sharesColorWith(first));
|
||||
handList.remove(first);
|
||||
num--;
|
||||
}
|
||||
return executePayment(ability, revealed);
|
||||
} else {
|
||||
Integer num = this.convertAmount();
|
||||
|
||||
@@ -193,6 +246,8 @@ public class CostReveal extends CostPartWithList {
|
||||
sb.append(this.getType());
|
||||
} else if (this.getType().equals("Hand")) {
|
||||
return ("Reveal you hand");
|
||||
} else if (this.getType().equals("SameColor")) {
|
||||
return ("Reveal " + i + " cards from your hand that share a color");
|
||||
} else {
|
||||
final StringBuilder desc = new StringBuilder();
|
||||
|
||||
|
||||
@@ -161,6 +161,10 @@ public class CostTapType extends CostPartWithList {
|
||||
public final boolean payHuman(final SpellAbility ability, final Game game) {
|
||||
List<Card> typeList = new ArrayList<Card>(ability.getActivatingPlayer().getCardsIn(ZoneType.Battlefield));
|
||||
String type = this.getType();
|
||||
final String amount = this.getAmount();
|
||||
final Card source = ability.getSourceCard();
|
||||
Integer c = this.convertAmount();
|
||||
|
||||
boolean sameType = false;
|
||||
if (type.contains("sharesCreatureTypeWith")) {
|
||||
sameType = true;
|
||||
@@ -168,6 +172,16 @@ public class CostTapType extends CostPartWithList {
|
||||
}
|
||||
typeList = CardLists.getValidCards(typeList, type.split(";"), ability.getActivatingPlayer(), ability.getSourceCard());
|
||||
typeList = CardLists.filter(typeList, Presets.UNTAPPED);
|
||||
if (c == null) {
|
||||
final String sVar = ability.getSVar(amount);
|
||||
// Generalize this
|
||||
if (sVar.equals("XChoice")) {
|
||||
c = Cost.chooseXValue(source, ability, typeList.size());
|
||||
} else {
|
||||
c = AbilityUtils.calculateAmount(source, amount, ability);
|
||||
}
|
||||
}
|
||||
|
||||
if (sameType) {
|
||||
final List<Card> List2 = typeList;
|
||||
typeList = CardLists.filter(typeList, new Predicate<Card>() {
|
||||
@@ -181,21 +195,28 @@ public class CostTapType extends CostPartWithList {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final String amount = this.getAmount();
|
||||
final Card source = ability.getSourceCard();
|
||||
Integer c = this.convertAmount();
|
||||
if (c == null) {
|
||||
final String sVar = ability.getSVar(amount);
|
||||
// Generalize this
|
||||
if (sVar.equals("XChoice")) {
|
||||
c = Cost.chooseXValue(source, ability, typeList.size());
|
||||
} else {
|
||||
c = AbilityUtils.calculateAmount(source, amount, ability);
|
||||
if (c == 0) return true;
|
||||
List<Card> tapped = new ArrayList<Card>();
|
||||
while (c > 0) {
|
||||
InputSelectCards inp = new InputSelectCardsFromList(1, 1, typeList);
|
||||
inp.setMessage("Select one of the cards to tap. Already chosen: " + tapped);
|
||||
inp.setCancelAllowed(true);
|
||||
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
||||
if (inp.hasCancelled())
|
||||
return false;
|
||||
final Card first = inp.getSelected().get(0);
|
||||
tapped.add(first);
|
||||
typeList = CardLists.filter(typeList, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(final Card c) {
|
||||
return c.sharesCreatureTypeWith(first);
|
||||
}
|
||||
});
|
||||
typeList.remove(first);
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
return executePayment(ability, tapped);
|
||||
}
|
||||
|
||||
InputSelectCards inp = new InputSelectCardsFromList(c, c, typeList);
|
||||
inp.setMessage("Select a " + getDescriptiveType() + " to tap (%d left)");
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.util.List;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import forge.Card;
|
||||
@@ -61,8 +60,11 @@ import forge.gui.match.controllers.CMessage;
|
||||
import forge.gui.match.controllers.CStack;
|
||||
import forge.gui.match.nonsingleton.VField;
|
||||
import forge.gui.match.views.VAntes;
|
||||
import forge.gui.menubar.FMenuBar;
|
||||
import forge.gui.menubar.MenuUtil;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.net.FServer;
|
||||
import forge.properties.ForgeLookAndFeel;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.properties.NewConstants;
|
||||
import forge.quest.QuestController;
|
||||
@@ -81,7 +83,8 @@ import forge.view.FView;
|
||||
*/
|
||||
public enum FControl {
|
||||
instance;
|
||||
|
||||
|
||||
private FMenuBar menuBar;
|
||||
private List<Shortcut> shortcuts;
|
||||
private JLayeredPane display;
|
||||
private Screens state = Screens.UNKNOWN;
|
||||
@@ -166,13 +169,13 @@ public enum FControl {
|
||||
public void initialize() {
|
||||
// Preloads skin components (using progress bar).
|
||||
FSkin.loadFull();
|
||||
|
||||
//This must be done here or at least between the skin being loaded and any FTabbedPanes being created.
|
||||
//Why,Swing? Why is this not a property of JTabbbedPane?
|
||||
UIManager.put("TabbedPane.selected", FSkin.getColor(FSkin.Colors.CLR_ACTIVE));
|
||||
UIManager.put("TabbedPane.contentOpaque", FSkin.getColor(FSkin.Colors.CLR_THEME));
|
||||
UIManager.put("TabbedPane.unselectedBackground", FSkin.getColor(FSkin.Colors.CLR_THEME2));
|
||||
setComboBoxLookAndFeel();
|
||||
|
||||
// This must be done here or at least between the skin being loaded
|
||||
// and any GUI controls being created.
|
||||
FSkin.setProgessBarMessage("Setting look and feel...");
|
||||
setForgeLookAndFeel();
|
||||
|
||||
createMenuBar();
|
||||
|
||||
this.shortcuts = KeyboardShortcuts.attachKeyboardShortcuts();
|
||||
this.display = FView.SINGLETON_INSTANCE.getLpnDocument();
|
||||
@@ -208,21 +211,16 @@ public enum FControl {
|
||||
public void run() { Singletons.getView().initialize(); } });
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/">UIManager Defaults</a>
|
||||
*/
|
||||
private void setComboBoxLookAndFeel() {
|
||||
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_THEMED_COMBOBOX)) {
|
||||
UIManager.put("ComboBox.background", FSkin.getColor(FSkin.Colors.CLR_THEME2));
|
||||
UIManager.put("ComboBox.foreground", FSkin.getColor(FSkin.Colors.CLR_TEXT));
|
||||
UIManager.put("ComboBox.selectionBackground", FSkin.getColor(FSkin.Colors.CLR_ACTIVE));
|
||||
UIManager.put("ComboBox.selectionForeground", FSkin.getColor(FSkin.Colors.CLR_TEXT));
|
||||
UIManager.put("ComboBox.disabledBackground", FSkin.getColor(FSkin.Colors.CLR_THEME2));
|
||||
UIManager.put("ComboBox.disabledForeground", FSkin.getColor(FSkin.Colors.CLR_THEME2).darker());
|
||||
UIManager.put("Button.select", FSkin.getColor(FSkin.Colors.CLR_ACTIVE));
|
||||
UIManager.put("ComboBox.font", FSkin.getFont(UIManager.getFont("ComboBox.font").getSize()));
|
||||
}
|
||||
private void setForgeLookAndFeel() {
|
||||
ForgeLookAndFeel laf = new ForgeLookAndFeel();
|
||||
laf.setForgeLookAndFeel(Singletons.getView().getFrame());
|
||||
}
|
||||
|
||||
private void createMenuBar() {
|
||||
if (MenuUtil.isMenuBarVisible()) {
|
||||
this.menuBar = new FMenuBar(Singletons.getView().getFrame());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches between display states in top level JFrame.
|
||||
|
||||
@@ -49,7 +49,7 @@ public class CardCollections {
|
||||
public CardCollections() {
|
||||
StopWatch sw = new StopWatch();
|
||||
sw.start();
|
||||
this.constructed = new StorageImmediatelySerialized<Deck>(new DeckSerializer(new File(NewConstants.DECK_CONSTRUCTED_DIR), true));
|
||||
this.constructed = new StorageImmediatelySerialized<Deck>(new DeckSerializer(new File(NewConstants.DECK_CONSTRUCTED_DIR), true), true);
|
||||
this.draft = new StorageImmediatelySerialized<DeckGroup>(new DeckGroupSerializer(new File(NewConstants.DECK_DRAFT_DIR)));
|
||||
this.sealed = new StorageImmediatelySerialized<DeckGroup>(new DeckGroupSerializer(new File(NewConstants.DECK_SEALED_DIR)));
|
||||
this.cube = new StorageImmediatelySerialized<Deck>(new DeckSerializer(new File(NewConstants.DECK_CUBE_DIR)));
|
||||
|
||||
@@ -77,7 +77,14 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
|
||||
getOrCreate(DeckSection.Main);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.item.InventoryItem#getItemType()
|
||||
*/
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return "Deck";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.getName().hashCode();
|
||||
|
||||
@@ -19,11 +19,13 @@ package forge.deck;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public abstract class DeckBase implements Serializable, Comparable<DeckBase> {
|
||||
public abstract class DeckBase implements Serializable, Comparable<DeckBase>, InventoryItem {
|
||||
private static final long serialVersionUID = -7538150536939660052L;
|
||||
// gameType is from Constant.GameType, like GameType.Regular
|
||||
|
||||
|
||||
@@ -135,4 +135,13 @@ public class DeckGroup extends DeckBase {
|
||||
}
|
||||
};
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.item.InventoryItem#getItemType()
|
||||
*/
|
||||
@Override
|
||||
public String getItemType() {
|
||||
// TODO Auto-generated method stub
|
||||
return "Set of limited mode decks";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -105,7 +105,16 @@ public class DeckgenUtil {
|
||||
* @return {@link forge.deck.Deck}
|
||||
*/
|
||||
public static Deck getConstructedDeck(final String selection) {
|
||||
return Singletons.getModel().getDecks().getConstructed().get(selection);
|
||||
IStorage<Deck> path = Singletons.getModel().getDecks().getConstructed();
|
||||
String name = selection;
|
||||
int idxSlash = name.indexOf('/');
|
||||
while( idxSlash > 0 ) {
|
||||
String sf = name.substring(0, idxSlash).trim();
|
||||
path = path.getFolders().get(sf);
|
||||
name = name.substring(idxSlash+1).trim();
|
||||
idxSlash = name.indexOf('/');
|
||||
};
|
||||
return path.get(name);
|
||||
}
|
||||
|
||||
public static Deck getPreconDeck(String selection) {
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckGroup;
|
||||
import forge.util.FileUtil;
|
||||
@@ -111,7 +113,7 @@ public class DeckGroupSerializer extends StorageReaderFolder<DeckGroup> implemen
|
||||
* @return the file
|
||||
*/
|
||||
public File makeFileFor(final DeckGroup decks) {
|
||||
return new File(this.getDirectory(), decks.getBestFileName());
|
||||
return new File(this.directory, decks.getBestFileName());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -134,4 +136,10 @@ public class DeckGroupSerializer extends StorageReaderFolder<DeckGroup> implemen
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<File> getSubFolders() {
|
||||
// Sealed decks are kept in separate folders, no further drilling possible
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import forge.properties.NewConstants;
|
||||
import forge.util.FileSection;
|
||||
import forge.util.FileSectionManual;
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.IItemReader;
|
||||
import forge.util.IItemSerializer;
|
||||
import forge.util.storage.StorageReaderFolder;
|
||||
import freemarker.template.Configuration;
|
||||
@@ -194,7 +195,7 @@ public class DeckSerializer extends StorageReaderFolder<Deck> implements IItemSe
|
||||
}
|
||||
|
||||
public File makeFileFor(final Deck deck) {
|
||||
return new File(this.getDirectory(), deck.getBestFileName() + FILE_EXTENSION);
|
||||
return new File(this.directory, deck.getBestFileName() + FILE_EXTENSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -245,4 +246,14 @@ public class DeckSerializer extends StorageReaderFolder<Deck> implements IItemSe
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.util.storage.StorageReaderBase#getReaderForFolder(java.io.File)
|
||||
*/
|
||||
@Override
|
||||
public IItemReader<Deck> getReaderForFolder(File subfolder) {
|
||||
if ( !subfolder.getParentFile().equals(directory) )
|
||||
throw new UnsupportedOperationException("Only child folders of " + directory + " may be processed");
|
||||
return new DeckSerializer(subfolder, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package forge.game.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
@@ -28,6 +29,9 @@ import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.CounterType;
|
||||
import forge.GameEntity;
|
||||
import forge.card.TriggerReplacementBase;
|
||||
import forge.card.trigger.Trigger;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.combat.CombatUtil;
|
||||
import forge.game.player.Player;
|
||||
@@ -197,7 +201,7 @@ public class AiBlockController {
|
||||
// 1.Blockers that can destroy the attacker but won't get
|
||||
// destroyed
|
||||
killingBlockers = getKillingBlockers(combat, attacker, safeBlockers);
|
||||
if (killingBlockers.size() > 0) {
|
||||
if (!killingBlockers.isEmpty()) {
|
||||
blocker = ComputerUtilCard.getWorstCreatureAI(killingBlockers);
|
||||
} else if (!attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")) {
|
||||
blocker = ComputerUtilCard.getWorstCreatureAI(safeBlockers);
|
||||
@@ -215,11 +219,34 @@ public class AiBlockController {
|
||||
}
|
||||
}
|
||||
// 4.Blockers that can destroy the attacker and are worth less
|
||||
if (blocker == null && killingBlockers.size() > 0) {
|
||||
if (blocker == null && !killingBlockers.isEmpty()) {
|
||||
final Card worst = ComputerUtilCard.getWorstCreatureAI(killingBlockers);
|
||||
int value = ComputerUtilCard.evaluateCreature(attacker);
|
||||
|
||||
// check for triggers when unblocked
|
||||
for (Trigger trigger : attacker.getTriggers()) {
|
||||
final HashMap<String, String> trigParams = trigger.getMapParams();
|
||||
TriggerType mode = trigger.getMode();
|
||||
|
||||
if ((ComputerUtilCard.evaluateCreature(worst) + diff) < ComputerUtilCard
|
||||
.evaluateCreature(attacker)) {
|
||||
if (!trigger.requirementsCheck(attacker.getGame())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode == TriggerType.DamageDone) {
|
||||
if (TriggerReplacementBase.matchesValid(attacker, trigParams.get("ValidSource").split(","), attacker)
|
||||
&& attacker.getNetCombatDamage() > 0
|
||||
&& (!trigParams.containsKey("ValidTarget")
|
||||
|| TriggerReplacementBase.matchesValid(combat.getDefenderByAttacker(attacker), trigParams.get("ValidTarget").split(","), attacker))) {
|
||||
value += 50;
|
||||
}
|
||||
} else if (mode == TriggerType.AttackerUnblocked) {
|
||||
if (TriggerReplacementBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), attacker)) {
|
||||
value += 50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((ComputerUtilCard.evaluateCreature(worst) + diff) < value) {
|
||||
blocker = worst;
|
||||
}
|
||||
}
|
||||
@@ -378,14 +405,13 @@ public class AiBlockController {
|
||||
|
||||
List<Card> possibleBlockers = getPossibleBlockers(combat, attacker, blockersLeft, true);
|
||||
killingBlockers = getKillingBlockers(combat, attacker, possibleBlockers);
|
||||
if ((killingBlockers.size() > 0) && ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
||||
if (!killingBlockers.isEmpty() && ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
||||
final Card blocker = ComputerUtilCard.getWorstCreatureAI(killingBlockers);
|
||||
combat.addBlocker(attacker, blocker);
|
||||
currentAttackers.remove(attacker);
|
||||
}
|
||||
}
|
||||
attackersLeft = (new ArrayList<Card>(currentAttackers));
|
||||
|
||||
}
|
||||
|
||||
// Chump Blocks (should only be made if life is in danger)
|
||||
|
||||
@@ -82,6 +82,15 @@ public class CustomLimited extends DeckBase {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.item.InventoryItem#getItemType()
|
||||
*/
|
||||
@Override
|
||||
public String getItemType() {
|
||||
// TODO Auto-generated method stub
|
||||
return "Limited game setup";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the.
|
||||
*
|
||||
|
||||
@@ -38,6 +38,7 @@ import forge.gui.deckeditor.views.VDeckgen;
|
||||
import forge.gui.framework.DragCell;
|
||||
import forge.gui.framework.EDocID;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.itemmanager.CardManager;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerIO;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
|
||||
@@ -86,9 +87,11 @@ public final class CEditorCommander extends ACEditorBase<PaperCard, Deck> {
|
||||
commanderPool = ItemPool.createFrom(CardDb.instance().getAllCards(Predicates.compose(Predicates.and(CardRulesPredicates.Presets.IS_CREATURE,CardRulesPredicates.Presets.IS_LEGENDARY), PaperCard.FN_GET_RULES)),PaperCard.class);
|
||||
normalPool = ItemPool.createFrom(CardDb.instance().getAllCards(), PaperCard.class);
|
||||
|
||||
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), true);
|
||||
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), true);
|
||||
boolean wantUnique = SItemManagerIO.getPref(EditorPreference.display_unique_only);
|
||||
|
||||
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
|
||||
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
|
||||
|
||||
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
|
||||
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import forge.gui.deckeditor.views.VCardCatalog;
|
||||
import forge.gui.deckeditor.views.VCurrentDeck;
|
||||
import forge.gui.framework.EDocID;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.CardManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerIO;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerIO.EditorPreference;
|
||||
@@ -92,8 +92,8 @@ public final class CEditorConstructed extends ACEditorBase<PaperCard, Deck> {
|
||||
|
||||
boolean wantUnique = SItemManagerIO.getPref(EditorPreference.display_unique_only);
|
||||
|
||||
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
|
||||
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
|
||||
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
|
||||
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), wantUnique);
|
||||
|
||||
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
|
||||
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);
|
||||
|
||||
@@ -37,7 +37,7 @@ import forge.gui.deckeditor.views.VCurrentDeck;
|
||||
import forge.gui.deckeditor.views.VDeckgen;
|
||||
import forge.gui.framework.DragCell;
|
||||
import forge.gui.home.sanctioned.CSubmenuDraft;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.CardManager;
|
||||
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
|
||||
import forge.item.PaperCard;
|
||||
import forge.item.InventoryItem;
|
||||
@@ -64,8 +64,8 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
|
||||
* Updates the deck editor UI as necessary draft selection mode.
|
||||
*/
|
||||
public CEditorDraftingProcess() {
|
||||
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
|
||||
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
|
||||
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);
|
||||
|
||||
@@ -30,7 +30,7 @@ import forge.gui.deckeditor.views.VDeckgen;
|
||||
import forge.gui.framework.DragCell;
|
||||
import forge.gui.home.sanctioned.CSubmenuDraft;
|
||||
import forge.gui.home.sanctioned.CSubmenuSealed;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.CardManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
|
||||
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
|
||||
import forge.item.PaperCard;
|
||||
@@ -59,8 +59,8 @@ public final class CEditorLimited extends ACEditorBase<PaperCard, DeckGroup> {
|
||||
* @param deckMap0   {@link forge.deck.DeckGroup}<{@link forge.util.storage.IStorage}>
|
||||
*/
|
||||
public CEditorLimited(final IStorage<DeckGroup> deckMap0) {
|
||||
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
|
||||
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
|
||||
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);
|
||||
|
||||
@@ -38,7 +38,7 @@ import forge.gui.deckeditor.views.VDeckgen;
|
||||
import forge.gui.framework.DragCell;
|
||||
import forge.gui.home.quest.CSubmenuQuestDecks;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.CardManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
|
||||
import forge.gui.toolbox.itemmanager.table.TableColumnInfo;
|
||||
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
|
||||
@@ -95,8 +95,8 @@ public final class CEditorQuest extends ACEditorBase<PaperCard, Deck> {
|
||||
public CEditorQuest(final QuestController questData0) {
|
||||
this.questData = questData0;
|
||||
|
||||
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
|
||||
catalogManager.setAlwaysNonUnique(true);
|
||||
deckManager.setAlwaysNonUnique(true);
|
||||
|
||||
@@ -48,7 +48,7 @@ import forge.gui.framework.DragCell;
|
||||
import forge.gui.home.quest.CSubmenuQuestDecks;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.InventoryItemManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
|
||||
import forge.gui.toolbox.itemmanager.table.TableColumnInfo;
|
||||
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
|
||||
@@ -127,8 +127,8 @@ public final class CEditorQuestCardShop extends ACEditorBase<InventoryItem, Deck
|
||||
public CEditorQuestCardShop(final QuestController qd) {
|
||||
this.questData = qd;
|
||||
|
||||
final ItemManager<InventoryItem> catalogManager = new ItemManager<InventoryItem>(InventoryItem.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final ItemManager<InventoryItem> deckManager = new ItemManager<InventoryItem>(InventoryItem.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final InventoryItemManager catalogManager = new InventoryItemManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
final InventoryItemManager deckManager = new InventoryItemManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), false);
|
||||
|
||||
catalogManager.setAlwaysNonUnique(true);
|
||||
deckManager.setAlwaysNonUnique(true);
|
||||
|
||||
@@ -34,7 +34,7 @@ import forge.gui.deckeditor.views.VCurrentDeck;
|
||||
import forge.gui.deckeditor.views.VDeckgen;
|
||||
import forge.gui.framework.DragCell;
|
||||
import forge.gui.framework.EDocID;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.CardManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil;
|
||||
import forge.gui.toolbox.itemmanager.table.TableColumnInfo;
|
||||
import forge.gui.toolbox.itemmanager.table.SColumnUtil;
|
||||
@@ -74,8 +74,8 @@ public final class CEditorVariant extends ACEditorBase<PaperCard, Deck> {
|
||||
cardPoolCondition = poolCondition;
|
||||
exitToScreen = exitTo;
|
||||
|
||||
final ItemManager<PaperCard> catalogManager = new ItemManager<PaperCard>(PaperCard.class, VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), true);
|
||||
final ItemManager<PaperCard> deckManager = new ItemManager<PaperCard>(PaperCard.class, VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), true);
|
||||
final CardManager catalogManager = new CardManager(VCardCatalog.SINGLETON_INSTANCE.getStatLabels(), true);
|
||||
final CardManager deckManager = new CardManager(VCurrentDeck.SINGLETON_INSTANCE.getStatLabels(), true);
|
||||
|
||||
VCardCatalog.SINGLETON_INSTANCE.setItemManager(catalogManager);
|
||||
VCurrentDeck.SINGLETON_INSTANCE.setItemManager(deckManager);
|
||||
|
||||
@@ -1,406 +1,407 @@
|
||||
package forge.gui.framework;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionAdapter;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.FNetOverlay;
|
||||
import forge.gui.toolbox.FAbsolutePositioner;
|
||||
import forge.gui.toolbox.FOverlay;
|
||||
import forge.view.FView;
|
||||
|
||||
/**
|
||||
* Package-private utilities for resizing drag behavior using
|
||||
* the draggable panels registered in FView.
|
||||
*
|
||||
* <br><br><i>(S at beginning of class name denotes a static factory.)</i>
|
||||
*/
|
||||
public final class SResizingUtil {
|
||||
private static final List<DragCell> LEFT_PANELS = new ArrayList<DragCell>();
|
||||
private static final List<DragCell> RIGHT_PANELS = new ArrayList<DragCell>();
|
||||
private static final List<DragCell> TOP_PANELS = new ArrayList<DragCell>();
|
||||
private static final List<DragCell> BOTTOM_PANELS = new ArrayList<DragCell>();
|
||||
|
||||
private static int dX;
|
||||
private static int evtX;
|
||||
private static int dY;
|
||||
private static int evtY;
|
||||
|
||||
/** Minimum cell width. */
|
||||
public static final int W_MIN = 100;
|
||||
/** Minimum cell height. */
|
||||
public static final int H_MIN = 75;
|
||||
|
||||
private static final MouseListener MAD_RESIZE_X = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(final MouseEvent e) {
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(final MouseEvent e) {
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent e) {
|
||||
SResizingUtil.startResizeX(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(final MouseEvent e) {
|
||||
SResizingUtil.endResize();
|
||||
}
|
||||
};
|
||||
|
||||
private static final MouseListener MAD_RESIZE_Y = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(final MouseEvent e) {
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(final MouseEvent e) {
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent e) {
|
||||
SResizingUtil.startResizeY(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(final MouseEvent e) {
|
||||
SResizingUtil.endResize();
|
||||
}
|
||||
};
|
||||
|
||||
private static final MouseMotionListener MMA_DRAG_X = new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseDragged(final MouseEvent e) {
|
||||
SResizingUtil.resizeX(e);
|
||||
}
|
||||
};
|
||||
|
||||
private static final MouseMotionListener MMA_DRAG_Y = new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseDragged(final MouseEvent e) {
|
||||
SResizingUtil.resizeY(e);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ComponentListener CAD_RESIZE = new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(final ComponentEvent e) {
|
||||
resizeWindow();
|
||||
SRearrangingUtil.updateBorders();
|
||||
}
|
||||
};
|
||||
|
||||
public static void resizeWindow() {
|
||||
final List<DragCell> cells = FView.SINGLETON_INSTANCE.getDragCells();
|
||||
final JPanel pnlContent = FView.SINGLETON_INSTANCE.getPnlContent();
|
||||
final JPanel pnlInsets = FView.SINGLETON_INSTANCE.getPnlInsets();
|
||||
|
||||
Rectangle mainBounds = FView.SINGLETON_INSTANCE.getFrame().getContentPane().getBounds();
|
||||
FAbsolutePositioner.SINGLETON_INSTANCE.containerResized(mainBounds);
|
||||
FOverlay.SINGLETON_INSTANCE.getPanel().setBounds(mainBounds);
|
||||
FNetOverlay.SINGLETON_INSTANCE.containerResized(mainBounds);
|
||||
|
||||
pnlInsets.setBounds(mainBounds);
|
||||
pnlInsets.validate();
|
||||
|
||||
final int w = pnlContent.getWidth();
|
||||
final int h = pnlContent.getHeight();
|
||||
|
||||
double roughVal = 0;
|
||||
int smoothVal = 0;
|
||||
|
||||
Set<Component> existingComponents = new HashSet<Component>();
|
||||
for (Component c : pnlContent.getComponents()) {
|
||||
existingComponents.add(c);
|
||||
}
|
||||
|
||||
// This is the core of the pixel-perfect layout. To avoid <20>1 px errors on borders
|
||||
// from rounding individual panels, the intermediate values (exactly accurate, in %)
|
||||
// for width and height are rounded based on comparison to other panels in the
|
||||
// layout. This is to avoid errors such as:
|
||||
// 10% = 9.8px -> 10px -> x 3 = 30px
|
||||
// 30% = 29.4px -> 29px (!)
|
||||
for (final DragCell cellA : cells) {
|
||||
RectangleOfDouble cellSizeA = cellA.getRoughBounds();
|
||||
roughVal = cellSizeA.getX() * w + cellSizeA.getW() * w;
|
||||
|
||||
smoothVal = (int) Math.round(roughVal);
|
||||
for (final DragCell cellB : cells) {
|
||||
RectangleOfDouble cellSizeB = cellB.getRoughBounds();
|
||||
if ((cellSizeB.getX() * w + cellSizeB.getW() * w) == roughVal) {
|
||||
cellB.setSmoothW(smoothVal - (int) Math.round(cellSizeB.getX() * w));
|
||||
}
|
||||
}
|
||||
cellA.setSmoothW(smoothVal - (int) Math.round(cellSizeA.getX() * w));
|
||||
|
||||
roughVal = cellSizeA.getY() * h + cellSizeA.getH() * h;
|
||||
smoothVal = (int) Math.round(roughVal);
|
||||
for (final DragCell cellB : cells) {
|
||||
RectangleOfDouble cellSizeB = cellB.getRoughBounds();
|
||||
if (cellSizeB.getY() * h + cellSizeB.getH() * h == roughVal) {
|
||||
cellB.setSmoothH(smoothVal - (int) Math.round(cellSizeB.getY() * h));
|
||||
}
|
||||
}
|
||||
cellA.setSmoothH(smoothVal - (int) Math.round(cellSizeA.getY() * h));
|
||||
|
||||
// X and Y coordinate can be rounded as usual.
|
||||
cellA.setSmoothX((int) Math.round(cellSizeA.getX() * w));
|
||||
cellA.setSmoothY((int) Math.round(cellSizeA.getY() * h));
|
||||
|
||||
// only add component if not already in container; otherwise the keyboard focus
|
||||
// jumps around to the most recenly added component
|
||||
if (!existingComponents.contains(cellA)) {
|
||||
pnlContent.add(cellA);
|
||||
}
|
||||
}
|
||||
|
||||
// Lock in final bounds and build heads.
|
||||
for (final DragCell t : cells) {
|
||||
t.setSmoothBounds();
|
||||
t.validate();
|
||||
t.refresh();
|
||||
}
|
||||
|
||||
cells.clear();
|
||||
}
|
||||
|
||||
/** @param e   {@link java.awt.event.MouseEvent} */
|
||||
public static void resizeX(final MouseEvent e) {
|
||||
dX = (int) e.getLocationOnScreen().getX() - evtX;
|
||||
evtX = (int) e.getLocationOnScreen().getX();
|
||||
boolean leftLock = false;
|
||||
boolean rightLock = false;
|
||||
|
||||
for (final DragCell t : LEFT_PANELS) {
|
||||
if ((t.getW() + dX) < W_MIN) { leftLock = true; break; }
|
||||
}
|
||||
|
||||
for (final DragCell t : RIGHT_PANELS) {
|
||||
if ((t.getW() - dX) < W_MIN) { rightLock = true; break; }
|
||||
}
|
||||
|
||||
if (dX < 0 && leftLock) { return; }
|
||||
if (dX > 0 && rightLock) { return; }
|
||||
|
||||
for (final DragCell t : LEFT_PANELS) {
|
||||
t.setBounds(t.getX(), t.getY(), t.getW() + dX, t.getH());
|
||||
t.refresh();
|
||||
}
|
||||
|
||||
for (final DragCell t : RIGHT_PANELS) {
|
||||
t.setBounds(t.getX() + dX, t.getY(), t.getW() - dX, t.getH());
|
||||
t.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/** @param e   {@link java.awt.event.MouseEvent} */
|
||||
public static void resizeY(final MouseEvent e) {
|
||||
dY = (int) e.getLocationOnScreen().getY() - evtY;
|
||||
evtY = (int) e.getLocationOnScreen().getY();
|
||||
boolean topLock = false;
|
||||
boolean bottomLock = false;
|
||||
|
||||
for (final DragCell t : TOP_PANELS) {
|
||||
if ((t.getH() + dY) < H_MIN) { topLock = true; break; }
|
||||
}
|
||||
|
||||
for (final DragCell t : BOTTOM_PANELS) {
|
||||
if ((t.getH() - dY) < H_MIN) { bottomLock = true; break; }
|
||||
}
|
||||
|
||||
if (dY < 0 && topLock) { return; }
|
||||
if (dY > 0 && bottomLock) { return; }
|
||||
|
||||
for (final DragCell t : TOP_PANELS) {
|
||||
t.setBounds(t.getX(), t.getY(), t.getW(), t.getH() + dY);
|
||||
t.revalidate();
|
||||
t.repaintSelf();
|
||||
}
|
||||
|
||||
for (final DragCell t : BOTTOM_PANELS) {
|
||||
t.setBounds(t.getX(), t.getY() + dY, t.getW(), t.getH() - dY);
|
||||
t.revalidate();
|
||||
t.repaintSelf();
|
||||
}
|
||||
}
|
||||
|
||||
/** @param e   {@link java.awt.event.MouseEvent} */
|
||||
public static void startResizeX(final MouseEvent e) {
|
||||
evtX = (int) e.getLocationOnScreen().getX();
|
||||
LEFT_PANELS.clear();
|
||||
RIGHT_PANELS.clear();
|
||||
|
||||
final DragCell src = (DragCell) ((JPanel) e.getSource()).getParent();
|
||||
final int srcX2 = src.getAbsX2();
|
||||
|
||||
int limTop = -1;
|
||||
int limBottom = Integer.MAX_VALUE;
|
||||
int tempX = -1;
|
||||
int tempX2 = -1;
|
||||
int tempY = -1;
|
||||
int tempY2 = -1;
|
||||
|
||||
// Add all panels who share a left or right edge with the
|
||||
// same coordinate as the right edge of the source panel.
|
||||
for (final DragCell t : FView.SINGLETON_INSTANCE.getDragCells()) {
|
||||
tempX = t.getAbsX();
|
||||
tempX2 = t.getAbsX2();
|
||||
|
||||
if (srcX2 == tempX) { RIGHT_PANELS.add(t); }
|
||||
else if (srcX2 == tempX2) { LEFT_PANELS.add(t); }
|
||||
}
|
||||
|
||||
// Set limits at panels which are level at intersections.
|
||||
for (final DragCell pnlL : LEFT_PANELS) {
|
||||
if (pnlL.equals(src)) { continue; }
|
||||
tempY = pnlL.getAbsY();
|
||||
tempY2 = pnlL.getAbsY2();
|
||||
|
||||
for (final DragCell pnlR : RIGHT_PANELS) {
|
||||
// Upper edges match? Set a bottom limit.
|
||||
if (tempY >= src.getAbsY2() && tempY == pnlR.getAbsY() && tempY < limBottom) {
|
||||
limBottom = tempY;
|
||||
}
|
||||
// Lower edges match? Set an upper limit.
|
||||
else if (tempY2 <= src.getAbsY() && tempY2 == pnlR.getAbsY2() && tempY2 > limTop) {
|
||||
limTop = tempY2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove non-contiguous panels from left side using limits.
|
||||
final Iterator<DragCell> itrLeft = LEFT_PANELS.iterator();
|
||||
while (itrLeft.hasNext()) {
|
||||
final DragCell t = itrLeft.next();
|
||||
|
||||
if (t.getAbsY() >= limBottom || t.getAbsY2() <= limTop) {
|
||||
itrLeft.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove non-contiguous panels from right side using limits.
|
||||
final Iterator<DragCell> itrRight = RIGHT_PANELS.iterator();
|
||||
while (itrRight.hasNext()) {
|
||||
final DragCell t = itrRight.next();
|
||||
|
||||
if (t.getAbsY() >= limBottom || t.getAbsY2() <= limTop) {
|
||||
itrRight.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param e   {@link java.awt.event.MouseEvent} */
|
||||
public static void startResizeY(final MouseEvent e) {
|
||||
evtY = (int) e.getLocationOnScreen().getY();
|
||||
TOP_PANELS.clear();
|
||||
BOTTOM_PANELS.clear();
|
||||
|
||||
final DragCell src = (DragCell) ((JPanel) e.getSource()).getParent();
|
||||
final int srcY2 = src.getAbsY2();
|
||||
|
||||
int limLeft = -1;
|
||||
int limRight = Integer.MAX_VALUE;
|
||||
int tempX = -1;
|
||||
int tempX2 = -1;
|
||||
int tempY = -1;
|
||||
int tempY2 = -1;
|
||||
|
||||
// Add all panels who share a top or bottom edge with the
|
||||
// same coordinate as the bottom edge of the source panel.
|
||||
for (final DragCell t : FView.SINGLETON_INSTANCE.getDragCells()) {
|
||||
tempY = t.getAbsY();
|
||||
tempY2 = t.getAbsY2();
|
||||
|
||||
if (srcY2 == tempY) { BOTTOM_PANELS.add(t); }
|
||||
else if (srcY2 == tempY2) { TOP_PANELS.add(t); }
|
||||
}
|
||||
|
||||
// Set limits at panels which are level at intersections.
|
||||
for (final DragCell pnlT : TOP_PANELS) {
|
||||
if (pnlT.equals(src)) { continue; }
|
||||
tempX = pnlT.getAbsX();
|
||||
tempX2 = pnlT.getAbsX2();
|
||||
|
||||
for (final DragCell pnlB : BOTTOM_PANELS) {
|
||||
// Right edges match? Set a right limit.
|
||||
if (tempX >= src.getAbsX2() && tempX == pnlB.getAbsX() && tempX < limRight) {
|
||||
limRight = tempX;
|
||||
}
|
||||
// Left edges match? Set an left limit.
|
||||
else if (tempX2 <= src.getAbsX() && tempX2 == pnlB.getAbsX2() && tempX2 > limLeft) {
|
||||
limLeft = tempX2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove non-contiguous panels from left side using limits.
|
||||
final Iterator<DragCell> itrTop = TOP_PANELS.iterator();
|
||||
while (itrTop.hasNext()) {
|
||||
final DragCell t = itrTop.next();
|
||||
if (t.getAbsX() >= limRight || t.getAbsX2() <= limLeft) {
|
||||
itrTop.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove non-contiguous panels from right side using limits.
|
||||
final Iterator<DragCell> itrBottom = BOTTOM_PANELS.iterator();
|
||||
while (itrBottom.hasNext()) {
|
||||
final DragCell t = itrBottom.next();
|
||||
if (t.getAbsX() >= limRight || t.getAbsX2() <= limLeft) {
|
||||
itrBottom.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** */
|
||||
public static void endResize() {
|
||||
SLayoutIO.saveLayout(null);
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.MouseListener} */
|
||||
public static MouseListener getResizeXListener() {
|
||||
return MAD_RESIZE_X;
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.MouseListener} */
|
||||
public static MouseListener getResizeYListener() {
|
||||
return MAD_RESIZE_Y;
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.MouseMotionListener} */
|
||||
public static MouseMotionListener getDragXListener() {
|
||||
return MMA_DRAG_X;
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.MouseMotionListener} */
|
||||
public static MouseMotionListener getDragYListener() {
|
||||
return MMA_DRAG_Y;
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.ComponentListener} */
|
||||
public static ComponentListener getWindowResizeListener() {
|
||||
return CAD_RESIZE;
|
||||
}
|
||||
}
|
||||
package forge.gui.framework;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionAdapter;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.FNetOverlay;
|
||||
import forge.gui.toolbox.FAbsolutePositioner;
|
||||
import forge.gui.toolbox.FOverlay;
|
||||
import forge.view.FView;
|
||||
|
||||
/**
|
||||
* Package-private utilities for resizing drag behavior using
|
||||
* the draggable panels registered in FView.
|
||||
*
|
||||
* <br><br><i>(S at beginning of class name denotes a static factory.)</i>
|
||||
*/
|
||||
public final class SResizingUtil {
|
||||
private static final List<DragCell> LEFT_PANELS = new ArrayList<DragCell>();
|
||||
private static final List<DragCell> RIGHT_PANELS = new ArrayList<DragCell>();
|
||||
private static final List<DragCell> TOP_PANELS = new ArrayList<DragCell>();
|
||||
private static final List<DragCell> BOTTOM_PANELS = new ArrayList<DragCell>();
|
||||
|
||||
private static int dX;
|
||||
private static int evtX;
|
||||
private static int dY;
|
||||
private static int evtY;
|
||||
|
||||
/** Minimum cell width. */
|
||||
public static final int W_MIN = 100;
|
||||
/** Minimum cell height. */
|
||||
public static final int H_MIN = 75;
|
||||
|
||||
private static final MouseListener MAD_RESIZE_X = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(final MouseEvent e) {
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(final MouseEvent e) {
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent e) {
|
||||
SResizingUtil.startResizeX(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(final MouseEvent e) {
|
||||
SResizingUtil.endResize();
|
||||
}
|
||||
};
|
||||
|
||||
private static final MouseListener MAD_RESIZE_Y = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(final MouseEvent e) {
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(final MouseEvent e) {
|
||||
FView.SINGLETON_INSTANCE.getLpnDocument().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(final MouseEvent e) {
|
||||
SResizingUtil.startResizeY(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(final MouseEvent e) {
|
||||
SResizingUtil.endResize();
|
||||
}
|
||||
};
|
||||
|
||||
private static final MouseMotionListener MMA_DRAG_X = new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseDragged(final MouseEvent e) {
|
||||
SResizingUtil.resizeX(e);
|
||||
}
|
||||
};
|
||||
|
||||
private static final MouseMotionListener MMA_DRAG_Y = new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseDragged(final MouseEvent e) {
|
||||
SResizingUtil.resizeY(e);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ComponentListener CAD_RESIZE = new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(final ComponentEvent e) {
|
||||
resizeWindow();
|
||||
SRearrangingUtil.updateBorders();
|
||||
}
|
||||
};
|
||||
|
||||
public static void resizeWindow() {
|
||||
final List<DragCell> cells = FView.SINGLETON_INSTANCE.getDragCells();
|
||||
final JPanel pnlContent = FView.SINGLETON_INSTANCE.getPnlContent();
|
||||
final JPanel pnlInsets = FView.SINGLETON_INSTANCE.getPnlInsets();
|
||||
|
||||
Rectangle mainBounds = FView.SINGLETON_INSTANCE.getFrame().getContentPane().getBounds();
|
||||
mainBounds.y = 0; // Play nicely with MenuBar if visible or not.
|
||||
FAbsolutePositioner.SINGLETON_INSTANCE.containerResized(mainBounds);
|
||||
FOverlay.SINGLETON_INSTANCE.getPanel().setBounds(mainBounds);
|
||||
FNetOverlay.SINGLETON_INSTANCE.containerResized(mainBounds);
|
||||
|
||||
pnlInsets.setBounds(mainBounds);
|
||||
pnlInsets.validate();
|
||||
|
||||
final int w = pnlContent.getWidth();
|
||||
final int h = pnlContent.getHeight();
|
||||
|
||||
double roughVal = 0;
|
||||
int smoothVal = 0;
|
||||
|
||||
Set<Component> existingComponents = new HashSet<Component>();
|
||||
for (Component c : pnlContent.getComponents()) {
|
||||
existingComponents.add(c);
|
||||
}
|
||||
|
||||
// This is the core of the pixel-perfect layout. To avoid <20>1 px errors on borders
|
||||
// from rounding individual panels, the intermediate values (exactly accurate, in %)
|
||||
// for width and height are rounded based on comparison to other panels in the
|
||||
// layout. This is to avoid errors such as:
|
||||
// 10% = 9.8px -> 10px -> x 3 = 30px
|
||||
// 30% = 29.4px -> 29px (!)
|
||||
for (final DragCell cellA : cells) {
|
||||
RectangleOfDouble cellSizeA = cellA.getRoughBounds();
|
||||
roughVal = cellSizeA.getX() * w + cellSizeA.getW() * w;
|
||||
|
||||
smoothVal = (int) Math.round(roughVal);
|
||||
for (final DragCell cellB : cells) {
|
||||
RectangleOfDouble cellSizeB = cellB.getRoughBounds();
|
||||
if ((cellSizeB.getX() * w + cellSizeB.getW() * w) == roughVal) {
|
||||
cellB.setSmoothW(smoothVal - (int) Math.round(cellSizeB.getX() * w));
|
||||
}
|
||||
}
|
||||
cellA.setSmoothW(smoothVal - (int) Math.round(cellSizeA.getX() * w));
|
||||
|
||||
roughVal = cellSizeA.getY() * h + cellSizeA.getH() * h;
|
||||
smoothVal = (int) Math.round(roughVal);
|
||||
for (final DragCell cellB : cells) {
|
||||
RectangleOfDouble cellSizeB = cellB.getRoughBounds();
|
||||
if (cellSizeB.getY() * h + cellSizeB.getH() * h == roughVal) {
|
||||
cellB.setSmoothH(smoothVal - (int) Math.round(cellSizeB.getY() * h));
|
||||
}
|
||||
}
|
||||
cellA.setSmoothH(smoothVal - (int) Math.round(cellSizeA.getY() * h));
|
||||
|
||||
// X and Y coordinate can be rounded as usual.
|
||||
cellA.setSmoothX((int) Math.round(cellSizeA.getX() * w));
|
||||
cellA.setSmoothY((int) Math.round(cellSizeA.getY() * h));
|
||||
|
||||
// only add component if not already in container; otherwise the keyboard focus
|
||||
// jumps around to the most recenly added component
|
||||
if (!existingComponents.contains(cellA)) {
|
||||
pnlContent.add(cellA);
|
||||
}
|
||||
}
|
||||
|
||||
// Lock in final bounds and build heads.
|
||||
for (final DragCell t : cells) {
|
||||
t.setSmoothBounds();
|
||||
t.validate();
|
||||
t.refresh();
|
||||
}
|
||||
|
||||
cells.clear();
|
||||
}
|
||||
|
||||
/** @param e   {@link java.awt.event.MouseEvent} */
|
||||
public static void resizeX(final MouseEvent e) {
|
||||
dX = (int) e.getLocationOnScreen().getX() - evtX;
|
||||
evtX = (int) e.getLocationOnScreen().getX();
|
||||
boolean leftLock = false;
|
||||
boolean rightLock = false;
|
||||
|
||||
for (final DragCell t : LEFT_PANELS) {
|
||||
if ((t.getW() + dX) < W_MIN) { leftLock = true; break; }
|
||||
}
|
||||
|
||||
for (final DragCell t : RIGHT_PANELS) {
|
||||
if ((t.getW() - dX) < W_MIN) { rightLock = true; break; }
|
||||
}
|
||||
|
||||
if (dX < 0 && leftLock) { return; }
|
||||
if (dX > 0 && rightLock) { return; }
|
||||
|
||||
for (final DragCell t : LEFT_PANELS) {
|
||||
t.setBounds(t.getX(), t.getY(), t.getW() + dX, t.getH());
|
||||
t.refresh();
|
||||
}
|
||||
|
||||
for (final DragCell t : RIGHT_PANELS) {
|
||||
t.setBounds(t.getX() + dX, t.getY(), t.getW() - dX, t.getH());
|
||||
t.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/** @param e   {@link java.awt.event.MouseEvent} */
|
||||
public static void resizeY(final MouseEvent e) {
|
||||
dY = (int) e.getLocationOnScreen().getY() - evtY;
|
||||
evtY = (int) e.getLocationOnScreen().getY();
|
||||
boolean topLock = false;
|
||||
boolean bottomLock = false;
|
||||
|
||||
for (final DragCell t : TOP_PANELS) {
|
||||
if ((t.getH() + dY) < H_MIN) { topLock = true; break; }
|
||||
}
|
||||
|
||||
for (final DragCell t : BOTTOM_PANELS) {
|
||||
if ((t.getH() - dY) < H_MIN) { bottomLock = true; break; }
|
||||
}
|
||||
|
||||
if (dY < 0 && topLock) { return; }
|
||||
if (dY > 0 && bottomLock) { return; }
|
||||
|
||||
for (final DragCell t : TOP_PANELS) {
|
||||
t.setBounds(t.getX(), t.getY(), t.getW(), t.getH() + dY);
|
||||
t.revalidate();
|
||||
t.repaintSelf();
|
||||
}
|
||||
|
||||
for (final DragCell t : BOTTOM_PANELS) {
|
||||
t.setBounds(t.getX(), t.getY() + dY, t.getW(), t.getH() - dY);
|
||||
t.revalidate();
|
||||
t.repaintSelf();
|
||||
}
|
||||
}
|
||||
|
||||
/** @param e   {@link java.awt.event.MouseEvent} */
|
||||
public static void startResizeX(final MouseEvent e) {
|
||||
evtX = (int) e.getLocationOnScreen().getX();
|
||||
LEFT_PANELS.clear();
|
||||
RIGHT_PANELS.clear();
|
||||
|
||||
final DragCell src = (DragCell) ((JPanel) e.getSource()).getParent();
|
||||
final int srcX2 = src.getAbsX2();
|
||||
|
||||
int limTop = -1;
|
||||
int limBottom = Integer.MAX_VALUE;
|
||||
int tempX = -1;
|
||||
int tempX2 = -1;
|
||||
int tempY = -1;
|
||||
int tempY2 = -1;
|
||||
|
||||
// Add all panels who share a left or right edge with the
|
||||
// same coordinate as the right edge of the source panel.
|
||||
for (final DragCell t : FView.SINGLETON_INSTANCE.getDragCells()) {
|
||||
tempX = t.getAbsX();
|
||||
tempX2 = t.getAbsX2();
|
||||
|
||||
if (srcX2 == tempX) { RIGHT_PANELS.add(t); }
|
||||
else if (srcX2 == tempX2) { LEFT_PANELS.add(t); }
|
||||
}
|
||||
|
||||
// Set limits at panels which are level at intersections.
|
||||
for (final DragCell pnlL : LEFT_PANELS) {
|
||||
if (pnlL.equals(src)) { continue; }
|
||||
tempY = pnlL.getAbsY();
|
||||
tempY2 = pnlL.getAbsY2();
|
||||
|
||||
for (final DragCell pnlR : RIGHT_PANELS) {
|
||||
// Upper edges match? Set a bottom limit.
|
||||
if (tempY >= src.getAbsY2() && tempY == pnlR.getAbsY() && tempY < limBottom) {
|
||||
limBottom = tempY;
|
||||
}
|
||||
// Lower edges match? Set an upper limit.
|
||||
else if (tempY2 <= src.getAbsY() && tempY2 == pnlR.getAbsY2() && tempY2 > limTop) {
|
||||
limTop = tempY2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove non-contiguous panels from left side using limits.
|
||||
final Iterator<DragCell> itrLeft = LEFT_PANELS.iterator();
|
||||
while (itrLeft.hasNext()) {
|
||||
final DragCell t = itrLeft.next();
|
||||
|
||||
if (t.getAbsY() >= limBottom || t.getAbsY2() <= limTop) {
|
||||
itrLeft.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove non-contiguous panels from right side using limits.
|
||||
final Iterator<DragCell> itrRight = RIGHT_PANELS.iterator();
|
||||
while (itrRight.hasNext()) {
|
||||
final DragCell t = itrRight.next();
|
||||
|
||||
if (t.getAbsY() >= limBottom || t.getAbsY2() <= limTop) {
|
||||
itrRight.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param e   {@link java.awt.event.MouseEvent} */
|
||||
public static void startResizeY(final MouseEvent e) {
|
||||
evtY = (int) e.getLocationOnScreen().getY();
|
||||
TOP_PANELS.clear();
|
||||
BOTTOM_PANELS.clear();
|
||||
|
||||
final DragCell src = (DragCell) ((JPanel) e.getSource()).getParent();
|
||||
final int srcY2 = src.getAbsY2();
|
||||
|
||||
int limLeft = -1;
|
||||
int limRight = Integer.MAX_VALUE;
|
||||
int tempX = -1;
|
||||
int tempX2 = -1;
|
||||
int tempY = -1;
|
||||
int tempY2 = -1;
|
||||
|
||||
// Add all panels who share a top or bottom edge with the
|
||||
// same coordinate as the bottom edge of the source panel.
|
||||
for (final DragCell t : FView.SINGLETON_INSTANCE.getDragCells()) {
|
||||
tempY = t.getAbsY();
|
||||
tempY2 = t.getAbsY2();
|
||||
|
||||
if (srcY2 == tempY) { BOTTOM_PANELS.add(t); }
|
||||
else if (srcY2 == tempY2) { TOP_PANELS.add(t); }
|
||||
}
|
||||
|
||||
// Set limits at panels which are level at intersections.
|
||||
for (final DragCell pnlT : TOP_PANELS) {
|
||||
if (pnlT.equals(src)) { continue; }
|
||||
tempX = pnlT.getAbsX();
|
||||
tempX2 = pnlT.getAbsX2();
|
||||
|
||||
for (final DragCell pnlB : BOTTOM_PANELS) {
|
||||
// Right edges match? Set a right limit.
|
||||
if (tempX >= src.getAbsX2() && tempX == pnlB.getAbsX() && tempX < limRight) {
|
||||
limRight = tempX;
|
||||
}
|
||||
// Left edges match? Set an left limit.
|
||||
else if (tempX2 <= src.getAbsX() && tempX2 == pnlB.getAbsX2() && tempX2 > limLeft) {
|
||||
limLeft = tempX2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove non-contiguous panels from left side using limits.
|
||||
final Iterator<DragCell> itrTop = TOP_PANELS.iterator();
|
||||
while (itrTop.hasNext()) {
|
||||
final DragCell t = itrTop.next();
|
||||
if (t.getAbsX() >= limRight || t.getAbsX2() <= limLeft) {
|
||||
itrTop.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove non-contiguous panels from right side using limits.
|
||||
final Iterator<DragCell> itrBottom = BOTTOM_PANELS.iterator();
|
||||
while (itrBottom.hasNext()) {
|
||||
final DragCell t = itrBottom.next();
|
||||
if (t.getAbsX() >= limRight || t.getAbsX2() <= limLeft) {
|
||||
itrBottom.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** */
|
||||
public static void endResize() {
|
||||
SLayoutIO.saveLayout(null);
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.MouseListener} */
|
||||
public static MouseListener getResizeXListener() {
|
||||
return MAD_RESIZE_X;
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.MouseListener} */
|
||||
public static MouseListener getResizeYListener() {
|
||||
return MAD_RESIZE_Y;
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.MouseMotionListener} */
|
||||
public static MouseMotionListener getDragXListener() {
|
||||
return MMA_DRAG_X;
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.MouseMotionListener} */
|
||||
public static MouseMotionListener getDragYListener() {
|
||||
return MMA_DRAG_Y;
|
||||
}
|
||||
|
||||
/** @return {@link java.awt.event.ComponentListener} */
|
||||
public static ComponentListener getWindowResizeListener() {
|
||||
return CAD_RESIZE;
|
||||
}
|
||||
}
|
||||
|
||||
51
src/main/java/forge/gui/menubar/FMenuBar.java
Normal file
51
src/main/java/forge/gui/menubar/FMenuBar.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package forge.gui.menubar;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
|
||||
import forge.gui.menus.ForgeMenu;
|
||||
import forge.gui.menus.HelpMenu;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class FMenuBar extends JMenuBar {
|
||||
|
||||
public FMenuBar(JFrame f) {
|
||||
f.setJMenuBar(this);
|
||||
setPreferredSize(new Dimension(f.getWidth(), 26));
|
||||
setupMenuBar(null);
|
||||
}
|
||||
|
||||
public void setupMenuBar(IMenuProvider provider) {
|
||||
removeAll();
|
||||
add(ForgeMenu.getMenu());
|
||||
addProviderMenus(provider);
|
||||
add(HelpMenu.getMenu());
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void addProviderMenus(IMenuProvider provider) {
|
||||
if (provider != null && provider.getMenus() != null) {
|
||||
for (JMenu m : provider.getMenus()) {
|
||||
m.setBorderPainted(false);
|
||||
add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the MenuBar.
|
||||
* <p>
|
||||
* Note: Disabling a component does not disable its children.
|
||||
*/
|
||||
public void setMenuBarEnabled(boolean isEnabled) {
|
||||
setEnabled(isEnabled);
|
||||
for (Component c : getComponents()) {
|
||||
c.setEnabled(isEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
19
src/main/java/forge/gui/menubar/IMenuProvider.java
Normal file
19
src/main/java/forge/gui/menubar/IMenuProvider.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package forge.gui.menubar;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
|
||||
/**
|
||||
* By implementing this interface a class can add menus to the menu bar
|
||||
* by calling the {@code MenuBarManager.SetupMenuBar()} method.
|
||||
*
|
||||
*/
|
||||
public interface IMenuProvider {
|
||||
|
||||
/**
|
||||
* Returns a list of JMenu objects for display in MenuBar.
|
||||
*/
|
||||
List<JMenu> getMenus();
|
||||
|
||||
}
|
||||
61
src/main/java/forge/gui/menubar/MenuUtil.java
Normal file
61
src/main/java/forge/gui/menubar/MenuUtil.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package forge.gui.menubar;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import forge.Singletons;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.gui.toolbox.FSkin.SkinProp;
|
||||
import forge.gui.toolbox.imaging.ImageUtil;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
|
||||
public final class MenuUtil {
|
||||
private MenuUtil() { }
|
||||
|
||||
private static ForgePreferences prefs = Singletons.getModel().getPreferences();
|
||||
|
||||
// Get appropriate OS standard accelerator key for menu shortcuts.
|
||||
private static final int DEFAULT_MenuShortcutKeyMask =
|
||||
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
|
||||
|
||||
public static boolean isMenuBarVisible() {
|
||||
return !prefs.getPrefBoolean(FPref.UI_HIDE_MENUBAR);
|
||||
}
|
||||
|
||||
public static void openUrlInBrowser(String url) {
|
||||
try {
|
||||
java.awt.Desktop.getDesktop().browse(java.net.URI.create(url));
|
||||
} catch (IOException e) {
|
||||
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static ImageIcon getMenuIcon(SkinProp ico) {
|
||||
return ImageUtil.getMenuIcon(FSkin.getIcon(ico));
|
||||
}
|
||||
|
||||
public static KeyStroke getAcceleratorKey(int key) {
|
||||
return KeyStroke.getKeyStroke(key, DEFAULT_MenuShortcutKeyMask);
|
||||
}
|
||||
|
||||
public static boolean getUserConfirmation(String prompt, String dialogTitle) {
|
||||
Object[] options = {"Yes", "No"};
|
||||
int reply = JOptionPane.showOptionDialog(
|
||||
null,
|
||||
prompt,
|
||||
dialogTitle,
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[1]);
|
||||
return (reply == JOptionPane.YES_OPTION);
|
||||
}
|
||||
|
||||
}
|
||||
70
src/main/java/forge/gui/menus/ForgeMenu.java
Normal file
70
src/main/java/forge/gui/menus/ForgeMenu.java
Normal file
@@ -0,0 +1,70 @@
|
||||
package forge.gui.menus;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import forge.Singletons;
|
||||
import forge.control.RestartUtil;
|
||||
import forge.control.FControl.Screens;
|
||||
import forge.gui.menubar.MenuUtil;
|
||||
|
||||
public final class ForgeMenu {
|
||||
private ForgeMenu() { }
|
||||
|
||||
public static JMenu getMenu() {
|
||||
JMenu menu = new JMenu("Forge");
|
||||
menu.setMnemonic(KeyEvent.VK_F);
|
||||
menu.add(getMenuItem_Restart());
|
||||
menu.add(getMenuItem_Exit());
|
||||
return menu;
|
||||
}
|
||||
|
||||
private static JMenuItem getMenuItem_Exit() {
|
||||
JMenuItem menuItem = new JMenuItem("Exit");
|
||||
menuItem.addActionListener(getExitAction());
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
private static ActionListener getExitAction() {
|
||||
return new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (!isHomeScreenActive()) {
|
||||
String userPrompt = "Please confirm you want to close Forge.\n\n";
|
||||
if (!MenuUtil.getUserConfirmation(userPrompt, "Exit Forge")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static JMenuItem getMenuItem_Restart() {
|
||||
JMenuItem menuItem = new JMenuItem("Restart");
|
||||
menuItem.addActionListener(getRestartAction());
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
private static ActionListener getRestartAction() {
|
||||
return new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (!isHomeScreenActive()) {
|
||||
String userPrompt = "Please confirm you want to restart Forge.\n\n";
|
||||
if (!MenuUtil.getUserConfirmation(userPrompt, "Restart Forge")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
RestartUtil.restartApplication(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isHomeScreenActive() {
|
||||
return Singletons.getControl().getState() == Screens.HOME_SCREEN;
|
||||
}
|
||||
|
||||
}
|
||||
124
src/main/java/forge/gui/menus/HelpMenu.java
Normal file
124
src/main/java/forge/gui/menus/HelpMenu.java
Normal file
@@ -0,0 +1,124 @@
|
||||
package forge.gui.menus;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import forge.gui.menubar.MenuUtil;
|
||||
import forge.util.FileUtil;
|
||||
|
||||
public final class HelpMenu {
|
||||
private HelpMenu() { }
|
||||
|
||||
public static JMenu getMenu() {
|
||||
JMenu menu = new JMenu("Help");
|
||||
menu.setMnemonic(KeyEvent.VK_H);
|
||||
menu.add(getMenu_GettingStarted());
|
||||
menu.add(getMenu_Articles());
|
||||
menu.add(getMenu_Troubleshooting());
|
||||
menu.addSeparator();
|
||||
menu.add(getMenuItem_ReleaseNotes());
|
||||
menu.add(getMenuItem_License());
|
||||
return menu;
|
||||
}
|
||||
|
||||
private static JMenu getMenu_Troubleshooting() {
|
||||
JMenu mnu = new JMenu("Troubleshooting");
|
||||
mnu.add(getMenuItem_UrlLink("How to Provide a Useful Bug Report", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=9621"));
|
||||
mnu.addSeparator();
|
||||
mnu.add(getMenuItem_ReadMeFile());
|
||||
return mnu;
|
||||
}
|
||||
|
||||
private static JMenu getMenu_Articles() {
|
||||
JMenu mnu = new JMenu("Articles");
|
||||
mnu.add(getMenuItem_UrlLink("HOW-TO: Customize your Sealed Deck games with fantasy blocks", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=8164"));
|
||||
mnu.add(getMenuItem_UrlLink("Quest Mode: Guide to Formats, Worlds, and everything", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=9258"));
|
||||
return mnu;
|
||||
}
|
||||
|
||||
private static JMenu getMenu_GettingStarted() {
|
||||
JMenu mnu = new JMenu("Getting Started");
|
||||
mnu.add(getMenuItem_UrlLink("Forge Wiki", "http://www.slightlymagic.net/wiki/Forge"));
|
||||
mnu.add(getMenuItem_UrlLink("What is Forge?", "http://www.slightlymagic.net/forum/viewtopic.php?f=26&t=468"));
|
||||
return mnu;
|
||||
}
|
||||
|
||||
private static JMenuItem getMenuItem_ReadMeFile() {
|
||||
JMenuItem menuItem = new JMenuItem("README.txt");
|
||||
menuItem.addActionListener(getOpenFileAction(getFile("README.txt")));
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
private static JMenuItem getMenuItem_License() {
|
||||
JMenuItem menuItem = new JMenuItem("Forge License");
|
||||
menuItem.addActionListener(getOpenFileAction(getFile("LICENSE.txt")));
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
private static JMenuItem getMenuItem_ReleaseNotes() {
|
||||
JMenuItem menuItem = new JMenuItem("Release Notes");
|
||||
menuItem.addActionListener(getOpenFileAction(getFile("CHANGES.txt")));
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
private static ActionListener getOpenFileAction(final File file) {
|
||||
return new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
openFile(file);
|
||||
} catch (IOException e1) {
|
||||
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected static File getFile(String filename) {
|
||||
// !! Linux is case-sensitive so file name and extension need to match exactly !!
|
||||
File file = null;
|
||||
String filePath = FileUtil.pathCombine(System.getProperty("user.dir"), filename);
|
||||
if (FileUtil.doesFileExist(filePath)) {
|
||||
file = new File(filePath);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://stackoverflow.com/questions/6273221/open-a-text-file-in-the-default-text-editor-via-java
|
||||
*/
|
||||
private static void openFile(File file) throws IOException {
|
||||
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
|
||||
String cmd = "rundll32 url.dll,FileProtocolHandler " + file.getCanonicalPath();
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
}
|
||||
else {
|
||||
Desktop.getDesktop().open(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static JMenuItem getMenuItem_UrlLink(String caption, String url) {
|
||||
JMenuItem menuItem = new JMenuItem(caption);
|
||||
menuItem.addActionListener(getLaunchUrlAction(url));
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
private static ActionListener getLaunchUrlAction(final String url) {
|
||||
return new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
MenuUtil.openUrlInBrowser(url);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
116
src/main/java/forge/gui/toolbox/LayoutHelper.java
Normal file
116
src/main/java/forge/gui/toolbox/LayoutHelper.java
Normal file
@@ -0,0 +1,116 @@
|
||||
package forge.gui.toolbox;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
/**
|
||||
* Helper class for doing custom layout
|
||||
*
|
||||
*/
|
||||
public final class LayoutHelper {
|
||||
private final int parentWidth, parentHeight;
|
||||
private int x, y, lineBottom;
|
||||
|
||||
public LayoutHelper(JComponent parent) {
|
||||
parentWidth = parent.getWidth();
|
||||
parentHeight = parent.getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout component to fill remaining space of parent
|
||||
* @param comp
|
||||
*/
|
||||
public void fill(final JComponent comp) {
|
||||
if (x >= parentWidth) {
|
||||
newLine();
|
||||
}
|
||||
include(comp, parentWidth - x, parentHeight - y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout component to fill remaining space of current line
|
||||
* @param comp
|
||||
* @param height
|
||||
*/
|
||||
public void fillLine(final JComponent comp, int height) {
|
||||
if (x >= parentWidth) {
|
||||
newLine();
|
||||
}
|
||||
include(comp, parentWidth - x, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include component in layout with a percentage width and fixed height
|
||||
* @param comp
|
||||
* @param widthPercent
|
||||
* @param height
|
||||
*/
|
||||
public void include(final JComponent comp, float widthPercent, int height) {
|
||||
include(comp, Math.round(parentWidth * widthPercent), height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include component in layout with a fixed width and percentage height
|
||||
* @param comp
|
||||
* @param width
|
||||
* @param heightPercent
|
||||
*/
|
||||
public void include(final JComponent comp, int width, float heightPercent) {
|
||||
include(comp, width, Math.round(parentHeight * heightPercent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Include component in layout with a percentage width and height
|
||||
* @param comp
|
||||
* @param widthPercent
|
||||
* @param heightPercent
|
||||
*/
|
||||
public void include(final JComponent comp, float widthPercent, float heightPercent) {
|
||||
include(comp, Math.round(parentWidth * widthPercent), Math.round(parentHeight * heightPercent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Include component in layout with a fixed width and height
|
||||
* @param comp
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
public void include(final JComponent comp, int width, int height) {
|
||||
if (width <= 0 || height <= 0) { return; }
|
||||
|
||||
if (x + width > parentWidth) {
|
||||
newLine();
|
||||
if (width > parentWidth) {
|
||||
width = parentWidth;
|
||||
}
|
||||
}
|
||||
if (y + height > parentHeight) {
|
||||
y = parentHeight - height;
|
||||
if (y >= parentHeight) { return; }
|
||||
}
|
||||
comp.setBounds(x, y, width, height);
|
||||
x += width + 3;
|
||||
if (y + height > lineBottom) {
|
||||
lineBottom = y + height;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset current layout helper position
|
||||
* @param dx
|
||||
* @param dy
|
||||
*/
|
||||
public void offset(int dx, int dy) {
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start new line of layout
|
||||
*/
|
||||
public void newLine() {
|
||||
if (lineBottom == y) { return; }
|
||||
x = 0;
|
||||
y = lineBottom + 3;
|
||||
lineBottom = y;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,9 @@
|
||||
package forge.gui.toolbox.imaging;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
/**
|
||||
* Useful general imaging routines.
|
||||
@@ -29,6 +32,12 @@ import java.awt.Dimension;
|
||||
public final class ImageUtil {
|
||||
private ImageUtil() {}
|
||||
|
||||
public static ImageIcon getMenuIcon(ImageIcon sourceIcon) {
|
||||
Image img = sourceIcon.getImage();
|
||||
Image newimg = img.getScaledInstance(16, 16, java.awt.Image.SCALE_SMOOTH);
|
||||
return new ImageIcon(newimg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nearest rotation for a requested rotation.
|
||||
* <p>
|
||||
|
||||
113
src/main/java/forge/gui/toolbox/itemmanager/CardManager.java
Normal file
113
src/main/java/forge/gui/toolbox/itemmanager/CardManager.java
Normal file
@@ -0,0 +1,113 @@
|
||||
package forge.gui.toolbox.itemmanager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JPopupMenu;
|
||||
import forge.Singletons;
|
||||
import forge.game.GameFormat;
|
||||
import forge.gui.GuiUtils;
|
||||
import forge.gui.home.quest.DialogChooseSets;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardCMCFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardColorFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardFormatFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardPowerFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardQuestWorldFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardSearchFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardSetFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardToughnessFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.CardTypeFilter;
|
||||
import forge.gui.toolbox.itemmanager.filters.ItemFilter;
|
||||
import forge.item.PaperCard;
|
||||
import forge.quest.QuestWorld;
|
||||
|
||||
/**
|
||||
* ItemManager for cards
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public final class CardManager extends ItemManager<PaperCard> {
|
||||
|
||||
public CardManager(Map<StatTypes, FLabel> statLabels0, boolean wantUnique0) {
|
||||
super(PaperCard.class, statLabels0, wantUnique0);
|
||||
|
||||
this.addFilter(new CardColorFilter(this));
|
||||
this.addFilter(new CardTypeFilter(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemFilter<PaperCard> createSearchFilter(String text) {
|
||||
return new CardSearchFilter(this, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildFilterMenu(JPopupMenu menu) {
|
||||
JMenu fmt = new JMenu("Format");
|
||||
for (final GameFormat f : Singletons.getModel().getFormats()) {
|
||||
GuiUtils.addMenuItem(fmt, f.getName(), null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
addFilter(new CardFormatFilter(CardManager.this, f));
|
||||
}
|
||||
}, CardFormatFilter.canAddFormat(f, getFilter(CardFormatFilter.class)));
|
||||
}
|
||||
menu.add(fmt);
|
||||
|
||||
GuiUtils.addMenuItem(menu, "Sets...", null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CardSetFilter existingFilter = getFilter(CardSetFilter.class);
|
||||
if (existingFilter != null) {
|
||||
existingFilter.edit();
|
||||
}
|
||||
else {
|
||||
final DialogChooseSets dialog = new DialogChooseSets(null, null, true);
|
||||
dialog.setOkCallback(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<String> sets = dialog.getSelectedSets();
|
||||
if (!sets.isEmpty()) {
|
||||
addFilter(new CardSetFilter(CardManager.this, sets));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JMenu range = new JMenu("Value range");
|
||||
GuiUtils.addMenuItem(range, "CMC", null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
addFilter(new CardCMCFilter(CardManager.this));
|
||||
}
|
||||
}, getFilter(CardCMCFilter.class) == null);
|
||||
GuiUtils.addMenuItem(range, "Power", null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
addFilter(new CardPowerFilter(CardManager.this));
|
||||
}
|
||||
}, getFilter(CardPowerFilter.class) == null);
|
||||
GuiUtils.addMenuItem(range, "Toughness", null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
addFilter(new CardToughnessFilter(CardManager.this));
|
||||
}
|
||||
}, getFilter(CardToughnessFilter.class) == null);
|
||||
menu.add(range);
|
||||
|
||||
JMenu world = new JMenu("Quest world");
|
||||
for (final QuestWorld w : Singletons.getModel().getWorlds()) {
|
||||
GuiUtils.addMenuItem(world, w.getName(), null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
addFilter(new CardQuestWorldFilter(CardManager.this, w));
|
||||
}
|
||||
}, CardQuestWorldFilter.canAddQuestWorld(w, getFilter(CardQuestWorldFilter.class)));
|
||||
}
|
||||
menu.add(world);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package forge.gui.toolbox.itemmanager;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
|
||||
import forge.gui.toolbox.itemmanager.filters.ItemFilter;
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public final class InventoryItemManager extends ItemManager<InventoryItem> {
|
||||
|
||||
public InventoryItemManager(Map<StatTypes, FLabel> statLabels0, boolean wantUnique0) {
|
||||
super(InventoryItem.class, statLabels0, wantUnique0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemFilter<InventoryItem> createSearchFilter(String text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildFilterMenu(JPopupMenu menu) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@
|
||||
*/
|
||||
package forge.gui.toolbox.itemmanager;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -24,8 +27,9 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
@@ -33,8 +37,11 @@ import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.Command;
|
||||
import forge.gui.GuiUtils;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.FTextField;
|
||||
import forge.gui.toolbox.LayoutHelper;
|
||||
import forge.gui.toolbox.ToolTipListener;
|
||||
import forge.gui.toolbox.itemmanager.filters.ItemFilter;
|
||||
import forge.gui.toolbox.itemmanager.table.ItemTable;
|
||||
@@ -43,6 +50,7 @@ import forge.item.InventoryItem;
|
||||
import forge.item.ItemPool;
|
||||
import forge.item.ItemPoolView;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.TypeUtil;
|
||||
|
||||
|
||||
/**
|
||||
@@ -51,21 +59,26 @@ import forge.util.Aggregates;
|
||||
* @param <T>
|
||||
* the generic type
|
||||
*/
|
||||
public final class ItemManager<T extends InventoryItem> extends JPanel {
|
||||
private static final long serialVersionUID = 3164349984277267922L;
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class ItemManager<T extends InventoryItem> extends JPanel {
|
||||
private ItemPool<T> pool;
|
||||
private final ItemManagerModel<T> model;
|
||||
private Predicate<T> filterPredicate = null;
|
||||
private final Map<ItemFilter.FilterTypes, ItemFilter<T>> filters =
|
||||
new HashMap<ItemFilter.FilterTypes, ItemFilter<T>>();
|
||||
private final Map<Class<? extends ItemFilter<T>>, List<ItemFilter<T>>> filters =
|
||||
new HashMap<Class<? extends ItemFilter<T>>, List<ItemFilter<T>>>();
|
||||
private final List<ItemFilter<T>> orderedFilters = new ArrayList<ItemFilter<T>>();
|
||||
private boolean wantUnique = false;
|
||||
private boolean alwaysNonUnique = false;
|
||||
private final Class<T> genericType;
|
||||
private final Map<SItemManagerUtil.StatTypes, FLabel> statLabels;
|
||||
|
||||
private final FLabel btnAddFilter = new FLabel.ButtonBuilder()
|
||||
.text("Add")
|
||||
.tooltip("Click to add filters to the list")
|
||||
.reactOnMouseDown().build();
|
||||
private final FTextField txtSearch = new FTextField.Builder().ghostText("Search").build();
|
||||
private final ItemTable<T> table;
|
||||
private final JScrollPane tableScroller;
|
||||
private final JTextField txtSearch = new FTextField.Builder().ghostText("Search").build();
|
||||
|
||||
/**
|
||||
* ItemManager Constructor.
|
||||
@@ -74,7 +87,7 @@ public final class ItemManager<T extends InventoryItem> extends JPanel {
|
||||
* @param statLabels0 stat labels for this item manager
|
||||
* @param wantUnique0 whether this table should display only one item with the same name
|
||||
*/
|
||||
public ItemManager(final Class<T> genericType0, Map<SItemManagerUtil.StatTypes, FLabel> statLabels0, final boolean wantUnique0) {
|
||||
protected ItemManager(final Class<T> genericType0, Map<SItemManagerUtil.StatTypes, FLabel> statLabels0, final boolean wantUnique0) {
|
||||
this.genericType = genericType0;
|
||||
this.statLabels = statLabels0;
|
||||
this.wantUnique = wantUnique0;
|
||||
@@ -92,25 +105,45 @@ public final class ItemManager<T extends InventoryItem> extends JPanel {
|
||||
//build display
|
||||
this.setOpaque(false);
|
||||
this.setLayout(null);
|
||||
this.add(this.btnAddFilter);
|
||||
this.add(this.txtSearch);
|
||||
this.add(this.tableScroller);
|
||||
|
||||
//setup command for btnAddFilter
|
||||
final Command addFilterCommand = new Command() {
|
||||
@Override
|
||||
public void run() {
|
||||
JPopupMenu menu = new JPopupMenu("FilterMenu");
|
||||
GuiUtils.addMenuItem(menu, "Current text search",
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ItemFilter<T> searchFilter = createSearchFilter(txtSearch.getText());
|
||||
if (searchFilter != null) {
|
||||
addFilter(searchFilter);
|
||||
}
|
||||
}
|
||||
}, !txtSearch.isEmpty());
|
||||
buildFilterMenu(menu);
|
||||
menu.show(btnAddFilter, 0, btnAddFilter.getHeight());
|
||||
}
|
||||
};
|
||||
this.btnAddFilter.setCommand(addFilterCommand);
|
||||
this.btnAddFilter.setRightClickCommand(addFilterCommand); //show menu on right-click too
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doLayout()
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = this.getWidth();
|
||||
int height = this.getHeight();
|
||||
|
||||
//position toolbar components //TODO: Uncomment
|
||||
/*int toolbarHeight = FTextField.HEIGHT + 3;
|
||||
this.txtSearch.setBounds(x, y, width / 2, FTextField.HEIGHT);
|
||||
y += toolbarHeight;*/
|
||||
|
||||
//position current item view
|
||||
this.tableScroller.setBounds(x, y, width, height - y);
|
||||
LayoutHelper helper = new LayoutHelper(this);
|
||||
/*helper.include(this.btnAddFilter, 30, FTextField.HEIGHT);
|
||||
helper.include(this.txtSearch, 0.5f, FTextField.HEIGHT);
|
||||
helper.newLine();
|
||||
for (ItemFilter<T> filter : this.orderedFilters) {
|
||||
helper.fillLine(filter.getPanel(), ItemFilter.PANEL_HEIGHT);
|
||||
}*/
|
||||
helper.fill(this.tableScroller);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -337,16 +370,48 @@ public final class ItemManager<T extends InventoryItem> extends JPanel {
|
||||
return this.statLabels.get(s);
|
||||
}
|
||||
|
||||
protected abstract ItemFilter<T> createSearchFilter(String text);
|
||||
protected abstract void buildFilterMenu(JPopupMenu menu);
|
||||
|
||||
protected <F extends ItemFilter<T>> F getFilter(Class<F> filterClass) {
|
||||
return TypeUtil.safeCast(this.filters.get(filterClass), filterClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addFilter(ItemFilter<T> filter) {
|
||||
this.filters.put(filter.getType(), filter);
|
||||
this.add(filter);
|
||||
final Class<? extends ItemFilter<T>> filterClass = (Class<? extends ItemFilter<T>>) filter.getClass();
|
||||
List<ItemFilter<T>> classFilters = this.filters.get(filterClass);
|
||||
if (classFilters == null) {
|
||||
classFilters = new ArrayList<ItemFilter<T>>();
|
||||
this.filters.put(filterClass, classFilters);
|
||||
}
|
||||
if (classFilters.size() > 0) {
|
||||
//if filter with the same class already exists, try to merge if allowed
|
||||
//NOTE: can always use first filter for these checks since if
|
||||
//merge is supported, only one will ever exist
|
||||
ItemFilter<T> existingFilter = classFilters.get(0);
|
||||
if (existingFilter.merge(filter)) {
|
||||
//if new filter merged with existing filter, just update layout
|
||||
this.revalidate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
classFilters.add(filter);
|
||||
this.add(filter.getPanel());
|
||||
this.revalidate();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void removeFilter(ItemFilter<T> filter) {
|
||||
this.filters.remove(filter.getType());
|
||||
this.remove(filter);
|
||||
this.revalidate();
|
||||
final Class<? extends ItemFilter<T>> filterClass = (Class<? extends ItemFilter<T>>) filter.getClass();
|
||||
final List<ItemFilter<T>> classFilters = this.filters.get(filterClass);
|
||||
if (classFilters != null && classFilters.remove(filter)) {
|
||||
if (classFilters.size() == 0) {
|
||||
this.filters.remove(filterClass);
|
||||
}
|
||||
this.remove(filter.getPanel());
|
||||
this.revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void buildFilterPredicate() {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
@@ -7,7 +9,6 @@ import forge.item.PaperCard;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CardCMCFilter extends ValueRangeFilter<PaperCard> {
|
||||
|
||||
public CardCMCFilter(ItemManager<PaperCard> itemManager0) {
|
||||
@@ -15,12 +16,7 @@ public class CardCMCFilter extends ValueRangeFilter<PaperCard> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTypes getType() {
|
||||
return FilterTypes.CardCMC;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addComponents() {
|
||||
protected void buildPanel(JPanel panel) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CardColorFilter extends ToggleButtonsFilter<PaperCard> {
|
||||
public CardColorFilter(ItemManager<PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTypes getType() {
|
||||
return FilterTypes.CardColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addComponents() {
|
||||
|
||||
protected void buildPanel(JPanel panel) {
|
||||
addToggleButton(panel, StatTypes.WHITE);
|
||||
addToggleButton(panel, StatTypes.BLUE);
|
||||
addToggleButton(panel, StatTypes.BLACK);
|
||||
addToggleButton(panel, StatTypes.RED);
|
||||
addToggleButton(panel, StatTypes.GREEN);
|
||||
addToggleButton(panel, StatTypes.COLORLESS);
|
||||
addToggleButton(panel, StatTypes.MULTICOLOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.game.GameFormat;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
@@ -7,19 +13,33 @@ import forge.item.PaperCard;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CardFormatFilter extends ListLabelFilter<PaperCard> {
|
||||
public CardFormatFilter(ItemManager<PaperCard> itemManager0) {
|
||||
private final Set<GameFormat> formats = new HashSet<GameFormat>();
|
||||
|
||||
public CardFormatFilter(ItemManager<PaperCard> itemManager0, GameFormat format0) {
|
||||
super(itemManager0);
|
||||
this.formats.add(format0);
|
||||
}
|
||||
|
||||
public static boolean canAddFormat(GameFormat format, ItemFilter<PaperCard> existingFilter) {
|
||||
return existingFilter == null || !((CardFormatFilter)existingFilter).formats.contains(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the given filter with this filter if possible
|
||||
* @param filter
|
||||
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean merge(ItemFilter filter) {
|
||||
CardFormatFilter cardFormatFilter = (CardFormatFilter)filter;
|
||||
this.formats.addAll(cardFormatFilter.formats);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTypes getType() {
|
||||
return FilterTypes.CardFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addComponents() {
|
||||
protected void buildPanel(JPanel panel) {
|
||||
|
||||
}
|
||||
|
||||
@@ -27,4 +47,13 @@ public class CardFormatFilter extends ListLabelFilter<PaperCard> {
|
||||
protected void onRemoved() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<String> getList() {
|
||||
Set<String> strings = new HashSet<String>();
|
||||
for (GameFormat f : this.formats) {
|
||||
strings.add(f.getName());
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
@@ -7,19 +9,13 @@ import forge.item.PaperCard;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CardPowerFilter extends ValueRangeFilter<PaperCard> {
|
||||
public CardPowerFilter(ItemManager<PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTypes getType() {
|
||||
return FilterTypes.CardPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addComponents() {
|
||||
protected void buildPanel(JPanel panel) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,49 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.Singletons;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.PaperCard;
|
||||
import forge.quest.QuestWorld;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CardQuestWorldFilter extends ListLabelFilter<PaperCard> {
|
||||
public CardQuestWorldFilter(ItemManager<PaperCard> itemManager0) {
|
||||
private final Set<QuestWorld> questWorlds = new HashSet<QuestWorld>();
|
||||
|
||||
public CardQuestWorldFilter(ItemManager<PaperCard> itemManager0, QuestWorld questWorld0) {
|
||||
super(itemManager0);
|
||||
this.questWorlds.add(questWorld0);
|
||||
}
|
||||
|
||||
public static boolean canAddQuestWorld(QuestWorld questWorld, ItemFilter<PaperCard> existingFilter) {
|
||||
if (questWorld.getFormat() == null && Singletons.getModel().getQuest().getMainFormat() == null) {
|
||||
return false; //must have format
|
||||
}
|
||||
return existingFilter == null || !((CardQuestWorldFilter)existingFilter).questWorlds.contains(questWorld);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the given filter with this filter if possible
|
||||
* @param filter
|
||||
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean merge(ItemFilter filter) {
|
||||
CardQuestWorldFilter cardQuestWorldFilter = (CardQuestWorldFilter)filter;
|
||||
this.questWorlds.addAll(cardQuestWorldFilter.questWorlds);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTypes getType() {
|
||||
return FilterTypes.CardQuestWorld;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addComponents() {
|
||||
protected void buildPanel(JPanel panel) {
|
||||
|
||||
}
|
||||
|
||||
@@ -27,4 +51,13 @@ public class CardQuestWorldFilter extends ListLabelFilter<PaperCard> {
|
||||
protected void onRemoved() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<String> getList() {
|
||||
Set<String> strings = new HashSet<String>();
|
||||
for (QuestWorld w : this.questWorlds) {
|
||||
strings.add(w.getName());
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class CardSearchFilter extends TextSearchFilter<PaperCard> {
|
||||
public CardSearchFilter(ItemManager<PaperCard> itemManager0, String text0) {
|
||||
super(itemManager0, text0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildPanel(JPanel panel) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemoved() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.home.quest.DialogChooseSets;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
@@ -7,19 +14,40 @@ import forge.item.PaperCard;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CardSetFilter extends ListLabelFilter<PaperCard> {
|
||||
public CardSetFilter(ItemManager<PaperCard> itemManager0) {
|
||||
private final Set<String> sets = new HashSet<String>();
|
||||
|
||||
public CardSetFilter(ItemManager<PaperCard> itemManager0, Collection<String> sets) {
|
||||
super(itemManager0);
|
||||
this.sets.addAll(sets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the given filter with this filter if possible
|
||||
* @param filter
|
||||
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean merge(ItemFilter filter) {
|
||||
CardSetFilter cardSetFilter = (CardSetFilter)filter;
|
||||
this.sets.addAll(cardSetFilter.sets);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void edit() {
|
||||
final DialogChooseSets dialog = new DialogChooseSets(this.sets, null, true);
|
||||
dialog.setOkCallback(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
sets.clear();
|
||||
sets.addAll(dialog.getSelectedSets());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTypes getType() {
|
||||
return FilterTypes.CardSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addComponents() {
|
||||
protected void buildPanel(JPanel panel) {
|
||||
|
||||
}
|
||||
|
||||
@@ -27,4 +55,9 @@ public class CardSetFilter extends ListLabelFilter<PaperCard> {
|
||||
protected void onRemoved() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<String> getList() {
|
||||
return this.sets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
@@ -7,19 +9,13 @@ import forge.item.PaperCard;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CardToughnessFilter extends ValueRangeFilter<PaperCard> {
|
||||
public CardToughnessFilter(ItemManager<PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTypes getType() {
|
||||
return FilterTypes.CardToughness;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addComponents() {
|
||||
protected void buildPanel(JPanel panel) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
|
||||
import forge.item.PaperCard;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CardTypeFilter extends ToggleButtonsFilter<PaperCard> {
|
||||
public CardTypeFilter(ItemManager<PaperCard> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterTypes getType() {
|
||||
return FilterTypes.CardType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addComponents() {
|
||||
|
||||
protected void buildPanel(JPanel panel) {
|
||||
addToggleButton(panel, StatTypes.LAND);
|
||||
addToggleButton(panel, StatTypes.ARTIFACT);
|
||||
addToggleButton(panel, StatTypes.CREATURE);
|
||||
addToggleButton(panel, StatTypes.ENCHANTMENT);
|
||||
addToggleButton(panel, StatTypes.PLANESWALKER);
|
||||
addToggleButton(panel, StatTypes.INSTANT);
|
||||
addToggleButton(panel, StatTypes.SORCERY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,40 +11,62 @@ import forge.item.InventoryItem;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class ItemFilter<T extends InventoryItem> extends JPanel {
|
||||
public abstract class ItemFilter<T extends InventoryItem> {
|
||||
private final ItemManager<T> itemManager;
|
||||
private int number;
|
||||
private JPanel panel;
|
||||
|
||||
public enum FilterTypes {
|
||||
CardCMC,
|
||||
CardColor,
|
||||
CardFormat,
|
||||
CardPower,
|
||||
CardQuestWorld,
|
||||
CardSet,
|
||||
CardToughness,
|
||||
CardType
|
||||
}
|
||||
public static int PANEL_HEIGHT = 30;
|
||||
|
||||
protected ItemFilter(ItemManager<T> itemManager0) {
|
||||
this.itemManager = itemManager0;
|
||||
this.setOpaque(false);
|
||||
this.addComponents();
|
||||
this.add(new FLabel.Builder().text("X").fontSize(10).hoverable(true)
|
||||
.tooltip("Remove filter").cmdClick(new Command() {
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return this.number;
|
||||
}
|
||||
|
||||
public void setNumber(int number0) {
|
||||
this.number = number0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public JPanel getPanel() {
|
||||
if (this.panel == null) {
|
||||
this.panel = new JPanel();
|
||||
this.panel.setOpaque(false);
|
||||
|
||||
this.buildPanel(panel);
|
||||
|
||||
//add button to remove filter
|
||||
this.panel.add(new FLabel.Builder()
|
||||
.text("X")
|
||||
.fontSize(10)
|
||||
.hoverable(true)
|
||||
.tooltip("Remove filter")
|
||||
.cmdClick(new Command() {
|
||||
@Override
|
||||
public void run() {
|
||||
itemManager.removeFilter(ItemFilter.this);
|
||||
ItemFilter.this.onRemoved();
|
||||
}
|
||||
}).build(), "top");
|
||||
}
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
protected void applyChange() {
|
||||
itemManager.buildFilterPredicate();
|
||||
this.itemManager.buildFilterPredicate();
|
||||
}
|
||||
|
||||
public abstract FilterTypes getType();
|
||||
protected abstract void addComponents();
|
||||
/**
|
||||
* Merge the given filter with this filter if possible
|
||||
* @param filter
|
||||
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public abstract boolean merge(ItemFilter filter);
|
||||
|
||||
protected abstract void buildPanel(JPanel panel);
|
||||
protected abstract void onRemoved();
|
||||
}
|
||||
|
||||
@@ -7,10 +7,32 @@ import forge.item.InventoryItem;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class ListLabelFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
|
||||
protected ListLabelFilter(ItemManager<T> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
protected abstract Iterable<String> getList();
|
||||
|
||||
public void buildPanel() {
|
||||
StringBuilder label = new StringBuilder();
|
||||
boolean truncated = false;
|
||||
for (String str : getList()) {
|
||||
// don't let the full label get too long
|
||||
if (label.length() < 32) {
|
||||
label.append(" ").append(str).append(";");
|
||||
} else {
|
||||
truncated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// chop off last semicolons
|
||||
label.delete(label.length() - 1, label.length());
|
||||
|
||||
if (truncated) {
|
||||
label.append("...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class TextFieldFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
|
||||
protected TextFieldFilter(ItemManager<T> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.toolbox.FTextField;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public abstract class TextSearchFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
private String text;
|
||||
|
||||
protected TextSearchFilter(ItemManager<T> itemManager0, String text0) {
|
||||
super(itemManager0);
|
||||
this.text = text0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the given filter with this filter if possible
|
||||
* @param filter
|
||||
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean merge(ItemFilter filter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildPanel(JPanel panel) {
|
||||
panel.add(new FTextField.Builder().text(this.text).build());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
package forge.gui.toolbox.itemmanager.filters;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.Command;
|
||||
import forge.gui.toolbox.FLabel;
|
||||
import forge.gui.toolbox.itemmanager.ItemManager;
|
||||
import forge.gui.toolbox.itemmanager.SItemManagerUtil.StatTypes;
|
||||
import forge.item.InventoryItem;
|
||||
|
||||
/**
|
||||
@@ -9,8 +18,60 @@ import forge.item.InventoryItem;
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class ToggleButtonsFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
private static final Dimension BUTTON_SIZE = new Dimension(60, 24);
|
||||
|
||||
private final ArrayList<FLabel> buttons = new ArrayList<FLabel>();
|
||||
|
||||
protected ToggleButtonsFilter(ItemManager<T> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
protected void addToggleButton(JPanel panel, StatTypes s) {
|
||||
addToggleButton(panel, s.toLabelString(), s.img);
|
||||
}
|
||||
|
||||
protected void addToggleButton(JPanel panel, String filterName, ImageIcon icon) {
|
||||
final FLabel button = new FLabel.Builder()
|
||||
.icon(icon).iconScaleAuto(false)
|
||||
.fontSize(11)
|
||||
.tooltip(filterName + " (click to toggle the filter, right-click to show only " + filterName.toLowerCase() + ")")
|
||||
.hoverable().selectable(true).selected(true)
|
||||
.build();
|
||||
|
||||
button.setPreferredSize(BUTTON_SIZE);
|
||||
button.setMinimumSize(BUTTON_SIZE);
|
||||
|
||||
button.setCommand(new Command() {
|
||||
@Override
|
||||
public void run() {
|
||||
applyChange();
|
||||
}
|
||||
});
|
||||
|
||||
//hook so right-clicking a button toggles itself on and toggles off all other buttons
|
||||
button.setRightClickCommand(new Command() {
|
||||
@Override
|
||||
public void run() {
|
||||
for(FLabel btn : buttons) {
|
||||
btn.setSelected(false);
|
||||
}
|
||||
button.setSelected(true);
|
||||
applyChange();
|
||||
}
|
||||
});
|
||||
|
||||
this.buttons.add(button);
|
||||
panel.add(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the given filter with this filter if possible
|
||||
* @param filter
|
||||
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean merge(ItemFilter filter) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,20 @@ import forge.item.InventoryItem;
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class ValueRangeFilter<T extends InventoryItem> extends ItemFilter<T> {
|
||||
|
||||
protected ValueRangeFilter(ItemManager<T> itemManager0) {
|
||||
super(itemManager0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the given filter with this filter if possible
|
||||
* @param filter
|
||||
* @return true if filter merged in or to suppress adding a new filter, false to allow adding new filter
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public boolean merge(ItemFilter filter) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import forge.gui.toolbox.FList;
|
||||
import forge.gui.toolbox.FRadioButton;
|
||||
import forge.gui.toolbox.FScrollPane;
|
||||
import forge.gui.toolbox.JXButtonPanel;
|
||||
import forge.item.PreconDeck;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.quest.QuestController;
|
||||
import forge.quest.QuestEvent;
|
||||
import forge.quest.QuestEventChallenge;
|
||||
@@ -194,8 +194,7 @@ public class FDeckChooser extends JPanel {
|
||||
lst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
final List<String> customNames = new ArrayList<String>();
|
||||
final IStorage<Deck> allDecks = Singletons.getModel().getDecks().getConstructed();
|
||||
for (final Deck d : allDecks) { customNames.add(d.getName()); }
|
||||
addDecksRecursive(Singletons.getModel().getDecks().getConstructed(), customNames, null);
|
||||
|
||||
lst.setListData(customNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
|
||||
lst.setName(DeckgenUtil.DeckTypes.CUSTOM.toString());
|
||||
@@ -210,14 +209,23 @@ public class FDeckChooser extends JPanel {
|
||||
lst.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
private <T extends InventoryItem> void addDecksRecursive(IStorage<T> node, List<String> customNames, String namePrefix ) {
|
||||
String path = namePrefix == null ? "" : namePrefix + " / ";
|
||||
for (final String fn : node.getFolders().getNames() )
|
||||
{
|
||||
IStorage<T> f = node.getFolders().get(fn);
|
||||
addDecksRecursive(f, customNames, path + fn);
|
||||
}
|
||||
for (final T d : node) { customNames.add(path + d.getName()); }
|
||||
}
|
||||
|
||||
/** Handles all control for "custom" radio button click. */
|
||||
private void updatePrecons() {
|
||||
final JList<String> lst = getLstDecks();
|
||||
lst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
final List<String> customNames = new ArrayList<String>();
|
||||
final IStorage<PreconDeck> allDecks = QuestController.getPrecons();
|
||||
for (final PreconDeck d : allDecks) { customNames.add(d.getName()); }
|
||||
addDecksRecursive(QuestController.getPrecons(), customNames, null);
|
||||
|
||||
lst.setListData(customNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
|
||||
lst.setName(DeckgenUtil.DeckTypes.PRECON.toString());
|
||||
|
||||
166
src/main/java/forge/properties/ForgeLookAndFeel.java
Normal file
166
src/main/java/forge/properties/ForgeLookAndFeel.java
Normal file
@@ -0,0 +1,166 @@
|
||||
package forge.properties;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.border.Border;
|
||||
|
||||
import forge.Singletons;
|
||||
import forge.gui.toolbox.FSkin;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
|
||||
/**
|
||||
* Sets the look and feel of the GUI based on the selected Forge theme.
|
||||
*
|
||||
* @see <a href="http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/">UIManager Defaults</a>
|
||||
*/
|
||||
public final class ForgeLookAndFeel {
|
||||
|
||||
private Color FORE_COLOR = FSkin.getColor(FSkin.Colors.CLR_TEXT);
|
||||
private Color BACK_COLOR = FSkin.getColor(FSkin.Colors.CLR_THEME2);
|
||||
private Color HIGHLIGHT_COLOR = BACK_COLOR.brighter();
|
||||
private Border LINE_BORDER = BorderFactory.createLineBorder(FORE_COLOR.darker(), 1);
|
||||
private Border EMPTY_BORDER = BorderFactory.createEmptyBorder(2,2,2,2);
|
||||
|
||||
/**
|
||||
* Sets the look and feel of the GUI based on the selected Forge theme.
|
||||
*/
|
||||
public void setForgeLookAndFeel(JFrame appFrame) {
|
||||
if (isUIManagerEnabled()) {
|
||||
if (setMetalLookAndFeel(appFrame)) {
|
||||
setMenusLookAndFeel();
|
||||
setComboBoxLookAndFeel();
|
||||
setTabbedPaneLookAndFeel();
|
||||
setButtonLookAndFeel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the standard "Java L&F" (also called "Metal") that looks the same on all platforms.
|
||||
* <p>
|
||||
* If not explicitly set then the Mac uses its native L&F which does
|
||||
* not support various settings (eg. combobox background color).
|
||||
*/
|
||||
private boolean setMetalLookAndFeel(JFrame appFrame) {
|
||||
boolean isMetalLafSet = false;
|
||||
try {
|
||||
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
|
||||
SwingUtilities.updateComponentTreeUI(appFrame);
|
||||
isMetalLafSet = true;
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
|
||||
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
}
|
||||
return isMetalLafSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the look and feel for a JMenuBar, JMenu, JMenuItem & variations.
|
||||
*/
|
||||
private void setMenusLookAndFeel() {
|
||||
// JMenuBar
|
||||
Color clrTheme = FSkin.getColor(FSkin.Colors.CLR_THEME);
|
||||
Color backgroundColor = FSkin.stepColor(clrTheme, 0);
|
||||
Color menuBarEdgeColor = FSkin.stepColor(clrTheme, -80);
|
||||
UIManager.put("MenuBar.foreground", FORE_COLOR);
|
||||
UIManager.put("MenuBar.gradient", getColorGradients(backgroundColor.darker(), backgroundColor));
|
||||
UIManager.put("MenuBar.border", BorderFactory.createMatteBorder(0, 0, 1, 0, menuBarEdgeColor));
|
||||
// JMenu
|
||||
UIManager.put("Menu.foreground", FORE_COLOR);
|
||||
UIManager.put("Menu.background", BACK_COLOR);
|
||||
UIManager.put("Menu.borderPainted", false);
|
||||
UIManager.put("Menu.selectionBackground", HIGHLIGHT_COLOR);
|
||||
UIManager.put("Menu.selectionForeground", FORE_COLOR);
|
||||
UIManager.put("Menu.border", EMPTY_BORDER);
|
||||
UIManager.put("Menu.opaque", false);
|
||||
// JPopupMenu
|
||||
UIManager.put("PopupMenu.border", LINE_BORDER);
|
||||
UIManager.put("PopupMenu.background", BACK_COLOR);
|
||||
UIManager.put("PopupMenu.foreground", FORE_COLOR);
|
||||
// JMenuItem
|
||||
UIManager.put("MenuItem.foreground", FORE_COLOR);
|
||||
UIManager.put("MenuItem.background", BACK_COLOR);
|
||||
UIManager.put("MenuItem.border", EMPTY_BORDER);
|
||||
UIManager.put("MenuItem.selectionBackground", HIGHLIGHT_COLOR);
|
||||
UIManager.put("MenuItem.selectionForeground", FORE_COLOR);
|
||||
UIManager.put("MenuItem.acceleratorForeground", FORE_COLOR.darker());
|
||||
UIManager.put("MenuItem.opaque", true);
|
||||
// JSeparator (needs to be opaque!).
|
||||
UIManager.put("Separator.foreground", FORE_COLOR.darker());
|
||||
UIManager.put("Separator.background", BACK_COLOR);
|
||||
// JRadioButtonMenuItem
|
||||
UIManager.put("RadioButtonMenuItem.foreground", FORE_COLOR);
|
||||
UIManager.put("RadioButtonMenuItem.background", BACK_COLOR);
|
||||
UIManager.put("RadioButtonMenuItem.selectionBackground", HIGHLIGHT_COLOR);
|
||||
UIManager.put("RadioButtonMenuItem.selectionForeground", FORE_COLOR);
|
||||
UIManager.put("RadioButtonMenuItem.border", EMPTY_BORDER);
|
||||
UIManager.put("RadioButtonMenuItem.acceleratorForeground", FORE_COLOR.darker());
|
||||
// JCheckboxMenuItem
|
||||
UIManager.put("CheckBoxMenuItem.foreground", FORE_COLOR);
|
||||
UIManager.put("CheckBoxMenuItem.background", BACK_COLOR);
|
||||
UIManager.put("CheckBoxMenuItem.selectionBackground", HIGHLIGHT_COLOR);
|
||||
UIManager.put("CheckBoxMenuItem.selectionForeground", FORE_COLOR);
|
||||
UIManager.put("CheckBoxMenuItem.border", EMPTY_BORDER);
|
||||
UIManager.put("CheckBoxMenuItem.acceleratorForeground", FORE_COLOR.darker());
|
||||
}
|
||||
|
||||
private void setTabbedPaneLookAndFeel() {
|
||||
UIManager.put("TabbedPane.selected", HIGHLIGHT_COLOR);
|
||||
UIManager.put("TabbedPane.contentOpaque", FSkin.getColor(FSkin.Colors.CLR_THEME));
|
||||
UIManager.put("TabbedPane.unselectedBackground", BACK_COLOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the look and feel for a <b>non-editable</b> JComboBox.
|
||||
*/
|
||||
private void setComboBoxLookAndFeel() {
|
||||
UIManager.put("ComboBox.background", BACK_COLOR);
|
||||
UIManager.put("ComboBox.foreground", FORE_COLOR);
|
||||
UIManager.put("ComboBox.selectionBackground", HIGHLIGHT_COLOR);
|
||||
UIManager.put("ComboBox.selectionForeground", FORE_COLOR);
|
||||
UIManager.put("ComboBox.disabledBackground", BACK_COLOR);
|
||||
UIManager.put("ComboBox.disabledForeground", BACK_COLOR.darker());
|
||||
UIManager.put("ComboBox.font", getDefaultFont("ComboBox.font"));
|
||||
UIManager.put("Button.select", HIGHLIGHT_COLOR);
|
||||
}
|
||||
|
||||
private void setButtonLookAndFeel() {
|
||||
UIManager.put("Button.foreground", FORE_COLOR);
|
||||
UIManager.put("Button.background", BACK_COLOR);
|
||||
UIManager.put("Button.select", HIGHLIGHT_COLOR);
|
||||
UIManager.put("Button.focus", FORE_COLOR.darker());
|
||||
UIManager.put("Button.rollover", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether theme styles should be applied to GUI.
|
||||
* <p>
|
||||
* TODO: Currently is using UI_THEMED_COMBOBOX setting but will
|
||||
* eventually want to rename for clarity.
|
||||
*/
|
||||
private boolean isUIManagerEnabled() {
|
||||
return Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_THEMED_COMBOBOX);
|
||||
}
|
||||
|
||||
private Font getDefaultFont(String component) {
|
||||
return FSkin.getFont(UIManager.getFont(component).getSize());
|
||||
}
|
||||
|
||||
private ArrayList<Object> getColorGradients(Color bottom, Color top) {
|
||||
ArrayList<Object> gradients = new ArrayList<>();
|
||||
gradients.add(0.0);
|
||||
gradients.add(0.0);
|
||||
gradients.add(top);
|
||||
gradients.add(bottom);
|
||||
gradients.add(bottom);
|
||||
return gradients;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,6 +61,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
|
||||
UI_CLONE_MODE_SOURCE ("false"), /** */
|
||||
UI_MATCH_IMAGE_VISIBLE ("true"),
|
||||
UI_THEMED_COMBOBOX ("true"),
|
||||
UI_HIDE_MENUBAR ("false"), // Dev setting only - cannot be set from GUI.
|
||||
|
||||
UI_FOR_TOUCHSCREN("false"),
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -41,4 +42,8 @@ public interface IItemReader<T> {
|
||||
* @return the item key
|
||||
*/
|
||||
String getItemKey(T item);
|
||||
|
||||
Iterable<File> getSubFolders();
|
||||
|
||||
IItemReader<T> getReaderForFolder(File subfolder);
|
||||
}
|
||||
|
||||
21
src/main/java/forge/util/TypeUtil.java
Normal file
21
src/main/java/forge/util/TypeUtil.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package forge.util;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public class TypeUtil {
|
||||
|
||||
/**
|
||||
* Cast object to a given type if possible, returning null if not possible
|
||||
* @param obj
|
||||
* @param type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T safeCast(Object obj, Class<T> type) {
|
||||
if (type.isInstance(obj)) {
|
||||
return (T) obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@
|
||||
*/
|
||||
package forge.util.storage;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.util.IItemReader;
|
||||
import forge.util.IItemSerializer;
|
||||
|
||||
//reads and writeDeck Deck objects
|
||||
@@ -32,6 +35,15 @@ import forge.util.IItemSerializer;
|
||||
public class StorageImmediatelySerialized<T> extends StorageBase<T> {
|
||||
|
||||
private final IItemSerializer<T> serializer;
|
||||
private final IStorage<IStorage<T>> subfolders;
|
||||
|
||||
private final Function<IItemReader<T>, IStorage<T>> nestedFactory = new Function<IItemReader<T>, IStorage<T>>() {
|
||||
@Override
|
||||
public IStorage<T> apply(IItemReader<T> io) {
|
||||
return new StorageImmediatelySerialized<T>((IItemSerializer<T>) io, true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for DeckManager.
|
||||
@@ -40,8 +52,14 @@ public class StorageImmediatelySerialized<T> extends StorageBase<T> {
|
||||
* @param io the io
|
||||
*/
|
||||
public StorageImmediatelySerialized(final IItemSerializer<T> io) {
|
||||
this(io, false);
|
||||
}
|
||||
|
||||
|
||||
public StorageImmediatelySerialized(final IItemSerializer<T> io, boolean withSubFolders) {
|
||||
super(io);
|
||||
this.serializer = io;
|
||||
subfolders = withSubFolders ? new StorageNestedFolders<T>(io, nestedFactory) : null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -65,4 +83,12 @@ public class StorageImmediatelySerialized<T> extends StorageBase<T> {
|
||||
public final void delete(final String deckName) {
|
||||
this.serializer.erase(this.map.remove(deckName));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.util.storage.StorageBase#getFolders()
|
||||
*/
|
||||
@Override
|
||||
public IStorage<IStorage<T>> getFolders() {
|
||||
return subfolders == null ? super.getFolders() : subfolders;
|
||||
}
|
||||
}
|
||||
|
||||
36
src/main/java/forge/util/storage/StorageNestedFolders.java
Normal file
36
src/main/java/forge/util/storage/StorageNestedFolders.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package forge.util.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.util.IItemReader;
|
||||
|
||||
|
||||
public class StorageNestedFolders<T> extends StorageBase<IStorage<T>> {
|
||||
|
||||
public StorageNestedFolders(IItemReader<T> io, Function<IItemReader<T>, IStorage<T>> factory) {
|
||||
super(new HashMap<String, IStorage<T>>());
|
||||
for(File sf : io.getSubFolders() )
|
||||
{
|
||||
map.put(sf.getName(), factory.apply(io.getReaderForFolder(sf)));
|
||||
}
|
||||
}
|
||||
|
||||
// need code implementations for folder create/delete operations
|
||||
|
||||
@Override
|
||||
public void add(IStorage<T> deck) {
|
||||
// need folder name here!
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String deckName) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
}
|
||||
27
src/main/java/forge/util/storage/StorageReaderBase.java
Normal file
27
src/main/java/forge/util/storage/StorageReaderBase.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package forge.util.storage;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import forge.util.IItemReader;
|
||||
|
||||
public abstract class StorageReaderBase<T> implements IItemReader<T> {
|
||||
|
||||
protected final Function<? super T, String> keySelector;
|
||||
public StorageReaderBase(final Function<? super T, String> keySelector0) {
|
||||
keySelector = keySelector0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<File> getSubFolders() {
|
||||
// TODO Auto-generated method stub
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemReader<T> getReaderForFolder(File subfolder) {
|
||||
throw new UnsupportedOperationException("This reader is not supposed to have nested folders");
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.IItemReader;
|
||||
|
||||
/**
|
||||
* This class treats every line of a given file as a source for a named object.
|
||||
@@ -36,10 +35,10 @@ import forge.util.IItemReader;
|
||||
* @param <T>
|
||||
* the generic type
|
||||
*/
|
||||
public abstract class StorageReaderFile<T> implements IItemReader<T> {
|
||||
public abstract class StorageReaderFile<T> extends StorageReaderBase<T> {
|
||||
|
||||
private final File file;
|
||||
private final Function<? super T, String> keySelector;
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new storage reader file.
|
||||
@@ -58,8 +57,8 @@ public abstract class StorageReaderFile<T> implements IItemReader<T> {
|
||||
* @param keySelector0 the key selector0
|
||||
*/
|
||||
public StorageReaderFile(final File file0, final Function<? super T, String> keySelector0) {
|
||||
super(keySelector0);
|
||||
this.file = file0;
|
||||
this.keySelector = keySelector0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -121,5 +120,4 @@ public abstract class StorageReaderFile<T> implements IItemReader<T> {
|
||||
public String getItemKey(final T item) {
|
||||
return this.keySelector.apply(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.util.FileUtil;
|
||||
import forge.util.IItemReader;
|
||||
|
||||
/**
|
||||
* This class treats every line of a given file as a source for a named object.
|
||||
@@ -38,18 +37,18 @@ import forge.util.IItemReader;
|
||||
* @param <T>
|
||||
* the generic type
|
||||
*/
|
||||
public abstract class StorageReaderFileSections<T> implements IItemReader<T> {
|
||||
public abstract class StorageReaderFileSections<T> extends StorageReaderBase<T> {
|
||||
|
||||
private final File file;
|
||||
private final Function<? super T, String> keySelector;
|
||||
|
||||
public StorageReaderFileSections(final String pathname, final Function<? super T, String> keySelector0) {
|
||||
this(new File(pathname), keySelector0);
|
||||
}
|
||||
|
||||
public StorageReaderFileSections(final File file0, final Function<? super T, String> keySelector0) {
|
||||
super(keySelector0);
|
||||
this.file = file0;
|
||||
this.keySelector = keySelector0;
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
package forge.util.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
@@ -34,7 +36,6 @@ import com.google.common.base.Function;
|
||||
|
||||
import forge.deck.io.OldDeckFileFormatException;
|
||||
import forge.error.BugReporter;
|
||||
import forge.util.IItemReader;
|
||||
|
||||
/**
|
||||
* This class treats every file in the given folder as a source for a named
|
||||
@@ -43,19 +44,9 @@ import forge.util.IItemReader;
|
||||
*
|
||||
* @param <T> the generic type
|
||||
*/
|
||||
public abstract class StorageReaderFolder<T> implements IItemReader<T> {
|
||||
public abstract class StorageReaderFolder<T> extends StorageReaderBase<T> {
|
||||
|
||||
private final File directory;
|
||||
private final Function<? super T, String> keySelector;
|
||||
|
||||
/**
|
||||
* Gets the directory.
|
||||
*
|
||||
* @return the directory
|
||||
*/
|
||||
protected final File getDirectory() {
|
||||
return this.directory;
|
||||
}
|
||||
protected final File directory;
|
||||
|
||||
/**
|
||||
* Instantiates a new storage reader folder.
|
||||
@@ -63,9 +54,9 @@ public abstract class StorageReaderFolder<T> implements IItemReader<T> {
|
||||
* @param deckDir0 the deck dir0
|
||||
*/
|
||||
public StorageReaderFolder(final File deckDir0, Function<? super T, String> keySelector0) {
|
||||
|
||||
super(keySelector0);
|
||||
|
||||
this.directory = deckDir0;
|
||||
keySelector = keySelector0;
|
||||
|
||||
if (this.directory == null) {
|
||||
throw new IllegalArgumentException("No deck directory specified");
|
||||
@@ -153,5 +144,18 @@ public abstract class StorageReaderFolder<T> implements IItemReader<T> {
|
||||
public String getItemKey(T item) {
|
||||
return keySelector.apply(item);
|
||||
}
|
||||
|
||||
|
||||
// methods handling nested folders are provided. It's up to consumer whether to use these or not.
|
||||
@Override
|
||||
public Iterable<File> getSubFolders() {
|
||||
File[] list = this.directory.listFiles(new FileFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return file.isDirectory() && !file.isHidden();
|
||||
}
|
||||
});
|
||||
return Arrays.asList(list);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user