Example #1
0
 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));
 }
Example #2
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 = 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);
        }
Example #3
0
        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()) });
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
 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);
 }
Example #7
0
        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;
            });
        }
Example #9
0
            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);
            }
Example #10
0
        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));
            });
        }
Example #11
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);
            }
Example #12
0
 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));
 })
 {
 }
Example #13
0
        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());
        }
Example #14
0
        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)));
        }
Example #15
0
        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);
        }
Example #16
0
        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);
        }
Example #17
0
 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);
 }
Example #18
0
        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));
        }
Example #19
0
        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]);
                }
            });
        }
Example #20
0
 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>()));
 }
Example #21
0
        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);
        }
Example #22
0
        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));
        }
Example #23
0
            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);
            }
Example #24
0
        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();
        }
Example #25
0
        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));
            });
        }
Example #26
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);
        }
Example #27
0
 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()) });
 }
Example #28
0
 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);
     })
 {
 }
Example #29
0
        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);
        }
Example #30
0
        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);
        }
Example #31
0
        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();
        }
Example #32
0
        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
                });
            }
Example #34
0
            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
                });
            }
Example #35
0
        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;
        }