Skip to content

Commit 6a9b24f

Browse files
committed
Add button components.
1 parent e03c9d9 commit 6a9b24f

File tree

15 files changed

+319
-96
lines changed

15 files changed

+319
-96
lines changed

LogicSandbox/Forms/FormMain.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Maxstupo.LogicSandbox.Logic;
1111
using Maxstupo.LogicSandbox.Logic.Components;
1212
using Maxstupo.LogicSandbox.Properties;
13+
using Maxstupo.LogicSandbox.Shapes;
1314
using Maxstupo.LogicSandbox.Utility.Interaction;
1415

1516
public partial class FormMain : Form {
@@ -64,6 +65,9 @@ private void FormMain_Load(object sender, EventArgs e) {
6465
// TEMP: Allow auto discovery of components.
6566
// TEMP: move to more suitable location.
6667
AddComponentToLibrary(new Power("", 0, 0));
68+
AddComponentToLibrary(new Toggle("", 0, 0));
69+
AddComponentToLibrary(new PushOn("", 0, 0));
70+
AddComponentToLibrary(new PushOff("", 0, 0));
6771
AddComponentToLibrary(new NotGate("", 0, 0));
6872
AddComponentToLibrary(new OrGate("", 0, 0));
6973
AddComponentToLibrary(new PortIn("", 0, 0));
@@ -121,16 +125,22 @@ private void Canvas_Paint(object sender, PaintEventArgs e) {
121125
selector.Draw(g);
122126
}
123127

128+
private Shape componentOver;
129+
124130
private void Canvas_MouseDown(object sender, MouseEventArgs e) {
125131

126132
if (e.Button == MouseButtons.Left) {
127133

134+
componentOver = circuit.GetComponentOver();
135+
if (componentOver != null)
136+
componentOver.UpdateMouseState(true);
137+
128138
selectedPin = circuit.GetPinOver();
129139
if (selectedPin == null) {
130140

131141
bool additiveMode = ModifierKeys.HasFlag(AdditiveKey); // Previous selection not cleared.
132142

133-
if (!selector.Start(canvas.MouseWorldX, canvas.MouseWorldY, additiveMode, (x, y) => circuit.GetComponentOver())) {
143+
if (!selector.Start(canvas.MouseWorldX, canvas.MouseWorldY, additiveMode, (x, y) => circuit.GetComponentMouseOverOrDescentants())) {
134144

135145
transformer.Clear();
136146
transformer.AddItems(selector.SelectedItems);
@@ -164,6 +174,10 @@ private void Canvas_MouseMove(object sender, MouseEventArgs e) {
164174
private void Canvas_MouseUp(object sender, MouseEventArgs e) {
165175
if (e.Button == MouseButtons.Left) {
166176

177+
if (componentOver != null)
178+
componentOver.UpdateMouseState(false);
179+
180+
167181
bool additiveMode = ModifierKeys.HasFlag(AdditiveKey); // Previous selection not cleared.
168182
bool inclusiveMode = ModifierKeys.HasFlag(InclusiveKey); // Item must be inside of selection bounds.
169183

LogicSandbox/Logic/Circuit.cs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
namespace Maxstupo.LogicSandbox.Logic {
2-
2+
33
using System;
44
using System.Collections.Generic;
55
using System.Drawing;
66
using System.Linq;
77
using Maxstupo.LogicSandbox.Logic.Components;
8+
using Maxstupo.LogicSandbox.Shapes;
89

910
/// <summary>
1011
/// Represents a collection of components that are connected via wires.
@@ -53,8 +54,8 @@ public void RemoveComponent(string id) {
5354
if (lookup.TryGetValue(id, out DigitalComponent component)) {
5455
Console.WriteLine($"Removing component with ID \"{id}\"");
5556

56-
foreach(Pin pin in component.Pins)
57-
RemoveConnectedWires(pin);
57+
foreach (Pin pin in component.Pins)
58+
RemoveConnectedWires(pin);
5859

5960
Components.RemoveAll(x => x.Id == id);
6061
} else {
@@ -124,8 +125,8 @@ public void Draw(Graphics g) {
124125
public bool Update(float mx, float my) {
125126
bool needsRefresh = false;
126127

127-
foreach (DigitalComponent component in Components)
128-
needsRefresh |= component.Update(mx, my);
128+
foreach (Shape component in Components)
129+
needsRefresh |= component.UpdateState(mx, my);
129130

130131
return needsRefresh;
131132
}
@@ -153,21 +154,34 @@ public bool Step(float stepRate) {
153154
/// </summary>
154155
public Pin GetPinOver() {
155156
foreach (DigitalComponent component in Components) {
156-
foreach (Pin pin in component) {
157-
if (pin.IsMouseOver)
157+
foreach (Shape shape in component) {
158+
if (shape.IsMouseOver && shape is Pin pin)
158159
return pin;
159160
}
160161
}
161162
return null;
162163
}
163164

164165
/// <summary>
165-
/// Returns the first component the mouse is over.
166+
/// Returns the first component that has the mouse over it or one of its child elements.
166167
/// </summary>
167-
public DigitalComponent GetComponentOver() {
168-
return Components.FirstOrDefault(x => x.IsMouseOver);
168+
public DigitalComponent GetComponentMouseOverOrDescentants() {
169+
foreach (DigitalComponent component in Components) {
170+
if (component.IsMouseOverOrDescentants())
171+
return component;
172+
}
173+
return null;
169174
}
170175

176+
public Shape GetComponentOver() {
177+
foreach (DigitalComponent dc in Components) {
178+
Shape shape = dc.GetMouseOverTopMost();
179+
if (shape != null) return shape;
180+
}
181+
return null;
182+
}
183+
184+
171185

172186
/// <summary>
173187
/// Removes all wires connected to the provided pin.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
namespace Maxstupo.LogicSandbox.Logic.Components {
2+
using System.Drawing;
3+
using System.Linq;
4+
using Maxstupo.LogicSandbox.Shapes;
5+
6+
public abstract class ButtonComponent : DigitalComponent {
7+
8+
public static Color ButtonPressedColor { get; set; } = Color.FromArgb(153, 153, 204);
9+
10+
11+
private bool buttonState; // The state of the button.
12+
public bool ButtonState {
13+
get => buttonState;
14+
set {
15+
if (buttonState != value) {
16+
buttonState = value;
17+
OnButtonStateChanged();
18+
}
19+
}
20+
}
21+
22+
// The "button" component that the user clicks.
23+
protected Shape interactiveShape;
24+
25+
public ButtonComponent(string id, string label, float x, float y, float width, float height) : base(id, label, x, y, width, height) {
26+
AddPin("in0", Polarity.Input);
27+
AddPin("out0", Polarity.Output);
28+
29+
BackgroundColor = Color.FromArgb(204, 204, 255);
30+
ProcessInterval = -1;
31+
32+
interactiveShape = new RectangleShape(0.25f, 0.25f, width / 2f, height / 2f) {
33+
Parent = this,
34+
CornerRadius = CornerRadius,
35+
BackgroundColor = BackgroundColor,
36+
OutlineColor = OutlineColorUnselected,
37+
OutlineThickness = OutlineThickness,
38+
PercentagePosition = true
39+
};
40+
41+
interactiveShape.OnMouseEntered += (s, e) => IsSelectable = false;
42+
interactiveShape.OnMouseLeft += (s, e) => IsSelectable = true;
43+
44+
interactiveShape.OnMousePressed += (s, e) => OnButtonPressed();
45+
interactiveShape.OnMouseReleased += (s, e) => OnButtonReleased();
46+
}
47+
48+
protected virtual void OnButtonStateChanged() {
49+
interactiveShape.BackgroundColor = ButtonState ? ButtonPressedColor : BackgroundColor;
50+
}
51+
52+
protected virtual void OnButtonPressed() {
53+
ButtonState = !ButtonState;
54+
}
55+
56+
protected virtual void OnButtonReleased() {
57+
58+
}
59+
60+
protected override bool Process() {
61+
bool isPowered = GetPins(Polarity.Input).Any(x => x.Value);
62+
bool value = ButtonState && isPowered;
63+
64+
return SetPinValues(Polarity.Output, value);
65+
}
66+
67+
protected override void DrawSymbol(Graphics g) {
68+
69+
}
70+
71+
}
72+
73+
}

LogicSandbox/Logic/Components/DigitalComponent.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ public abstract class DigitalComponent : RectangleShape, ISelectable {
4747

4848
public IReadOnlyList<Pin> Pins => pins.Values.ToList().AsReadOnly();
4949

50-
public DigitalComponent(string id, string label, float x, float y, float width, float height) : base(x, y, width, height, null) {
50+
public bool IsSelectable { get; protected set; } = true;
51+
52+
public DigitalComponent(string id, string label, float x, float y, float width, float height) : base(x, y, width, height) {
5153
Id = id;
5254
Label = label;
5355

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Maxstupo.LogicSandbox.Logic.Components {
2+
3+
public class PushOff : ButtonComponent {
4+
5+
public PushOff(string id, float x, float y) : base(id, "Push Off", x, y, 34, 34) {
6+
ButtonState = true;
7+
}
8+
9+
protected override void OnButtonPressed() {
10+
ButtonState = false;
11+
}
12+
13+
protected override void OnButtonReleased() {
14+
ButtonState = true;
15+
}
16+
17+
}
18+
19+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Maxstupo.LogicSandbox.Logic.Components {
2+
3+
public class PushOn : ButtonComponent {
4+
5+
public PushOn(string id, float x, float y) : base(id, "Push On", x, y, 34, 34) { }
6+
7+
protected override void OnButtonPressed() {
8+
ButtonState = true;
9+
}
10+
11+
protected override void OnButtonReleased() {
12+
ButtonState = false;
13+
}
14+
15+
}
16+
17+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Maxstupo.LogicSandbox.Logic.Components {
2+
3+
public class Toggle : ButtonComponent {
4+
5+
public Toggle(string id, float x, float y) : base(id, "Toggle", x, y, 34, 34) {
6+
7+
}
8+
9+
}
10+
11+
}

LogicSandbox/Logic/Pin.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,27 @@ public bool Value {
3333
}
3434
}
3535

36-
public Pin(DigitalComponent component, string id, Polarity polarity, float x, float y, float diameter) : base(x, y, diameter, component) {
36+
public Pin(DigitalComponent component, string id, Polarity polarity, float x, float y, float diameter) : base(x, y, diameter) {
3737
Id = id;
3838
Polarity = polarity;
39+
Parent = component;
3940

4041
BackgroundColor = (Polarity == Polarity.Input) ? Color.FromArgb(255, 204, 0) : Color.White;
4142

4243
OutlineColor = Color.Black;
4344
OutlineThickness = 1;
44-
45-
OnMouseEnter += Pin_OnMouseEnter;
46-
OnMouseLeave += Pin_OnMouseLeave;
4745
}
4846

49-
private void Pin_OnMouseLeave(object sender, EventArgs e) {
50-
OutlineColor = Value ? PinHighColor : PinLowColor;
47+
protected override void OnMouseEnter() {
48+
base.OnMouseEnter();
49+
OutlineColor = PinSelectedColor;
5150
}
5251

53-
private void Pin_OnMouseEnter(object sender, EventArgs e) {
54-
OutlineColor = PinSelectedColor;
52+
protected override void OnMouseLeave() {
53+
base.OnMouseLeave();
54+
OutlineColor = Value ? PinHighColor : PinLowColor;
5555
}
56+
5657

5758
}
5859

LogicSandbox/LogicSandbox.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,17 @@
5959
<DependentUpon>FormMain.cs</DependentUpon>
6060
</Compile>
6161
<Compile Include="Logic\Circuit.cs" />
62+
<Compile Include="Logic\Components\ButtonComponent.cs" />
6263
<Compile Include="Logic\Components\BypassComponent.cs" />
6364
<Compile Include="Logic\Components\DigitalComponent.cs" />
6465
<Compile Include="Logic\Components\PortIn.cs" />
6566
<Compile Include="Logic\Components\PortOut.cs" />
6667
<Compile Include="Logic\Components\Power.cs" />
6768
<Compile Include="Logic\Components\OrGate.cs" />
6869
<Compile Include="Logic\Components\NotGate.cs" />
70+
<Compile Include="Logic\Components\PushOff.cs" />
71+
<Compile Include="Logic\Components\PushOn.cs" />
72+
<Compile Include="Logic\Components\Toggle.cs" />
6973
<Compile Include="Logic\Pin.cs" />
7074
<Compile Include="Logic\Polarity.cs" />
7175
<Compile Include="Logic\Wire.cs" />

LogicSandbox/Shapes/CircleShape.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public class CircleShape : Shape {
1717
public override float Height { get => base.Height; set { base.Height = value; base.Width = value; } }
1818

1919

20-
public CircleShape() : this(0, 0, 0, null) { }
20+
public CircleShape() : this(0, 0, 0) { }
2121

22-
public CircleShape(float x, float y, float diameter, Shape parent = null) : base(x, y, diameter, diameter, parent) { }
22+
public CircleShape(float x, float y, float diameter) : base(x, y, diameter, diameter) { }
2323

2424
public override bool ContainsPoint(float x, float y) {
2525
float dx = x - GlobalX;

0 commit comments

Comments
 (0)