308 lines
11 KiB
C#
308 lines
11 KiB
C#
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<Tuple<Shape, Shape>, 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<bool, bool, bool> 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<bool, bool, bool>();
|
|
_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<Shape, Shape> 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<Tuple<Tuple<Shape, Shape>, Line>> connections = new List<Tuple<Tuple<Shape, Shape>, Line>>();
|
|
foreach (var inputShape in InputShapes) {
|
|
connections.Add(new Tuple<Tuple<Shape, Shape>, Line>(new Tuple<Shape, Shape>(Shape, inputShape), new Line()));
|
|
}
|
|
foreach (var outputShape in OutputShapes) {
|
|
connections.Add(new Tuple<Tuple<Shape, Shape>, Line>(new Tuple<Shape, Shape>(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<TKey1,TKey2,TValue> : Dictionary<Tuple<TKey1, TKey2>, TValue>, IDictionary<Tuple<TKey1, TKey2>, 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));
|
|
}
|
|
}
|
|
} |