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.Shapes; namespace DigiSim.Logic { public abstract class Gate { private TextBlock _textBlock; private MouseEventHandler _onMove; private MouseEventHandler _onLeave; private MouseButtonEventHandler _onUp; private MouseButtonEventHandler _onDown; private MouseButtonEventHandler _onDelete; protected bool IsAttached; public Point Position { get; private set; } public Size Size { get; protected set; } protected Shape Shape { get; set; } protected Tuple, Line>[] ConnectorLines { get; set; } public Ellipse[] InputShapes { get; protected set; } public Ellipse[] OutputShapes { get; protected set; } public Wire[] ConnectedInputs { get; protected set; } public Wire[] ConnectedOutputs { get; protected set; } protected Dictionary TruthTable { get; set; } protected string Text { get; set; } public bool IsDeleted { get; private set; } protected Gate(double x, double y, double width, double height) { Constructor(x, y, width, height); } protected Gate() {} protected void Constructor(double x, double y, double width, double height) { Position = new Point(x, y); Size = new Size(width, height); _textBlock = new TextBlock() {TextAlignment = TextAlignment.Center, Foreground = Brushes.White, FontSize = 15, IsHitTestVisible = false }; Setup(Window.Board); Shape.Fill = FromHex(Window.FillColor); } private void Setup(Canvas canvas) { TruthTable = new Dictionary(); _onMove = (sender, e) => { if (IsAttached) { Point mouse = Mouse.GetPosition(canvas); Position = new Point( mouse.X - Size.Width / 2, mouse.Y - Size.Height / 2 ); Update(this); } else if (Mouse.LeftButton == MouseButtonState.Pressed && e.OriginalSource.Equals(Shape) && Window.CurrentConnection == null) AttachToMouse(); }; _onUp = (s, e) => IsAttached = false; _onLeave = (s, e) => IsAttached = false; _onDown = (sender, e) => { if (IsAttached) return; if (ConnectedOutputs != null) { for (int i = 0; i < ConnectedOutputs.Length; i++) { if (IsMouseOver(OutputShapes[i])) { Window.StartConnectingGates(this, i); return; } } } if (ConnectedInputs != null) { for (int i = 0; i < ConnectedInputs.Length; i++) { Wire wire = ConnectedInputs[i]; if (IsMouseOver(InputShapes[i])) { wire.Delete(); return; } } } }; _onDelete = (sender, e) => { if (e.OriginalSource.Equals(Shape)) Window.DeleteGate(this); }; canvas.MouseMove += _onMove; canvas.MouseLeave += _onLeave; canvas.MouseUp += _onUp; canvas.MouseDown += _onDown; canvas.MouseRightButtonUp += _onDelete; InternalSetup(canvas); if (InputShapes != null) ConnectedInputs = Enumerable.Repeat(new Wire(), InputShapes.Length).ToArray(); if (OutputShapes != null) ConnectedOutputs = Enumerable.Repeat(new Wire(), OutputShapes.Length).ToArray(); Update(this); } public void AttachToMouse() { IsAttached = true; } protected abstract void InternalSetup(Canvas canvas); public abstract void Update(Gate source); protected void UpdateShapes() { Shape.Width = Size.Width; Shape.Height = Size.Height; Canvas.SetLeft(Shape, Position.X); Canvas.SetTop(Shape, Position.Y); Canvas.SetZIndex(Shape, 10); double outSpace = Size.Height / OutputShapes.Length; for (int i = 0; i < OutputShapes.Length; i++) { Shape shape = OutputShapes[i]; shape.Width = 10; shape.Height = 10; shape.Fill = ConnectedOutputs[i].IsPowered ? FromHex(Window.PoweredColor) : FromHex(Window.FillColor); Canvas.SetLeft(shape, Position.X + Size.Width + 5); Canvas.SetTop(shape, Position.Y + outSpace * i + outSpace / 2 - 5); Canvas.SetZIndex(shape, 2); } double inSpace = Size.Height / InputShapes.Length; for (int i = 0; i < InputShapes.Length; i++) { Shape shape = InputShapes[i]; shape.Width = 10; shape.Height = 10; shape.Fill = ConnectedInputs[i].IsPowered ? FromHex(Window.PoweredColor) : FromHex(Window.FillColor); Canvas.SetLeft(shape, Position.X - 15); Canvas.SetTop(shape, Position.Y + inSpace * i + inSpace / 2 - 5); Canvas.SetZIndex(shape, 2); } foreach (var line in ConnectorLines) { Tuple t = line.Item1; Point p1 = new Point(Canvas.GetLeft(t.Item1) + t.Item1.Width / 2, 0); Point p2 = new Point(Canvas.GetLeft(t.Item2) + t.Item2.Width / 2, Canvas.GetTop(t.Item2) + t.Item2.Height / 2); line.Item2.Stroke = FromHex(Window.FillColor); line.Item2.StrokeThickness = 1; line.Item2.X1 = p1.X; line.Item2.X2 = p2.X; line.Item2.Y1 = p2.Y; line.Item2.Y2 = p2.Y; Canvas.SetZIndex(line.Item2, 1); } _textBlock.Width = Size.Width; _textBlock.Height = Size.Height; Canvas.SetLeft(_textBlock, Position.X); Canvas.SetTop(_textBlock, Position.Y); Canvas.SetZIndex(_textBlock, 11); _textBlock.Text = Text; } protected void UpdateConnectedGates(Gate source) { if (ConnectedOutputs != null) { foreach (var output in ConnectedOutputs) { if (output != null) output.Update(); else continue; if (output.Site2 != null) { if (output.Site2 != source) output.Site2.Update(source); } } } if (ConnectedInputs != null) { foreach (var input in ConnectedInputs) { if (input != null) input.Update(); } } } protected void SetInputs(int count) { InputShapes = new Ellipse[count]; for (int i = 0; i < count; i++) { InputShapes[i] = new Ellipse(); } } protected void SetOutputs(int count) { OutputShapes = new Ellipse[count]; for (int i = 0; i < count; i++) { OutputShapes[i] = new Ellipse(); } } protected void CreateConnections() { List, Line>> connections = new List, Line>>(); foreach (var inputShape in InputShapes) { connections.Add(new Tuple, Line>(new Tuple(Shape, inputShape), new Line())); } foreach (var outputShape in OutputShapes) { connections.Add(new Tuple, Line>(new Tuple(Shape, outputShape), new Line())); } ConnectorLines = connections.ToArray(); } protected void Instantiate() { foreach (var connectorLine in ConnectorLines) { Window.Board.Children.Add(connectorLine.Item2); } foreach (var inputShape in InputShapes) { Window.Board.Children.Add(inputShape); } foreach (var outputShape in OutputShapes) { Window.Board.Children.Add(outputShape); } Window.Board.Children.Add(Shape); Window.Board.Children.Add(_textBlock); } public void Delete() { IsDeleted = true; Window.Board.MouseMove -= _onMove; Window.Board.MouseLeave -= _onLeave; Window.Board.MouseUp -= _onUp; Window.Board.MouseDown -= _onDown; Window.Board.MouseRightButtonUp -= _onDelete; Window.Board.Children.Remove(Shape); Window.Board.Children.Remove(_textBlock); foreach (var connectorLine in ConnectorLines) { Window.Board.Children.Remove(connectorLine.Item2); } foreach (var inputShape in InputShapes) { Window.Board.Children.Remove(inputShape); } foreach (var outputShape in OutputShapes) { Window.Board.Children.Remove(outputShape); } foreach (var connectedInput in ConnectedInputs) { connectedInput.Delete(); } ConnectedInputs = null; foreach (var connectedOutput in ConnectedOutputs) { connectedOutput.Delete(); } ConnectedOutputs = null; } // STATIC UTILITIY METHODS private static Rect GetBounds(Shape shape) { return shape.TransformToVisual(Window.Board) .TransformBounds(new Rect(0, 0, shape.ActualWidth, shape.ActualHeight)); } public static bool CheckBoundingIntersection(Shape shape1, Shape shape2) { return GetBounds(shape1).IntersectsWith(GetBounds(shape2)); } public static bool IsMouseOver(Shape shape) { return GetBounds(shape).Contains(Mouse.GetPosition(Window.Board)); } public static SolidColorBrush FromHex(String hex) { return (SolidColorBrush)new BrushConverter().ConvertFromString(hex); } } public class Dictionary : Dictionary, TValue>, IDictionary, TValue> { public TValue this[TKey1 key1, TKey2 key2] { get { return base[Tuple.Create(key1, key2)]; } set { base[Tuple.Create(key1, key2)] = value; } } public void Add(TKey1 key1, TKey2 key2, TValue value) { base.Add(Tuple.Create(key1, key2), value); } public bool ContainsKey(TKey1 key1, TKey2 key2) { return base.ContainsKey(Tuple.Create(key1, key2)); } } }