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 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 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 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 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 = new CellStreamSink <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 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 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 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 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 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 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); }) { }
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 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; }