using Dominion.NET_WPF.Enums;
using Dominion.NET_WPF.ViewModel;
using DominionBase.Cards;
using DominionBase.Enums;
using DominionBase.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
namespace Dominion.NET_WPF.Controls
{
///
/// Interaction logic for CardStackControl.xaml
///
public partial class CardStackControl : UserControl, IDisposable
{
public static readonly RoutedEvent CardStackControlClickEvent = EventManager.RegisterRoutedEvent(
"CardStackControlClick",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(CardStackControl));
public event RoutedEventHandler CardStackControlClick
{
add { AddHandler(CardStackControlClickEvent, value); }
remove { RemoveHandler(CardStackControlClickEvent, value); }
}
public static readonly DependencyProperty AnchorPointProperty = DependencyProperty.Register(
"AnchorPoint",
typeof(Point),
typeof(CardStackControl),
new FrameworkPropertyMetadata(new Point(0, 0), FrameworkPropertyMetadataOptions.AffectsMeasure));
public Point AnchorPoint
{
get { return (Point)GetValue(AnchorPointProperty); }
set { SetValue(AnchorPointProperty, value); }
}
public void InitAnchor()
{
LayoutUpdated -= CardStackControl_LayoutUpdated;
LayoutUpdated += CardStackControl_LayoutUpdated;
}
private void CardStackControl_LayoutUpdated(object sender, EventArgs e)
{
var size = RenderSize;
var ofs = new Point(size.Width / 2, size.Height / 2);
if (Window.GetWindow(this) is WMain window)
AnchorPoint = TransformToVisual(window).Transform(ofs);
}
private IEnumerable _cardCollection = new List();
private DominionBase.TokenCollection _tokens = new DominionBase.TokenCollection();
private CardLabelCollection _cardLabels = new CardLabelCollection();
//private DominionBase.Cards.CardCollection _CardCollection = new DominionBase.Cards.CardCollection();
private int _glowSize;
private DominionBase.IPlayer _player;
private DominionBase.Players.PhaseEnum _playerPhase = DominionBase.Players.PhaseEnum.Action;
private DominionBase.Players.PlayerMode _playerMode = DominionBase.Players.PlayerMode.Waiting;
private CardSize _cardSize = CardSize.Medium;
private HighlightMode _highlight;
public bool IsCardsVisible { get; set; }
public Card ClickedCard { get; private set; }
public DominionBase.IPlayer Player
{
private get { return _player; }
set
{
_player = value;
UpdateCardDisplay();
}
}
public DominionBase.Players.PhaseEnum Phase
{
private get { return _playerPhase; }
set
{
_playerPhase = value;
UpdateGlowEffectAll();
}
}
public DominionBase.Players.PlayerMode PlayerMode
{
private get { return _playerMode; }
set
{
_playerMode = value;
UpdateGlowEffectAll();
}
}
public bool IsClickable
{
get
{
return bImages.IsEnabled;
}
set
{
if (value)
{
bImages.IsEnabled = bName.IsEnabled = true;
bImages.Visibility = bName.Visibility = Visibility.Visible;
Panel.SetZIndex(bImages, 1);
Panel.SetZIndex(bName, 1);
}
else
{
bImages.IsEnabled = bName.IsEnabled = false;
bImages.Visibility = bName.Visibility = Visibility.Collapsed;
Panel.SetZIndex(bImages, -1);
Panel.SetZIndex(bName, -1);
}
}
}
public CardSize CardSize
{
get { return _cardSize; }
set
{
_cardSize = value;
switch (_cardSize)
{
case CardSize.Text:
case CardSize.SmallText:
gImages.Visibility = Visibility.Collapsed;
_glowSize = 0;
break;
case CardSize.Small:
gImages.Visibility = Visibility.Visible;
_glowSize = 10;
break;
case CardSize.Medium:
gImages.Visibility = Visibility.Visible;
_glowSize = 20;
break;
}
dpMain.Margin = new Thickness(_glowSize / 4d, 0, _glowSize / 4d, 0);
gImages.Margin = new Thickness(_glowSize / 2d);
UpdateCardDisplay();
}
}
public HighlightMode Highlight
{
get { return _highlight; }
set
{
_highlight = value;
DropShadowEffect dse = null;
switch (_highlight)
{
case HighlightMode.None:
bMain.BorderBrush = Brushes.Transparent;
break;
case HighlightMode.Primary:
dse = Caching.DropShadowRepository.GetDSE(_glowSize * 4, Colors.Crimson, 1.0, false);
bMain.BorderBrush = Brushes.Crimson;
break;
case HighlightMode.Secondary:
dse = Caching.DropShadowRepository.GetDSE(_glowSize * 4, Colors.Crimson, 1.0, false);
bMain.BorderBrush = Brushes.Goldenrod;
break;
}
if (IsCardsVisible && PileVisibility == DominionBase.Piles.Visibility.All)
{
var image = gImages.Children.OfType().LastOrDefault();
if (image != null)
image.Effect = dse;
lName.Effect = dse;
}
}
}
public void CountVPs(IEnumerable cards)
{
dpVPCount.Visibility = Visibility.Visible;
if (_cardCollection.Any())
{
var count = 0;
if (_cardCollection.ElementAt(0) is DominionBase.IPoints cp)
count = cp.ComputeVictoryPoints(Player, cards.OfType());
lVPCount.Content = count;
lVP.Content = StringUtility.Plural("VP", count, false);
}
else
lVPCount.Content = string.Empty;
}
public void HideVPs()
{
lVPCount.Content = string.Empty;
dpVPCount.Visibility = Visibility.Collapsed;
}
public CardStackControl()
{
DataContext = new CardStackControlViewModel();
InitializeComponent();
IsClickable = false;
if (WMain.Settings != null)
{
WMain.Settings.SettingsChanged += Settings_SettingsChanged;
Settings_SettingsChanged(WMain.Settings, null);
}
}
public void Dispose()
{
if (WMain.Settings != null)
{
WMain.Settings.SettingsChanged -= Settings_SettingsChanged;
}
}
protected virtual void Settings_SettingsChanged(object sender, SettingsChangedEventArgs e)
{
if (sender is Settings settings)
{
if (settings.ToolTipShowDuration == ToolTipShowDuration.Off)
ToolTipService.SetIsEnabled(this, false);
else
{
ToolTipService.SetIsEnabled(this, true);
ToolTipService.SetShowDuration(this, (int)settings.ToolTipShowDuration);
}
}
}
public IEnumerable CardCollection
{
get { return _cardCollection; }
set
{
_cardCollection = value;
UpdateCardDisplay();
}
}
public DominionBase.TokenCollection Tokens
{
get { return _tokens; }
set
{
_tokens = value;
UpdateCardDisplay();
}
}
public CardLabelCollection CardLabels
{
get { return _cardLabels; }
set
{
_cardLabels = value;
UpdateCardDisplay();
}
}
public string Title
{
get { return tbName.Text; }
private set
{
tbName.Text = value;
tbName.ToolTip = value;
lName.Visibility = string.IsNullOrEmpty(value) ? Visibility.Hidden : Visibility.Visible;
}
}
public DominionBase.Piles.Visibility PileVisibility { get; set; }
public bool ExactCount { get; set; }
public bool CascadePile { get; set; } = true;
private void UpdateCardDisplay()
{
spExtraStuff.Visibility = Visibility.Visible;
spExtraStuff.Children.Clear();
Tokens.ForEach(t => spExtraStuff.Children.Add(new ucTokenIcon { Token = t, Size = CardSize.Text }));
if (spExtraStuff.Children.Count == 0)
spExtraStuff.Visibility = Visibility.Collapsed;
var stackOffset = new Size();
switch (CardSize)
{
case CardSize.Text:
break;
case CardSize.SmallText:
dpName.Height = 16;
lCount.Margin = new Thickness(0);
lName.Padding = new Thickness(0);
lName.Margin = new Thickness(0, 0, 2, 0);
Padding = new Thickness(0);
break;
case CardSize.Small:
stackOffset = new Size(12, 6);
break;
case CardSize.Medium:
stackOffset = new Size(24, 10);
break;
}
lCount.Visibility = Visibility.Collapsed;
if (_cardCollection.Count() > 4 || (gImages.Visibility == Visibility.Collapsed && _cardCollection.Count() > 1))
{
lCount.Visibility = Visibility.Visible;
if (IsCardsVisible && PileVisibility == DominionBase.Piles.Visibility.All)
lCount.Content = $"{_cardCollection.Count()}x";
stackOffset.Width = 0.75 * stackOffset.Width;
}
if (_cardCollection.Count() > 6 && stackOffset.Height > 0)
{
var verticalScale = 56f / (_cardCollection.Count() - 1);
stackOffset = new Size((int)(0.625 * stackOffset.Width * verticalScale / stackOffset.Height), (int)verticalScale);
}
if (PileVisibility != DominionBase.Piles.Visibility.All)
stackOffset.Width = 0;
var startIndex = (CascadePile || !_cardCollection.Any()) ? 0 : (_cardCollection.Count() - 1);
for (var index = startIndex; index < _cardCollection.Count(); index++)
{
var card = _cardCollection.ElementAt(index);
if (card == null)
continue;
if ((IsCardsVisible && PileVisibility == DominionBase.Piles.Visibility.All || PileVisibility == DominionBase.Piles.Visibility.Top) &&
!(card is DominionBase.Cards.Universal.Blank))
{
var category = card.Category;
if (card is Card c)
category = c.PhysicalCategory;
lName.Background = Caching.BrushRepository.GetBackgroundBrush(category);
lName.Foreground = Caching.BrushRepository.GetForegroundBrush(category);
// Flip the foreground/background for Events
if (category.HasFlag(Categories.Event))
{
var t = lName.Foreground;
lName.Foreground = lName.Background;
lName.Background = t;
}
if (category.HasFlag(Categories.Reaction))
tbName.Effect = Caching.DropShadowRepository.GetDSE(8, Colors.White, 1d);
}
if (gImages.Visibility == Visibility.Visible)
{
var newImage = new Image();
var repo = Caching.ImageRepository.Acquire();
switch (CardSize)
{
case CardSize.Small:
if (IsCardsVisible &&
(PileVisibility == DominionBase.Piles.Visibility.All || PileVisibility == DominionBase.Piles.Visibility.Top) &&
card.Type != DominionBase.Cards.Universal.TypeClass.Dummy &&
card.Type != DominionBase.Cards.Universal.TypeClass.DummyRed &&
card.Type != DominionBase.Cards.Universal.TypeClass.Blank)
newImage.Source = repo.GetBitmapImage(card.ImageName, "small");
else
{
switch (card.CardBack)
{
case CardBack.Standard:
newImage.Source = repo.GetBitmapImage("back", "small");
break;
case CardBack.Red:
newImage.Source = repo.GetBitmapImage("back_red", "small");
break;
case CardBack.Blank:
newImage.Source = repo.GetBitmapImage("blank", "small");
break;
}
}
break;
case CardSize.Medium:
if (IsCardsVisible &&
(PileVisibility == DominionBase.Piles.Visibility.All || PileVisibility == DominionBase.Piles.Visibility.Top) &&
card.Type != DominionBase.Cards.Universal.TypeClass.Dummy &&
card.Type != DominionBase.Cards.Universal.TypeClass.DummyRed &&
card.Type != DominionBase.Cards.Universal.TypeClass.Blank)
newImage.Source = repo.GetBitmapImage(card.ImageName, "medium");
else
{
switch (card.CardBack)
{
case CardBack.Standard:
newImage.Source = repo.GetBitmapImage("back", "medium");
break;
case CardBack.Red:
newImage.Source = repo.GetBitmapImage("back_red", "medium");
break;
case CardBack.Blank:
newImage.Source = repo.GetBitmapImage("blank", "medium");
break;
}
}
break;
}
Caching.ImageRepository.Release();
if (newImage.Source != null)
{
newImage.Width = newImage.Source.Width;
newImage.Height = newImage.Source.Height;
}
newImage.HorizontalAlignment = HorizontalAlignment.Left;
newImage.VerticalAlignment = VerticalAlignment.Top;
newImage.Margin = new Thickness((index - startIndex) * stackOffset.Width, (index - startIndex) * stackOffset.Height, 0, 0);
newImage.Tag = card;
gImages.Children.Insert(gImages.Children.Count - 1, newImage);
}
}
Title = string.Empty;
if (_cardCollection.Any() && IsCardsVisible)
{
if (PileVisibility == DominionBase.Piles.Visibility.All || PileVisibility == DominionBase.Piles.Visibility.Top)
{
var card = _cardCollection.Last();
if (card is DominionBase.Cards.Universal.Blank)
Title = "Empty";
else if (card != null)
{
if (card.Facing == Facing.FaceDown)
{
lStatus.Content = "(Face Down)";
lStatus.Visibility = Visibility.Visible;
}
else
lStatus.Visibility = Visibility.Collapsed;
lLabels.Content = string.Join(", ", CardLabels.Select(cl => cl.Name));
lLabels.Visibility = CardLabels.Any() ? Visibility.Visible : Visibility.Collapsed;
Title = card.Name;
if (_cardCollection.First() is DominionBase.Cards.Universal.Dummy || _cardCollection.First() is DominionBase.Cards.Universal.DummyRed)
ttcCard.Card = card;
else
ttcCard.CardList = _cardCollection.Reverse();
}
}
}
UpdateGlowEffectAll();
if (!IsCardsVisible || PileVisibility == DominionBase.Piles.Visibility.None)
{
var count = _cardCollection.Count();
if (count == 1 && _cardCollection.ElementAt(0) is DominionBase.Cards.Universal.Blank)
Title = "Empty";
else if (ExactCount || count <= 1)
Title = StringUtility.Plural("Card", count);
}
}
private void UpdateGlowEffectAll()
{
if (IsCardsVisible && PileVisibility == DominionBase.Piles.Visibility.All)
{
var anyGlowAdded = false;
foreach (var image in gImages.Children.OfType())
{
var addGlow = image.Tag is Card card
&& PlayerMode == DominionBase.Players.PlayerMode.Normal
&& (
(Phase == DominionBase.Players.PhaseEnum.Action
&& ((card.Category.HasFlag(Categories.Action) && Player.Actions > 0)
|| card.Category.HasFlag(Categories.Treasure))
)
|| ((Phase == DominionBase.Players.PhaseEnum.ActionTreasure || Phase == DominionBase.Players.PhaseEnum.BuyTreasure)
&& card.Category.HasFlag(Categories.Treasure))
|| (Phase == DominionBase.Players.PhaseEnum.Night
&& card.Category.HasFlag(Categories.Night))
);
UpdateGlowEffect(image, addGlow, _glowSize, Colors.Black, Colors.MediumBlue);
anyGlowAdded |= addGlow;
}
UpdateGlowEffect(lName, anyGlowAdded, _glowSize, Colors.Black, Colors.MediumBlue);
}
}
private void UpdateGlowEffect(UIElement element, bool addGlow, int glowSize, Color color1, Color color2)
{
if (addGlow)
{
var dse = Caching.DropShadowRepository.GetDSE(glowSize, color1, 0.85, false);
var ca = new ColorAnimation
{
From = color1,
To = color2,
Duration = TimeSpan.FromSeconds(1),
AutoReverse = true,
RepeatBehavior = RepeatBehavior.Forever,
AccelerationRatio = 0.4,
};
var da = new DoubleAnimation
{
From = glowSize * 2 / 3,
To = glowSize * 1.5,
Duration = TimeSpan.FromSeconds(1),
AutoReverse = true,
RepeatBehavior = RepeatBehavior.Forever,
AccelerationRatio = 0.4,
};
dse.BeginAnimation(DropShadowEffect.ColorProperty, ca);
dse.BeginAnimation(DropShadowEffect.BlurRadiusProperty, da);
element.Effect = dse;
IsClickable = true;
bImages.Cursor = bName.Cursor = Cursors.Hand;
}
else
{
element.Effect = null;
IsClickable = false;
bImages.Cursor = bName.Cursor = null;
}
}
internal Control FindGameObject(DominionBase.IGameObject gameObject)
{
return CardCollection.Any(card => card.UniqueId == gameObject.UniqueId) ? this : null;
}
private void B_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button != null) button.IsEnabled = false;
ClickedCard = (gImages.Children[gImages.Children.Count - 2] as Image)?.Tag as Card;
RaiseEvent(new RoutedEventArgs(CardStackControlClickEvent));
ClickedCard = null;
if (button != null) button.IsEnabled = true;
}
private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
{
if (WMain.Settings == null || ((ToolTip as ToolTip)?.Content as ToolTipIDisplayable)?.Card == null
|| (((ToolTip)ToolTip).Content as ToolTipIDisplayable)?.Card.Type == DominionBase.Cards.Universal.TypeClass.Dummy
|| (((ToolTip)ToolTip).Content as ToolTipIDisplayable)?.Card.Type == DominionBase.Cards.Universal.TypeClass.DummyRed
|| (((ToolTip)ToolTip).Content as ToolTipIDisplayable)?.Card.Type == DominionBase.Cards.Universal.TypeClass.Blank)
return;
if (WMain.Settings.ShowToolTipOnRightClick && e.ChangedButton == MouseButton.Right && e.ButtonState == MouseButtonState.Pressed)
{
CaptureMouse();
((ToolTip)ToolTip).IsOpen = true;
e.Handled = true;
}
}
private void UserControl_MouseUp(object sender, MouseButtonEventArgs e)
{
if (WMain.Settings == null || ToolTip == null)
return;
if (WMain.Settings.ShowToolTipOnRightClick && e.ChangedButton == MouseButton.Right && e.ButtonState == MouseButtonState.Released)
{
ReleaseMouseCapture();
if (ToolTip is ToolTip toolTip) toolTip.IsOpen = false;
e.Handled = true;
}
}
private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (ToolTip is ToolTip toolTip && toolTip.IsOpen)
toolTip.IsOpen = false;
}
private void UserControl_MouseEnter(object sender, MouseEventArgs e)
{
CardHover.RaiseCardHoverEvent(this, new CardHoverEventArgs(ttcCard.Card?.DisplayCard));
}
private void UserControl_StylusEnter(object sender, StylusEventArgs e)
{
CardHover.RaiseCardHoverEvent(this, new CardHoverEventArgs(ttcCard.Card?.DisplayCard));
}
private void UserControl_TouchEnter(object sender, TouchEventArgs e)
{
CardHover.RaiseCardHoverEvent(this, new CardHoverEventArgs(ttcCard.Card?.DisplayCard));
}
}
}