public Outputs Create(Inputs inputs) { StreamLoop<Fuel> sStart = new StreamLoop<Fuel>(); Fill fi = new Fill(inputs.SClearSale, inputs.SFuelPulses, inputs.Calibration, inputs.Price1, inputs.Price2, inputs.Price3, sStart); NotifyPointOfSale np = new NotifyPointOfSale( new LifeCycle(inputs.SNozzle1, inputs.SNozzle2, inputs.SNozzle3), inputs.SClearSale, fi); sStart.Loop(np.SStart); CellLoop<bool> keypadActive = new CellLoop<bool>(); Keypad ke = new Keypad(inputs.SKeypad, inputs.SClearSale, keypadActive); Preset pr = new Preset(ke.Value, fi, np.FuelFlowing); keypadActive.Loop(pr.KeypadActive); return new Outputs() .SetDelivery(pr.Delivery) .SetSaleCostLcd(fi.DollarsDelivered.Map(Formatters.FormatSaleCost)) .SetSaleQuantityLcd(fi.LitersDelivered.Map(Formatters.FormatSaleQuantity)) .SetPriceLcd1(ShowDollarsPump.PriceLcd(np.FillActive, fi.Price, Fuel.One, inputs)) .SetPriceLcd2(ShowDollarsPump.PriceLcd(np.FillActive, fi.Price, Fuel.Two, inputs)) .SetPriceLcd3(ShowDollarsPump.PriceLcd(np.FillActive, fi.Price, Fuel.Three, inputs)) .SetSaleComplete(np.SSaleComplete) .SetPresetLcd(ke.Value.Map(Formatters.FormatPresetAmount)) .SetBeep(np.SBeep.OrElse(ke.SBeep)); }
public void TestLoop() { (Cell <int> c, CellStreamSink <int> s) = Transaction.Run(() => { CellLoop <int> loop = Cell.CreateLoop <int>(); Cell <int> cLocal = loop.Map(v => v * 5); CellStreamSink <int> sLocal = Cell.CreateStreamSink <int>(); loop.Loop(sLocal.Hold(3)); return(cLocal, sLocal); }); List <int> output1 = new List <int>(); List <int> output2 = new List <int>(); IListener l = c.Listen(output1.Add); IListener l2 = c.Updates().Listen(output2.Add); s.Send(5); s.Send(7); l2.Unlisten(); l.Unlisten(); CollectionAssert.AreEqual(new[] { 15, 25, 35 }, output1); CollectionAssert.AreEqual(new[] { 25, 35 }, output2); }
public FrView(Window window, Fridget fr, IListener l) { StreamSink <MouseEvent> sMouse = new StreamSink <MouseEvent>(); StreamSink <KeyEvent> sKey = new StreamSink <KeyEvent>(); this.MouseDown += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseUp += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseMove += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); CellSink <Maybe <Size> > size = new CellSink <Maybe <Size> >(Maybe.None); this.SizeChanged += (sender, args) => size.Send(Maybe.Some(args.NewSize)); window.KeyDown += (sender, args) => { Key key = args.Key == Key.System ? args.SystemKey : args.Key; if (key == Key.Back) { sKey.Send(new BackspaceKeyEvent()); } }; window.TextInput += (sender, args) => sKey.Send(new StringKeyEvent(args.Text)); CellLoop <long> focus = new CellLoop <long>(); Fridget.Output fo = fr.Reify(size, sMouse, sKey, focus, new Supply()); focus.Loop(fo.SChangeFocus.Hold(-1)); this.drawable = fo.Drawable; this.l = new CompositeListener(new[] { l, this.drawable.Updates.Listen(d => this.InvalidateVisual()) }); }
public Keypad(Stream <Key> sKeypad, Stream <Unit> sClear) { CellLoop <int> value = new CellLoop <int>(); this.Value = value; Stream <int> sKeyUpdate = sKeypad.Snapshot(value, (key, valueLocal) => { if (key == Key.Clear) { return(Maybe.Some(0)); } int x10 = valueLocal * 10; return(x10 >= 1000 ? Maybe.None : Maybe.Some( key == Key.Zero ? x10 : key == Key.One ? x10 + 1 : key == Key.Two ? x10 + 2 : key == Key.Three ? x10 + 3 : key == Key.Four ? x10 + 4 : key == Key.Five ? x10 + 5 : key == Key.Six ? x10 + 6 : key == Key.Seven ? x10 + 7 : key == Key.Eight ? x10 + 8 : x10 + 9)); }).FilterMaybe(); value.Loop(sKeyUpdate.OrElse(sClear.Map(u => 0)).Hold(0)); this.SBeep = sKeyUpdate.Map(_ => Unit.Value); }
public void SwitchEarlySOnCellLoop() { ValueTuple <Stream <int>, StreamSink <int>, StreamSink <int>, CellSink <Stream <int> > > t = Transaction.Run(() => { CellLoop <Stream <int> > loop = Cell.CreateLoop <Stream <int> >(); StreamSink <int> c1 = Stream.CreateSink <int>(); StreamSink <int> c2 = Stream.CreateSink <int>(); Stream <int> c = loop.SwitchEarlyS(); CellSink <Stream <int> > s = Cell.CreateSink(c1.AsStream()); loop.Loop(s); return(ValueTuple.Create(c, c1, c2, s)); }); List <int> output = new List <int>(); IListener l = t.Item1.Listen(output.Add); t.Item2.Send(2); t.Item3.Send(12); Transaction.RunVoid(() => { t.Item2.Send(3); t.Item3.Send(13); t.Item4.Send(t.Item3); }); t.Item2.Send(4); t.Item3.Send(14); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 13, 14 }, output); }
public Keypad(Stream<Key> sKeypad, Stream<Unit> sClear) { CellLoop<int> value = new CellLoop<int>(); this.Value = value; Stream<int> sKeyUpdate = sKeypad.Snapshot(value, (key, valueLocal) => { if (key == Key.Clear) { return Maybe.Just(0); } int x10 = valueLocal * 10; return x10 >= 1000 ? Maybe.Nothing<int>() : Maybe.Just( key == Key.Zero ? x10 : key == Key.One ? x10 + 1 : key == Key.Two ? x10 + 2 : key == Key.Three ? x10 + 3 : key == Key.Four ? x10 + 4 : key == Key.Five ? x10 + 5 : key == Key.Six ? x10 + 6 : key == Key.Seven ? x10 + 7 : key == Key.Eight ? x10 + 8 : x10 + 9); }).FilterMaybe(); value.Loop(sKeyUpdate.OrElse(sClear.Map(u => 0)).Hold(0)); this.SBeep = sKeyUpdate.Map(_ => Unit.Value); }
private FrTextField(string initText, CellLoop <string> text) : base((size, sMouse, sKey, focus, idSupply) => { Stream <double> sPressed = sMouse.Snapshot(size, (e, mSize) => mSize.Bind( s => { MouseButtonEventArgs b = e.Args as MouseButtonEventArgs; Point p = e.GetPosition(); return(b != null && b.ChangedButton == MouseButton.Left && b.ButtonState == MouseButtonState.Pressed && p.X >= 2 && p.X < s.Width - 2 && p.Y >= 2 && p.Y < s.Height - 2 ? Maybe.Some(p.X - 2) : Maybe.None); })).FilterMaybe(); CellLoop <int> x = new CellLoop <int>(); long myId = idSupply.Get(); Cell <bool> haveFocus = focus.Map(fId => fId == myId); Typeface typeface = new Typeface(new FontFamily("Helvetica"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); Stream <TextUpdate> sTextUpdate = sKey.Gate(haveFocus).Snapshot(text, x, (key, txt, xValue) => { if (key is BackspaceKeyEvent) { return(xValue > 0 ? Maybe.Some(new TextUpdate( txt.Substring(0, xValue - 1) + txt.Substring(xValue), xValue - 1)) : Maybe.None); } if (!(key is StringKeyEvent stringKey)) { throw new InvalidOperationException("Unexpected type encountered for " + typeof(KeyEvent).FullName + ": " + key.GetType().FullName + "."); }
public MainWindow() { this.InitializeComponent(); Transaction.RunVoid(() => { STextBox word = new STextBox(string.Empty); CellLoop <bool> enabled = new CellLoop <bool>(); SButton button = new SButton(enabled) { Content = "look up" }; Stream <string> sWord = button.SClicked.Snapshot(word.Text); IsBusy <string, IMaybe <string> > ib = new IsBusy <string, IMaybe <string> >(Lookup, sWord); Stream <string> sDefinition = ib.SOut.Map(o => o.Match(v => v, () => "ERROR!")); Cell <string> definition = sDefinition.Hold(string.Empty); Cell <string> output = definition.Lift(ib.Busy, (def, bsy) => bsy ? "Looking up..." : def); enabled.Loop(ib.Busy.Map(b => !b)); STextBox outputArea = new STextBox(Operational.Value(output), string.Empty, enabled) { TextWrapping = TextWrapping.Wrap, AcceptsReturn = true }; this.TextBoxPlaceholder.Child = word; this.ButtonPlaceholder.Child = button; this.OutputPlaceholder.Child = outputArea; }); }
public void TestSwitchSValuesLoop() { CellStreamSink <IReadOnlyList <TestObject> > streamSink = Cell.CreateStreamSink <IReadOnlyList <TestObject> >(); Cell <IReadOnlyList <TestObject> > cell = Transaction.Run(() => { CellLoop <IReadOnlyList <TestObject> > cellLoop = new CellLoop <IReadOnlyList <TestObject> >(); Cell <IReadOnlyList <TestObject> > cellLocal = streamSink.Map(v => (Func <IReadOnlyList <TestObject>, IReadOnlyList <TestObject> >)(_ => v)) .Merge(cellLoop.Map(oo => oo.Select(o => o.Output).Lift(vv => vv.Sum()).Values()).SwitchS().Filter(sum => sum < 50).MapTo((Func <IReadOnlyList <TestObject>, IReadOnlyList <TestObject> >)(v => v.Concat(new[] { new TestObject() }).ToArray())), (f, g) => v => g(f(v))) .Snapshot(cellLoop, (f, v) => f(v)) .Hold(Enumerable.Range(1, 10).Select(_ => new TestObject()).ToArray()); cellLoop.Loop(cellLocal); return(cellLocal); }); List <int> objectCounts = new List <int>(); objectCounts.Add(-1); cell.Listen(vv => objectCounts.Add(vv.Count)); objectCounts.Add(-1); cell.Sample()[2].Input1.Send(1); objectCounts.Add(-1); cell.Sample()[1].Input1.Send(-20); objectCounts.Add(-1); streamSink.Send(new TestObject[0]); objectCounts.Add(-1); // Ideal result, likely not achievable. //CollectionAssert.AreEquivalent(new[] { -1, 10, -1, 11, -1, 15, -1, 10, -1 }, objectCounts); // Glitchy result, also not returned by this method. //CollectionAssert.AreEquivalent(new[] { -1, 10, -1, 11, -1, 12, 13, 14, 15, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1 }, objectCounts); // Incorrect result we will see. CollectionAssert.AreEquivalent(new[] { -1, 10, -1, 11, -1, 12, -1, 0, -1 }, objectCounts); }
public MainWindow() { this.InitializeComponent(); Transaction.RunVoid(() => { CellLoop <int> value = new CellLoop <int>(); SLabel lblValue = new SLabel(value.Map(i => i.ToString())); SButton plus = new SButton { Content = "+", Width = 25, Margin = new Thickness(5, 0, 0, 0) }; SButton minus = new SButton { Content = "-", Width = 25, Margin = new Thickness(5, 0, 0, 0) }; this.Container.Children.Add(lblValue); this.Container.Children.Add(plus); this.Container.Children.Add(minus); Stream <int> sPlusDelta = plus.SClicked.Map(_ => 1); Stream <int> sMinusDelta = minus.SClicked.Map(_ => - 1); Stream <int> sDelta = sPlusDelta.OrElse(sMinusDelta); Stream <int> sUpdate = sDelta.Snapshot(value, (d, v) => v + d); value.Loop(sUpdate.Hold(0)); }); }
public void TestSwitchCDeferredLoopWithBetterApi() { CellStreamSink <IReadOnlyList <TestObject> > streamSink = Cell.CreateStreamSink <IReadOnlyList <TestObject> >(); Cell <IReadOnlyList <TestObject> > cell = Transaction.Run(() => { CellLoop <IReadOnlyList <TestObject> > cellLoop = new CellLoop <IReadOnlyList <TestObject> >(); Cell <IReadOnlyList <TestObject> > cellLocal = streamSink .OrElse(cellLoop.Map(oo => oo.Select(o => o.Output).Lift(vv => vv.Sum())).SwitchCWithDeferredValues().Filter(sum => sum < 50).Snapshot(cellLoop, (_, items) => (IReadOnlyList <TestObject>)items.Concat(new[] { new TestObject() }).ToArray())) .Hold(Enumerable.Range(1, 10).Select(_ => new TestObject()).ToArray()); cellLoop.Loop(cellLocal); return(cellLocal); }); List <int> objectCounts = new List <int>(); objectCounts.Add(-1); cell.Listen(vv => objectCounts.Add(vv.Count)); objectCounts.Add(-1); cell.Sample()[2].Input1.Send(1); objectCounts.Add(-1); cell.Sample()[1].Input1.Send(-20); objectCounts.Add(-1); streamSink.Send(new TestObject[0]); objectCounts.Add(-1); // Ideal result, likely not achievable. //CollectionAssert.AreEquivalent(new[] { -1, 10, -1, 11, -1, 15, -1, 10, -1 }, objectCounts); // Glitchy result, but correct otherwise. CollectionAssert.AreEquivalent(new[] { -1, 10, -1, 11, -1, 12, 13, 14, 15, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1 }, objectCounts); }
public FrFlow(Orientation dir, IEnumerable <Fridget> fridgets) : base((size, sMouse, sKey, focus, idSupply) => { Cell <Size> desiredSize = Cell.Constant(new Size(0, 0)); Cell <DrawableDelegate> drawable = Cell.Constant(new DrawableDelegate(d => { })); Stream <long> sChangeFocus = Stream.Never <long>(); foreach (Fridget fridget in fridgets) { CellLoop <Maybe <Size> > childSz = new CellLoop <Maybe <Size> >(); Output fo = new FrTranslate(fridget, dir == Orientation.Horizontal ? desiredSize.Map(dsz => new Point(dsz.Width, 0)) : desiredSize.Map(dsz => new Point(0, dsz.Height))) .Reify(childSz, sMouse, sKey, focus, idSupply.Child1()); idSupply = idSupply.Child2(); childSz.Loop( size.Lift(fo.DesiredSize, (mSize, foDsz) => mSize.Map(s => dir == Orientation.Horizontal ? new Size(foDsz.Width, s.Height) : new Size(s.Width, foDsz.Height)))); Size LiftDesiredSizeHorizontal(Size dsz, Size foDsz) => new Size(dsz.Width + foDsz.Width, dsz.Height > foDsz.Height ? dsz.Height : foDsz.Height); Size LiftDesiredSizeVertical(Size dsz, Size foDsz) => new Size(dsz.Width > foDsz.Width ? dsz.Width : foDsz.Width, dsz.Height + foDsz.Height); desiredSize = desiredSize.Lift(fo.DesiredSize, dir == Orientation.Horizontal ? LiftDesiredSizeHorizontal : (Func <Size, Size, Size>)LiftDesiredSizeVertical); drawable = drawable.Lift(fo.Drawable, (drA, drB) => drA.Append(drB)); sChangeFocus = sChangeFocus.OrElse(fo.SChangeFocus); } return(new Output(drawable, desiredSize, sChangeFocus)); }) { }
public void TestLoopCell() { CellSink <int> ca = Cell.CreateSink(22); (CellLoop <int> cb, Cell <int> cb2, Cell <int> cc) = Transaction.Run(() => { CellLoop <int> cbLocal = Cell.CreateLoop <int>(); Cell <int> ccLocal = ca.Map(x => x % 10).Lift(cbLocal, (x, y) => x * y); Cell <int> cbOut = ca.Map(x => x / 10); cbLocal.Loop(cbOut); return(cbLocal, cbOut, ccLocal); }); List <int> @out = new List <int>(); List <int> out2 = new List <int>(); List <int> out3 = new List <int>(); IListener l = cb.Listen(@out.Add); IListener l2 = cb2.Listen(out2.Add); IListener l3 = cc.Listen(out3.Add); ca.Send(2); ca.Send(52); l3.Unlisten(); l2.Unlisten(); l.Unlisten(); CollectionAssert.AreEqual(new[] { 2, 0, 5 }, @out.ToArray()); CollectionAssert.AreEqual(new[] { 2, 0, 5 }, out2.ToArray()); CollectionAssert.AreEqual(new[] { 4, 0, 10 }, out3.ToArray()); }
public Outputs Create(Inputs inputs) { StreamLoop <Fuel> sStart = new StreamLoop <Fuel>(); Fill fi = new Fill(inputs.SClearSale, inputs.SFuelPulses, inputs.Calibration, inputs.Price1, inputs.Price2, inputs.Price3, sStart); NotifyPointOfSale np = new NotifyPointOfSale( new LifeCycle(inputs.SNozzle1, inputs.SNozzle2, inputs.SNozzle3), inputs.SClearSale, fi); sStart.Loop(np.SStart); CellLoop <bool> keypadActive = new CellLoop <bool>(); Keypad ke = new Keypad(inputs.SKeypad, inputs.SClearSale, keypadActive); Preset pr = new Preset(ke.Value, fi, np.FuelFlowing); keypadActive.Loop(pr.KeypadActive); return(new Outputs() .SetDelivery(pr.Delivery) .SetSaleCostLcd(fi.DollarsDelivered.Map(Formatters.FormatSaleCost)) .SetSaleQuantityLcd(fi.LitersDelivered.Map(Formatters.FormatSaleQuantity)) .SetPriceLcd1(ShowDollarsPump.PriceLcd(np.FillActive, fi.Price, Fuel.One, inputs)) .SetPriceLcd2(ShowDollarsPump.PriceLcd(np.FillActive, fi.Price, Fuel.Two, inputs)) .SetPriceLcd3(ShowDollarsPump.PriceLcd(np.FillActive, fi.Price, Fuel.Three, inputs)) .SetSaleComplete(np.SSaleComplete) .SetPresetLcd(ke.Value.Map(Formatters.FormatPresetAmount)) .SetBeep(np.SBeep.OrElse(ke.SBeep))); }
private static Stream <DateTime> Periodic(ITimerSystem <DateTime> sys, TimeSpan period) { Behavior <DateTime> time = sys.Time; CellLoop <Maybe <DateTime> > oAlarm = new CellLoop <Maybe <DateTime> >(); Stream <DateTime> sAlarm = sys.At(oAlarm); oAlarm.Loop(sAlarm.Map(t => Maybe.Some(t + period)).Hold(Maybe.Some(time.Sample() + period))); return(sAlarm); }
private Cell <bool> GetFlag(int target, Stream <int> sFlag) { Stream <int> sMark = sFlag.Filter(target.Equals); CellLoop <bool> flag = new CellLoop <bool>(); Stream <bool> sInvert = sMark.Snapshot(flag, (_, value) => !value); flag.Loop(sInvert.Hold(true)); return(flag); }
public static Cell<double> Accumulate( Stream<Unit> sClearAccumulator, Stream<int> sPulses, Cell<double> calibration) { CellLoop<int> total = new CellLoop<int>(); total.Loop(sClearAccumulator.Map(u => 0) .OrElse(sPulses.Snapshot(total, (pulsesLocal, totalLocal) => pulsesLocal + totalLocal)) .Hold(0)); return total.Lift( calibration, (totalLocal, calibrationLocal) => totalLocal * calibrationLocal); }
public static Cell <double> Accumulate( Stream <Unit> sClearAccumulator, Stream <int> sPulses, Cell <double> calibration) { CellLoop <int> total = new CellLoop <int>(); total.Loop(sClearAccumulator.Map(u => 0) .OrElse(sPulses.Snapshot(total, (pulsesLocal, totalLocal) => pulsesLocal + totalLocal)) .Hold(0)); return(total.Lift( calibration, (totalLocal, calibrationLocal) => totalLocal * calibrationLocal)); }
public MainWindow() { InitializeComponent(); const int buttonSize = 24; // Introduction // const int columns = 8; // const int rows = 8; // const int mines = 10; // Intermediate // const int columns = 16; // const int rows = 16; // const int mines = 40; // Expert const int columns = 30; const int rows = 16; const int mines = 99; Container.MaxWidth = buttonSize * columns; Container.MaxHeight = buttonSize * rows; Transaction.RunVoid(() => { var sClicked = Stream.Never <int>(); var sClickedRight = Stream.Never <int>(); var squares = new Dictionary <int, CellLoop <Square> >(); foreach (var target in Enumerable.Range(0, columns * rows)) { var square = new CellLoop <Square>(); squares.Add(target, square); var button = new SButton(square) { Width = buttonSize, Height = buttonSize }; sClicked = button.SClicked.Map(u => target).OrElse(sClicked); sClickedRight = button.SClickedRight.Map(u => target).OrElse(sClickedRight); Container.Children.Add(button); } var field = new Game(columns, rows, mines, sClicked, sClickedRight).Field; foreach (var target in Enumerable.Range(0, columns * rows)) { squares[target].Loop(field[target]); } }); }
public LifeCycle(Stream<UpDown> sNozzle1, Stream<UpDown> sNozzle2, Stream<UpDown> sNozzle3) { Stream<Fuel> sLiftNozzle = WhenLifted(sNozzle1, Fuel.One).OrElse( WhenLifted(sNozzle2, Fuel.Two).OrElse( WhenLifted(sNozzle3, Fuel.Three))); CellLoop<IMaybe<Fuel>> fillActive = new CellLoop<IMaybe<Fuel>>(); this.FillActive = fillActive; this.SStart = sLiftNozzle.Snapshot(fillActive, (newFuel, fillActiveLocal) => fillActiveLocal.Match(_ => Maybe.Nothing<Fuel>(), () => Maybe.Just(newFuel))).FilterMaybe(); this.SEnd = WhenSetDown(sNozzle1, Fuel.One, fillActive).OrElse( WhenSetDown(sNozzle2, Fuel.Two, fillActive).OrElse( WhenSetDown(sNozzle3, Fuel.Three, fillActive))); fillActive.Loop( this.SEnd.Map(e => Maybe.Nothing<Fuel>()) .OrElse(this.SStart.Map(Maybe.Just)) .Hold(Maybe.Nothing<Fuel>())); }
public void TestRunConstruct2() { var(objectsAndIsSelected, selectAllStream, objects) = Transaction.Run(() => { CellLoop <bool?> allSelectedCellLoop = Cell.CreateLoop <bool?>(); StreamSink <Unit> toggleAllSelectedStreamLocal = Stream.CreateSink <Unit>(); Stream <bool> selectAllStreamLocal = toggleAllSelectedStreamLocal.Snapshot(allSelectedCellLoop).Map(a => a != true); IReadOnlyList <TestObject2> o2 = Enumerable.Range(0, 10000).Select(n => new TestObject2(n, n < 1500, selectAllStreamLocal)).ToArray(); CellSink <IReadOnlyList <TestObject2> > objectsLocal = Cell.CreateSink(o2); var objectsAndIsSelectedLocal = objectsLocal.Map(oo => oo.Select(o => o.IsSelected.Map(s => new { Object = o, IsSelected = s })).Lift()).SwitchC(); bool defaultValue = o2.Count < 1; Cell <bool?> allSelected = objectsAndIsSelectedLocal.Map( oo => !oo.Any() ? defaultValue : (oo.All(o => o.IsSelected) ? true : (oo.All(o => !o.IsSelected) ? (bool?)false : null))); allSelectedCellLoop.Loop(allSelected); return(objectsAndIsSelectedLocal, selectAllStreamLocal, objectsLocal); }); List <int> @out = new List <int>(); using (Transaction.Run( () => objectsAndIsSelected.Map(oo => oo.Count(o => o.IsSelected)) .Values.Listen(@out.Add))) { Transaction.Run(() => { objects.Send( Enumerable.Range(0, 20000) .Select(n => new TestObject2(n, n < 500, selectAllStream)) .ToArray()); return(Unit.Value); }); } CollectionAssert.AreEqual(new[] { 1500, 500 }, @out); }
public LifeCycle(Stream <UpDown> sNozzle1, Stream <UpDown> sNozzle2, Stream <UpDown> sNozzle3) { Stream <Fuel> sLiftNozzle = WhenLifted(sNozzle1, Fuel.One).OrElse( WhenLifted(sNozzle2, Fuel.Two).OrElse( WhenLifted(sNozzle3, Fuel.Three))); CellLoop <Maybe <Fuel> > fillActive = new CellLoop <Maybe <Fuel> >(); this.FillActive = fillActive; this.SStart = sLiftNozzle.Snapshot(fillActive, (newFuel, fillActiveLocal) => fillActiveLocal.Match(_ => Maybe.None, () => Maybe.Some(newFuel))).FilterMaybe(); this.SEnd = WhenSetDown(sNozzle1, Fuel.One, fillActive).OrElse( WhenSetDown(sNozzle2, Fuel.Two, fillActive).OrElse( WhenSetDown(sNozzle3, Fuel.Three, fillActive))); fillActive.Loop( this.SEnd.Map(e => Maybe <Fuel> .None) .OrElse(this.SStart.Map(Maybe.Some)) .Hold(Maybe.None)); }
public void TestSwitchCLoop() { Exception actual = null; try { CellStreamSink <IReadOnlyList <TestObject> > streamSink = Cell.CreateStreamSink <IReadOnlyList <TestObject> >(); Cell <IReadOnlyList <TestObject> > cell = Transaction.Run(() => { CellLoop <IReadOnlyList <TestObject> > cellLoop = new CellLoop <IReadOnlyList <TestObject> >(); Cell <IReadOnlyList <TestObject> > cellLocal = streamSink.Map(v => (Func <IReadOnlyList <TestObject>, IReadOnlyList <TestObject> >)(_ => v)) .Merge(cellLoop.Map(oo => oo.Select(o => o.Output).Lift(vv => vv.Sum())).SwitchC().Updates().Filter(sum => sum < 50).MapTo((Func <IReadOnlyList <TestObject>, IReadOnlyList <TestObject> >)(v => v.Concat(new[] { new TestObject() }).ToArray())), (f, g) => v => g(f(v))) .Snapshot(cellLoop, (f, v) => f(v)) .Hold(Enumerable.Range(1, 10).Select(_ => new TestObject()).ToArray()); cellLoop.Loop(cellLocal); return(cellLocal); }); List <int> objectCounts = new List <int>(); objectCounts.Add(-1); cell.Listen(vv => objectCounts.Add(vv.Count)); objectCounts.Add(-1); cell.Sample()[2].Input1.Send(1); objectCounts.Add(-1); cell.Sample()[1].Input1.Send(-20); objectCounts.Add(-1); streamSink.Send(new TestObject[0]); objectCounts.Add(-1); } catch (AggregateException e) { actual = e.InnerExceptions.FirstOrDefault(ex => ex.Message == "A dependency cycle was detected."); } catch (Exception e) { actual = e; } Assert.IsNotNull(actual); Assert.AreEqual("A dependency cycle was detected.", actual.Message); }
public async Task TestListenAsync() { CellSink <int> a = Cell.CreateSink(1); Cell <int> a1 = a.Map(x => x + 1); Cell <int> a2 = a.Map(x => x * 2); (List <int> results, CellLoop <int> called, IListener l) = Transaction.Run(() => { Cell <int> result = a1.Lift(a2, (x, y) => x + y); Stream <Unit> incrementStream = result.Values().MapTo(Unit.Value); StreamSink <Unit> decrementStream = Stream.CreateSink <Unit>(); CellLoop <int> calledLoop = Cell.CreateLoop <int>(); calledLoop.Loop(incrementStream.MapTo(1).Merge(decrementStream.MapTo(-1), (x, y) => x + y).Snapshot(calledLoop, (u, c) => c + u).Hold(0)); List <int> r = new List <int>(); IListener lLocal = result.Listen(v => { Task.Run(async() => { await Task.Delay(900); r.Add(v); decrementStream.Send(Unit.Value); }); }); return(r, calledLoop, lLocal); }); // ReSharper disable once UnusedVariable List <int> calledResults = new List <int>(); IListener l2 = called.Listen(calledResults.Add); await Task.Delay(500); a.Send(2); await Task.Delay(500); a.Send(3); await Task.Delay(2500); l2.Unlisten(); l.Unlisten(); }
public MainWindow() { this.InitializeComponent(); Transaction.RunVoid(() => { CellLoop<int> value = new CellLoop<int>(); SLabel lblValue = new SLabel(value.Map(i => i.ToString())); SButton plus = new SButton { Content = "+", Width = 25, Margin = new Thickness(5, 0, 0, 0) }; SButton minus = new SButton { Content = "-", Width = 25, Margin = new Thickness(5, 0, 0, 0) }; this.Container.Children.Add(lblValue); this.Container.Children.Add(plus); this.Container.Children.Add(minus); Stream<int> sPlusDelta = plus.SClicked.Map(_ => 1); Stream<int> sMinusDelta = minus.SClicked.Map(_ => -1); Stream<int> sDelta = sPlusDelta.OrElse(sMinusDelta); Stream<int> sUpdate = sDelta.Snapshot(value, (d, v) => v + d).Filter(n => n >= 0); value.Loop(sUpdate.Hold(0)); }); }
public void ImperativeCellLoop() { CellSink <int> s = Cell.CreateSink(0); Cell <int> result = Transaction.Run( () => { CellLoop <int> l = new CellLoop <int>(); Cell <int> resultLocal = s.Updates().Snapshot(l, (n, o) => n + o).Hold(0); l.Loop(resultLocal); return(resultLocal); }); List <int> @out = new List <int>(); using (Transaction.Run(() => result.Values().Listen(@out.Add))) { s.Send(1); s.Send(2); s.Send(3); } CollectionAssert.AreEqual(new[] { 0, 1, 3, 6 }, @out); }
public FrView(Window window, Fridget fr, IListener l) { StreamSink<MouseEvent> sMouse = new StreamSink<MouseEvent>(); StreamSink<KeyEvent> sKey = new StreamSink<KeyEvent>(); this.MouseDown += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseUp += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); this.MouseMove += (sender, args) => sMouse.Send(new MouseEvent(args, () => args.GetPosition(this))); CellSink<IMaybe<Size>> size = new CellSink<IMaybe<Size>>(Maybe.Nothing<Size>()); this.SizeChanged += (sender, args) => size.Send(Maybe.Just(args.NewSize)); window.KeyDown += (sender, args) => { Key key = args.Key == Key.System ? args.SystemKey : args.Key; if (key == Key.Back) { sKey.Send(new BackspaceKeyEvent()); } }; window.TextInput += (sender, args) => sKey.Send(new StringKeyEvent(args.Text)); CellLoop<long> focus = new CellLoop<long>(); Fridget.Output fo = fr.Reify(size, sMouse, sKey, focus, new Supply()); focus.Loop(fo.SChangeFocus.Hold(-1)); this.drawable = fo.Drawable; this.l = new ImmutableCompositeListener(new[] { l, Operational.Updates(this.drawable).Listen(d => this.InvalidateVisual()) }); }
public FrFlow(Orientation dir, IEnumerable<Fridget> fridgets) : base((size, sMouse, sKey, focus, idSupply) => { Cell<Size> desiredSize = Cell.Constant(new Size(0, 0)); Cell<DrawableDelegate> drawable = Cell.Constant(new DrawableDelegate(d => { })); Stream<long> sChangeFocus = Stream.Never<long>(); foreach (Fridget fridget in fridgets) { CellLoop<IMaybe<Size>> childSz = new CellLoop<IMaybe<Size>>(); Output fo = new FrTranslate(fridget, dir == Orientation.Horizontal ? desiredSize.Map(dsz => new Point(dsz.Width, 0)) : desiredSize.Map(dsz => new Point(0, dsz.Height))) .Reify(childSz, sMouse, sKey, focus, idSupply.Child1()); idSupply = idSupply.Child2(); childSz.Loop( size.Lift(fo.DesiredSize, (mSize, foDsz) => mSize.Match(s => Maybe.Just(dir == Orientation.Horizontal ? new Size(foDsz.Width, s.Height) : new Size(s.Width, foDsz.Height)), Maybe.Nothing<Size>))); Func<Size, Size, Size> liftDesiredSizeHorizontal = (dsz, foDsz) => new Size( dsz.Width + foDsz.Width, dsz.Height > foDsz.Height ? dsz.Height : foDsz.Height); Func<Size, Size, Size> liftDesiredSizeVertical = (dsz, foDsz) => new Size( dsz.Width > foDsz.Width ? dsz.Width : foDsz.Width, dsz.Height + foDsz.Height); desiredSize = desiredSize.Lift(fo.DesiredSize, dir == Orientation.Horizontal ? liftDesiredSizeHorizontal : liftDesiredSizeVertical); drawable = drawable.Lift(fo.Drawable, (drA, drB) => drA.Append(drB)); sChangeFocus = sChangeFocus.OrElse(fo.SChangeFocus); } return new Output(drawable, desiredSize, sChangeFocus); }) { }
public void ImperativeCellLoopFailsWhenLoopedInSeparateTransaction() { InvalidOperationException actual = null; CellLoop <int> l = null; new Thread( () => Transaction.RunVoid( () => { l = new CellLoop <int>(); Thread.Sleep(500); })).Start(); try { CellSink <int> s = Cell.CreateSink(0); Transaction.RunVoid( () => { Thread.Sleep(250); Cell <int> resultLocal = s.Updates().Snapshot(l, (n, o) => n + o).Hold(0); l.Loop(resultLocal); }); } catch (InvalidOperationException e) { actual = e; } Thread.Sleep(500); Assert.IsNotNull(actual); Assert.AreEqual("Loop must be looped in the same transaction that it was created in.", actual.Message); }
public void ImperativeCellLoopFailsWhenLoopedTwice() { InvalidOperationException actual = null; try { CellSink <int> s = Cell.CreateSink(0); Transaction.RunVoid( () => { CellLoop <int> l = new CellLoop <int>(); Cell <int> resultLocal = s.Updates().Snapshot(l, (n, o) => n + o).Hold(0); l.Loop(resultLocal); l.Loop(resultLocal); }); } catch (InvalidOperationException e) { actual = e; } Assert.IsNotNull(actual); Assert.AreEqual("Loop was looped more than once.", actual.Message); }
public static void Main(string[] args) { Console.WriteLine("Press any key"); Console.ReadKey(); var(toggleAllSelectedStream, objectsAndIsSelected, selectAllStream, objects) = Transaction.Run(() => { CellLoop <bool?> allSelectedCellLoop = Cell.CreateLoop <bool?>(); StreamSink <Unit> toggleAllSelectedStreamLocal = Stream.CreateSink <Unit>(); Stream <bool> selectAllStreamLocal = toggleAllSelectedStreamLocal.Snapshot(allSelectedCellLoop).Map(a => a != true); IReadOnlyList <TestObject> o2 = Enumerable.Range(0, 10000).Select(n => new TestObject(n, selectAllStreamLocal)).ToArray(); DiscreteCellSink <IReadOnlyList <TestObject> > objectsLocal = DiscreteCell.CreateSink((IReadOnlyList <TestObject>) new TestObject[0]); var objectsAndIsSelectedLocal = objectsLocal.Map(oo => oo.Select(o => o.IsSelected.Map(s => new { Object = o, IsSelected = s })).Lift()).SwitchC(); bool defaultValue = o2.Count < 1; DiscreteCell <bool?> allSelected = objectsAndIsSelectedLocal.Map( oo => !oo.Any() ? defaultValue : (oo.All(o => o.IsSelected) ? true : (oo.All(o => !o.IsSelected) ? (bool?)false : null))); allSelectedCellLoop.Loop(allSelected.Cell); return(toggleAllSelectedStreamLocal, objectsAndIsSelectedLocal, selectAllStreamLocal, objectsLocal); }); // ReSharper disable once UnusedVariable IListener l = Transaction.Run(() => objectsAndIsSelected.Map(oo => oo.Count(o => o.IsSelected)).Updates.Listen(v => Console.WriteLine($"{v} selected"))); Console.WriteLine("Press any key"); Console.ReadKey(); Stopwatch sw = new Stopwatch(); sw.Start(); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); Thread.Sleep(500); SendMore(objects, selectAllStream); objects.Cell.Sample()[2].IsSelectedStreamSink.Send(true); Transaction.RunVoid(() => { objects.Cell.Sample()[3].IsSelectedStreamSink.Send(true); objects.Cell.Sample()[4].IsSelectedStreamSink.Send(true); }); Transaction.RunVoid(() => { objects.Send(Enumerable.Range(0, 2500).Select(n => new TestObject(n, selectAllStream)).ToArray()); toggleAllSelectedStream.Send(Unit.Value); }); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); toggleAllSelectedStream.Send(Unit.Value); objects.Send(new TestObject[0]); sw.Stop(); Console.WriteLine(); Console.WriteLine(); Console.WriteLine($"Elapsed: {sw.ElapsedMilliseconds}ms"); Console.WriteLine(); Console.WriteLine("Press any key"); Console.ReadKey(); }
private FrTextField(string initText, CellLoop <string> text) : base((size, sMouse, sKey, focus, idSupply) => { Stream <double> sPressed = sMouse.Snapshot(size, (e, mSize) => mSize.Match( s => { MouseButtonEventArgs b = e.Args as MouseButtonEventArgs; Point p = e.GetPosition(); return(b != null && b.ChangedButton == MouseButton.Left && b.ButtonState == MouseButtonState.Pressed && p.X >= 2 && p.X < s.Width - 2 && p.Y >= 2 && p.Y < s.Height - 2 ? Maybe.Just(p.X - 2) : Maybe.Nothing <double>()); }, Maybe.Nothing <double>)).FilterMaybe(); CellLoop <int> x = new CellLoop <int>(); long myId = idSupply.Get(); Cell <bool> haveFocus = focus.Map(fId => fId == myId); Typeface typeface = new Typeface(new FontFamily("Helvetica"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); Stream <TextUpdate> sTextUpdate = sKey.Gate(haveFocus).Snapshot(text, (key, txt) => { int xValue = x.Sample(); if (key is BackspaceKeyEvent) { return(xValue > 0 ? Maybe.Just(new TextUpdate( txt.Substring(0, xValue - 1) + txt.Substring(xValue), xValue - 1)) : Maybe.Nothing <TextUpdate>()); } StringKeyEvent stringKey = key as StringKeyEvent; if (stringKey == null) { throw new InvalidOperationException("Unexpected type encountered for " + typeof(KeyEvent).FullName + ": " + key.GetType().FullName + "."); } string keyString = stringKey.String; return(keyString == "\b" ? Maybe.Nothing <TextUpdate>() : Maybe.Just(new TextUpdate( txt.Substring(0, xValue) + keyString + txt.Substring(xValue), xValue + 1))); }).FilterMaybe(); x.Loop(sPressed.Snapshot(text, (xCoord, txt) => { for (int i = 1; i <= txt.Length; i++) { if (xCoord < FontUtilities.MeasureString(txt.Substring(0, i), typeface, 13).Width) { return(i - 1); } } return(txt.Length); }) .OrElse(sTextUpdate.Map(tu => tu.NewX)) .Hold(0)); text.Loop(sTextUpdate.Map(tu => tu.Txt).Hold(initText)); Cell <Size> desiredSize = text.Map(txt => { Size s = FontUtilities.MeasureString(txt, typeface, 13); return(new Size(s.Width + 14, s.Height + 10)); }); return(new Output( text.Lift( x, haveFocus, size, (txt, xValue, haveFocusValue, mSize) => new DrawableDelegate(d => { mSize.Match( sz => { d.DrawRectangle(Brushes.White, new Pen(Brushes.Black, 1), new Rect(new Point(2, 2), new Size(sz.Width - 5, sz.Height - 5))); FormattedText t = FontUtilities.GetStandardFormattedText(txt, typeface, 13, Brushes.Black); FormattedText tCursor = FontUtilities.GetStandardFormattedText(txt.Substring(0, xValue), typeface, 13, Brushes.Black); d.DrawText(t, new Point(4, (sz.Height - t.Height) / 2)); if (haveFocusValue) { double cursorX = tCursor.Width; d.DrawLine(new Pen(Brushes.Red, 1), new Point(4 + cursorX, 4), new Point(4 + cursorX, sz.Height - 5)); } }, () => { }); })), desiredSize, sPressed.Map(_ => myId))); }) { this.Text = text; }
public Implementation(PetrolPumpWindow petrolPump) { SComboBox <IPump> logic = new SComboBox <IPump>( new IPump[] { new LifeCyclePump(), new AccumulatePulsesPump(), new ShowDollarsPump(), new ClearSalePump(), new KeypadPump(), new PresetAmountPump() }, p => p.GetType().FullName); petrolPump.LogicComboBoxPlaceholder.Children.Add(logic); STextField textPrice1 = new STextField("2.149") { Width = 100 }; petrolPump.Price1Placeholder.Children.Add(textPrice1); STextField textPrice2 = new STextField("2.341") { Width = 100 }; petrolPump.Price2Placeholder.Children.Add(textPrice2); STextField textPrice3 = new STextField("1.499") { Width = 100 }; petrolPump.Price3Placeholder.Children.Add(textPrice3); Func <string, double> parseDoubleSafe = s => { double n; if (double.TryParse(s, out n)) { return(n); } return(0.0); }; StreamSink <Key> sKey = new StreamSink <Key>(); Dictionary <Key, FrameworkElement> containersByKey = new Dictionary <Key, FrameworkElement> { { Key.One, petrolPump.Keypad1Button }, { Key.Two, petrolPump.Keypad2Button }, { Key.Three, petrolPump.Keypad3Button }, { Key.Four, petrolPump.Keypad4Button }, { Key.Five, petrolPump.Keypad5Button }, { Key.Six, petrolPump.Keypad6Button }, { Key.Seven, petrolPump.Keypad7Button }, { Key.Eight, petrolPump.Keypad8Button }, { Key.Nine, petrolPump.Keypad9Button }, { Key.Zero, petrolPump.Keypad0Button }, { Key.Clear, petrolPump.KeypadClearButton } }; foreach (KeyValuePair <Key, FrameworkElement> containerAndKey in containersByKey) { containerAndKey.Value.MouseDown += async(sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => sKey.Send(containerAndKey.Key)); } }; } CellLoop <UpDown> nozzle1 = new CellLoop <UpDown>(); CellLoop <UpDown> nozzle2 = new CellLoop <UpDown>(); CellLoop <UpDown> nozzle3 = new CellLoop <UpDown>(); Cell <double> calibration = Cell.Constant(0.001); Cell <double> price1 = textPrice1.Text.Map(parseDoubleSafe); Cell <double> price2 = textPrice2.Text.Map(parseDoubleSafe); Cell <double> price3 = textPrice3.Text.Map(parseDoubleSafe); CellSink <Stream <Unit> > csClearSale = new CellSink <Stream <Unit> >(Sodium.Stream.Never <Unit>()); Stream <Unit> sClearSale = csClearSale.SwitchS(); StreamSink <int> sFuelPulses = new StreamSink <int>(); Cell <Outputs> outputs = logic.SelectedItem.Map( pump => pump.Create(new Inputs( Operational.Updates(nozzle1), Operational.Updates(nozzle2), Operational.Updates(nozzle3), sKey, sFuelPulses, calibration, price1, price2, price3, sClearSale))); Cell <Delivery> delivery = outputs.Map(o => o.Delivery).SwitchC(); Cell <string> presetLcd = outputs.Map(o => o.PresetLcd).SwitchC(); Cell <string> saleCostLcd = outputs.Map(o => o.SaleCostLcd).SwitchC(); Cell <string> saleQuantityLcd = outputs.Map(o => o.SaleQuantityLcd).SwitchC(); Cell <string> priceLcd1 = outputs.Map(o => o.PriceLcd1).SwitchC(); Cell <string> priceLcd2 = outputs.Map(o => o.PriceLcd2).SwitchC(); Cell <string> priceLcd3 = outputs.Map(o => o.PriceLcd3).SwitchC(); Stream <Unit> sBeep = outputs.Map(o => o.SBeep).SwitchS(); Stream <Sale> sSaleComplete = outputs.Map(o => o.SSaleComplete).SwitchS(); SoundPlayer beepPlayer = new SoundPlayer(GetResourceStream(@"sounds\beep.wav")); this.listeners.Add(sBeep.Listen(_ => new Thread(() => beepPlayer.PlaySync()) { IsBackground = true }.Start())); SoundPlayer fastRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\fast.wav")); Action stopFast = () => { }; Action playFast = () => { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { fastRumblePlayer.PlayLooping(); mre.WaitOne(); fastRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopFast = () => mre.Set(); }; SoundPlayer slowRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\slow.wav")); Action stopSlow = () => { }; Action playSlow = () => { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { slowRumblePlayer.PlayLooping(); mre.WaitOne(); slowRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopSlow = () => mre.Set(); }; this.listeners.Add(delivery.Changes().Listen(d => { petrolPump.Dispatcher.InvokeIfNecessary(() => { if (d == Delivery.Fast1 || d == Delivery.Fast2 || d == Delivery.Fast3) { playFast(); } else { stopFast(); } if (d == Delivery.Slow1 || d == Delivery.Slow2 || d == Delivery.Slow3) { playSlow(); } else { stopSlow(); } }); })); StackPanel presetLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.PresetPlaceholder.Children.Add(presetLcdStackPanel); this.listeners.Add(presetLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(presetLcdStackPanel, t, 5, true)))); StackPanel saleCostStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.DollarsPlaceholder.Children.Add(saleCostStackPanel); this.listeners.Add(saleCostLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleCostStackPanel, t, 5, true)))); StackPanel saleQuantityLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.LitersPlaceholder.Children.Add(saleQuantityLcdStackPanel); this.listeners.Add(saleQuantityLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleQuantityLcdStackPanel, t, 5, true)))); StackPanel priceLcd1StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel1Placeholder.Children.Add(priceLcd1StackPanel); this.listeners.Add(priceLcd1.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd1StackPanel, t, 5, false)))); StackPanel priceLcd2StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel2Placeholder.Children.Add(priceLcd2StackPanel); this.listeners.Add(priceLcd2.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd2StackPanel, t, 5, false)))); StackPanel priceLcd3StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel3Placeholder.Children.Add(priceLcd3StackPanel); this.listeners.Add(priceLcd3.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd3StackPanel, t, 5, false)))); Dictionary <CellLoop <UpDown>, Image> nozzles = new Dictionary <CellLoop <UpDown>, Image> { { nozzle1, petrolPump.Nozzle1Image }, { nozzle2, petrolPump.Nozzle2Image }, { nozzle3, petrolPump.Nozzle3Image } }; this.listeners.AddRange(nozzles.Select(nozzle => nozzle.Key.Listen(p => petrolPump.Dispatcher.InvokeIfNecessary(() => nozzle.Value.Margin = p == UpDown.Up ? new Thickness(0, 0, 0, 0) : new Thickness(0, 30, 0, 0))))); foreach (KeyValuePair <CellLoop <UpDown>, Image> nozzle in nozzles) { StreamSink <Unit> nozzleClicks = new StreamSink <Unit>(); nozzle.Value.MouseDown += async(sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => nozzleClicks.Send(Unit.Value)); } }; nozzle.Key.Loop(nozzleClicks.Snapshot(nozzle.Key, (_, n) => n == UpDown.Down ? UpDown.Up : UpDown.Down).Hold(UpDown.Down)); } this.listeners.Add(sSaleComplete.Listen(sale => { Task.Run(() => { petrolPump.Dispatcher.InvokeIfNecessary(() => { SaleCompleteDialog dialog = new SaleCompleteDialog( sale.Fuel.ToString(), Formatters.FormatPrice(sale.Price, null), Formatters.FormatSaleCost(sale.Cost), Formatters.FormatSaleQuantity(sale.Quantity)); dialog.Owner = petrolPump; csClearSale.Send(dialog.SOkClicked); dialog.Show(); IListener l = null; // ReSharper disable once RedundantAssignment l = dialog.SOkClicked.Listen(_ => { petrolPump.Dispatcher.InvokeIfNecessary(() => dialog.Close()); // ReSharper disable once AccessToModifiedClosure using (l) { } }); }); }); })); Task.Run(async() => { while (true) { Transaction.RunVoid(() => { switch (delivery.Sample()) { case Delivery.Fast1: case Delivery.Fast2: case Delivery.Fast3: sFuelPulses.Send(40); break; case Delivery.Slow1: case Delivery.Slow2: case Delivery.Slow3: sFuelPulses.Send(2); break; } }); await Task.Delay(200).ConfigureAwait(false); } // ReSharper disable once FunctionNeverReturns }); }
public Implementation(PetrolPumpWindow petrolPump) { SComboBox<IPump> logic = new SComboBox<IPump>( new IPump[] { new LifeCyclePump(), new AccumulatePulsesPump(), new ShowDollarsPump(), new ClearSalePump(), new KeypadPump(), new PresetAmountPump() }, p => p.GetType().FullName); petrolPump.LogicComboBoxPlaceholder.Children.Add(logic); STextField textPrice1 = new STextField("2.149") { Width = 100 }; petrolPump.Price1Placeholder.Children.Add(textPrice1); STextField textPrice2 = new STextField("2.341") { Width = 100 }; petrolPump.Price2Placeholder.Children.Add(textPrice2); STextField textPrice3 = new STextField("1.499") { Width = 100 }; petrolPump.Price3Placeholder.Children.Add(textPrice3); Func<string, double> parseDoubleSafe = s => { double n; if (double.TryParse(s, out n)) { return n; } return 0.0; }; StreamSink<Key> sKey = new StreamSink<Key>(); Dictionary<Key, FrameworkElement> containersByKey = new Dictionary<Key, FrameworkElement> { { Key.One, petrolPump.Keypad1Button }, { Key.Two, petrolPump.Keypad2Button }, { Key.Three, petrolPump.Keypad3Button }, { Key.Four, petrolPump.Keypad4Button }, { Key.Five, petrolPump.Keypad5Button }, { Key.Six, petrolPump.Keypad6Button }, { Key.Seven, petrolPump.Keypad7Button }, { Key.Eight, petrolPump.Keypad8Button }, { Key.Nine, petrolPump.Keypad9Button }, { Key.Zero, petrolPump.Keypad0Button }, { Key.Clear, petrolPump.KeypadClearButton } }; foreach (KeyValuePair<Key, FrameworkElement> containerAndKey in containersByKey) { containerAndKey.Value.MouseDown += async (sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => sKey.Send(containerAndKey.Key)); } }; } CellLoop<UpDown> nozzle1 = new CellLoop<UpDown>(); CellLoop<UpDown> nozzle2 = new CellLoop<UpDown>(); CellLoop<UpDown> nozzle3 = new CellLoop<UpDown>(); Cell<double> calibration = Cell.Constant(0.001); Cell<double> price1 = textPrice1.Text.Map(parseDoubleSafe); Cell<double> price2 = textPrice2.Text.Map(parseDoubleSafe); Cell<double> price3 = textPrice3.Text.Map(parseDoubleSafe); CellSink<Stream<Unit>> csClearSale = new CellSink<Stream<Unit>>(Sodium.Stream.Never<Unit>()); Stream<Unit> sClearSale = csClearSale.SwitchS(); StreamSink<int> sFuelPulses = new StreamSink<int>(); Cell<Outputs> outputs = logic.SelectedItem.Map( pump => pump.Create(new Inputs( Operational.Updates(nozzle1), Operational.Updates(nozzle2), Operational.Updates(nozzle3), sKey, sFuelPulses, calibration, price1, price2, price3, sClearSale))); Cell<Delivery> delivery = outputs.Map(o => o.Delivery).SwitchC(); Cell<string> presetLcd = outputs.Map(o => o.PresetLcd).SwitchC(); Cell<string> saleCostLcd = outputs.Map(o => o.SaleCostLcd).SwitchC(); Cell<string> saleQuantityLcd = outputs.Map(o => o.SaleQuantityLcd).SwitchC(); Cell<string> priceLcd1 = outputs.Map(o => o.PriceLcd1).SwitchC(); Cell<string> priceLcd2 = outputs.Map(o => o.PriceLcd2).SwitchC(); Cell<string> priceLcd3 = outputs.Map(o => o.PriceLcd3).SwitchC(); Stream<Unit> sBeep = outputs.Map(o => o.SBeep).SwitchS(); Stream<Sale> sSaleComplete = outputs.Map(o => o.SSaleComplete).SwitchS(); SoundPlayer beepPlayer = new SoundPlayer(GetResourceStream(@"sounds\beep.wav")); this.listeners.Add(sBeep.Listen(_ => new Thread(() => beepPlayer.PlaySync()) { IsBackground = true }.Start())); SoundPlayer fastRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\fast.wav")); Action stopFast = () => { }; Action playFast = () => { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { fastRumblePlayer.PlayLooping(); mre.WaitOne(); fastRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopFast = () => mre.Set(); }; SoundPlayer slowRumblePlayer = new SoundPlayer(GetResourceStream(@"sounds\slow.wav")); Action stopSlow = () => { }; Action playSlow = () => { ManualResetEvent mre = new ManualResetEvent(false); new Thread(() => { slowRumblePlayer.PlayLooping(); mre.WaitOne(); slowRumblePlayer.Stop(); }) { IsBackground = true }.Start(); stopSlow = () => mre.Set(); }; this.listeners.Add(delivery.Changes().Listen(d => { petrolPump.Dispatcher.InvokeIfNecessary(() => { if (d == Delivery.Fast1 || d == Delivery.Fast2 || d == Delivery.Fast3) { playFast(); } else { stopFast(); } if (d == Delivery.Slow1 || d == Delivery.Slow2 || d == Delivery.Slow3) { playSlow(); } else { stopSlow(); } }); })); StackPanel presetLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.PresetPlaceholder.Children.Add(presetLcdStackPanel); this.listeners.Add(presetLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(presetLcdStackPanel, t, 5, true)))); StackPanel saleCostStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.DollarsPlaceholder.Children.Add(saleCostStackPanel); this.listeners.Add(saleCostLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleCostStackPanel, t, 5, true)))); StackPanel saleQuantityLcdStackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.LitersPlaceholder.Children.Add(saleQuantityLcdStackPanel); this.listeners.Add(saleQuantityLcd.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(saleQuantityLcdStackPanel, t, 5, true)))); StackPanel priceLcd1StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel1Placeholder.Children.Add(priceLcd1StackPanel); this.listeners.Add(priceLcd1.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd1StackPanel, t, 5, false)))); StackPanel priceLcd2StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel2Placeholder.Children.Add(priceLcd2StackPanel); this.listeners.Add(priceLcd2.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd2StackPanel, t, 5, false)))); StackPanel priceLcd3StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; petrolPump.Fuel3Placeholder.Children.Add(priceLcd3StackPanel); this.listeners.Add(priceLcd3.Listen(t => petrolPump.Dispatcher.InvokeIfNecessary(() => petrolPump.SetLcdDigits(priceLcd3StackPanel, t, 5, false)))); Dictionary<CellLoop<UpDown>, Image> nozzles = new Dictionary<CellLoop<UpDown>, Image> { { nozzle1, petrolPump.Nozzle1Image }, { nozzle2, petrolPump.Nozzle2Image }, { nozzle3, petrolPump.Nozzle3Image } }; this.listeners.AddRange(nozzles.Select(nozzle => nozzle.Key.Listen(p => petrolPump.Dispatcher.InvokeIfNecessary(() => nozzle.Value.Margin = p == UpDown.Up ? new Thickness(0, 0, 0, 0) : new Thickness(0, 30, 0, 0))))); foreach (KeyValuePair<CellLoop<UpDown>, Image> nozzle in nozzles) { StreamSink<Unit> nozzleClicks = new StreamSink<Unit>(); nozzle.Value.MouseDown += async (sender, args) => { if (args.LeftButton == MouseButtonState.Pressed) { await Task.Run(() => nozzleClicks.Send(Unit.Value)); } }; nozzle.Key.Loop(nozzleClicks.Snapshot(nozzle.Key, (_, n) => n == UpDown.Down ? UpDown.Up : UpDown.Down).Hold(UpDown.Down)); } this.listeners.Add(sSaleComplete.Listen(sale => { Task.Run(() => { petrolPump.Dispatcher.InvokeIfNecessary(() => { SaleCompleteDialog dialog = new SaleCompleteDialog( sale.Fuel.ToString(), Formatters.FormatPrice(sale.Price, null), Formatters.FormatSaleCost(sale.Cost), Formatters.FormatSaleQuantity(sale.Quantity)); dialog.Owner = petrolPump; csClearSale.Send(dialog.SOkClicked); dialog.Show(); IListener l = null; // ReSharper disable once RedundantAssignment l = dialog.SOkClicked.Listen(_ => { petrolPump.Dispatcher.InvokeIfNecessary(() => dialog.Close()); // ReSharper disable once AccessToModifiedClosure using (l) { } }); }); }); })); Task.Run(async () => { while (true) { Transaction.RunVoid(() => { switch (delivery.Sample()) { case Delivery.Fast1: case Delivery.Fast2: case Delivery.Fast3: sFuelPulses.Send(40); break; case Delivery.Slow1: case Delivery.Slow2: case Delivery.Slow3: sFuelPulses.Send(2); break; } }); await Task.Delay(200).ConfigureAwait(false); } // ReSharper disable once FunctionNeverReturns }); }
private FrTextField(string initText, CellLoop<string> text) : base((size, sMouse, sKey, focus, idSupply) => { Stream<double> sPressed = sMouse.Snapshot(size, (e, mSize) => mSize.Match( s => { MouseButtonEventArgs b = e.Args as MouseButtonEventArgs; Point p = e.GetPosition(); return b != null && b.ChangedButton == MouseButton.Left && b.ButtonState == MouseButtonState.Pressed && p.X >= 2 && p.X < s.Width - 2 && p.Y >= 2 && p.Y < s.Height - 2 ? Maybe.Just(p.X - 2) : Maybe.Nothing<double>(); }, Maybe.Nothing<double>)).FilterMaybe(); CellLoop<int> x = new CellLoop<int>(); long myId = idSupply.Get(); Cell<bool> haveFocus = focus.Map(fId => fId == myId); Typeface typeface = new Typeface(new FontFamily("Helvetica"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); Stream<TextUpdate> sTextUpdate = sKey.Gate(haveFocus).Snapshot(text, (key, txt) => { int xValue = x.Sample(); if (key is BackspaceKeyEvent) { return xValue > 0 ? Maybe.Just(new TextUpdate( txt.Substring(0, xValue - 1) + txt.Substring(xValue), xValue - 1)) : Maybe.Nothing<TextUpdate>(); } StringKeyEvent stringKey = key as StringKeyEvent; if (stringKey == null) { throw new InvalidOperationException("Unexpected type encountered for " + typeof(KeyEvent).FullName + ": " + key.GetType().FullName + "."); } string keyString = stringKey.String; return keyString == "\b" ? Maybe.Nothing<TextUpdate>() : Maybe.Just(new TextUpdate( txt.Substring(0, xValue) + keyString + txt.Substring(xValue), xValue + 1)); }).FilterMaybe(); x.Loop(sPressed.Snapshot(text, (xCoord, txt) => { for (int i = 1; i <= txt.Length; i++) { if (xCoord < FontUtilities.MeasureString(txt.Substring(0, i), typeface, 13).Width) { return i - 1; } } return txt.Length; }) .OrElse(sTextUpdate.Map(tu => tu.NewX)) .Hold(0)); text.Loop(sTextUpdate.Map(tu => tu.Txt).Hold(initText)); Cell<Size> desiredSize = text.Map(txt => { Size s = FontUtilities.MeasureString(txt, typeface, 13); return new Size(s.Width + 14, s.Height + 10); }); return new Output( text.Lift( x, haveFocus, size, (txt, xValue, haveFocusValue, mSize) => new DrawableDelegate(d => { mSize.Match( sz => { d.DrawRectangle(Brushes.White, new Pen(Brushes.Black, 1), new Rect(new Point(2, 2), new Size(sz.Width - 5, sz.Height - 5))); FormattedText t = FontUtilities.GetStandardFormattedText(txt, typeface, 13, Brushes.Black); FormattedText tCursor = FontUtilities.GetStandardFormattedText(txt.Substring(0, xValue), typeface, 13, Brushes.Black); d.DrawText(t, new Point(4, (sz.Height - t.Height) / 2)); if (haveFocusValue) { double cursorX = tCursor.Width; d.DrawLine(new Pen(Brushes.Red, 1), new Point(4 + cursorX, 4), new Point(4 + cursorX, sz.Height - 5)); } }, () => { }); })), desiredSize, sPressed.Map(_ => myId)); }) { this.Text = text; }