Beispiel #1
0
        public static void ShowMessage(ConsoleString message, Action<DialogButton> resultCallback, bool allowEscapeToCancel = true, int maxHeight = 6, params DialogButton [] buttons)
        {
            if(buttons.Length == 0)
            {
                throw new ArgumentException("You need to specify at least one button");
            }

            ConsolePanel dialogContent = new ConsolePanel();

            Dialog dialog = new Dialog(dialogContent);
            dialog.MaxHeight = maxHeight;
            dialog.AllowEscapeToCancel = allowEscapeToCancel;
            dialog.Cancelled.SubscribeForLifetime(() => { resultCallback(null); }, dialog.LifetimeManager);

            ScrollablePanel messagePanel = dialogContent.Add(new ScrollablePanel()).Fill(padding: new Thickness(0, 0, 1, 3));
            Label messageLabel = messagePanel.ScrollableContent.Add(new Label() { Mode = LabelRenderMode.MultiLineSmartWrap, Text = message }).FillHoriontally(padding: new Thickness(3,3,0,0) );

            StackPanel buttonPanel = dialogContent.Add(new StackPanel() { Margin = 1, Height = 1, Orientation = Orientation.Horizontal }).FillHoriontally(padding: new Thickness(1,0,0,0)).DockToBottom(padding: 1);

            Button firstButton = null;
            foreach (var buttonInfo in buttons)
            {
                var myButtonInfo = buttonInfo;
                Button b = new Button() { Text = buttonInfo.DisplayText };
                b.Pressed.SubscribeForLifetime(() =>
                {
                    ConsoleApp.Current.LayoutRoot.Controls.Remove(dialog);
                    resultCallback(myButtonInfo);
                }, dialog.LifetimeManager);
                buttonPanel.Controls.Add(b);
                firstButton = firstButton ?? b;
            }
            ConsoleApp.Current.LayoutRoot.Controls.Add(dialog);
        }
Beispiel #2
0
 /// <summary>
 /// Creates a new ConsolePanel
 /// </summary>
 public ProtectedConsolePanel()
 {
     this.CanFocus         = false;
     ProtectedPanel        = new ConsolePanel();
     ProtectedPanel.Parent = this;
     ProtectedPanel.Fill();
 }
Beispiel #3
0
        /// <summary>
        /// Creates a new console app given a set of boundaries
        /// </summary>
        /// <param name="w">The width of the app</param>
        /// <param name="h">The height of the app</param>
        public ConsoleApp(int w, int h)
        {
            this.Name              = GetType().Name;
            this.console           = ConsoleProvider.Current;
            consoleWriter          = Console.Out;
            this.lastConsoleWidth  = this.console.BufferWidth;
            this.lastConsoleHeight = this.console.WindowHeight;
            this.observable        = new ObservableObject(this);

            cycleRateMeter = new FrameRateMeter();

            this.EndOfCycle.SubscribeForLifetime(Cycle, this);
            SetFocusOnStart        = true;
            LayoutRoot             = new ConsolePanel(w, h);
            FocusManager           = new FocusManager();
            LayoutRoot.Application = this;
            isFullScreen           = false;
            FocusManager.SubscribeForLifetime(nameof(FocusManager.FocusedControl), () => RequestPaintAsync(), this);
            LayoutRoot.Controls.BeforeAdded.SubscribeForLifetime((c) => { c.Application = this; c.BeforeAddedToVisualTreeInternal(); }, this);
            LayoutRoot.Controls.BeforeRemoved.SubscribeForLifetime((c) => { c.BeforeRemovedFromVisualTreeInternal(); }, this);
            LayoutRoot.Controls.Added.SubscribeForLifetime(ControlAddedToVisualTree, this);
            LayoutRoot.Controls.Removed.SubscribeForLifetime(ControlRemovedFromVisualTree, this);
            WindowResized.SubscribeForLifetime(HandleDebouncedResize, this);
            this.LoopStarted.SubscribeOnce(() => _current = this);
            this.EndOfCycle.SubscribeForLifetime(DrainPaints, this);
        }
Beispiel #4
0
        private static void ParsePanel(ParserContext context, ConsolePanel panel)
        {
            var myElement = context.CurrentElement;

            context.CurrentControl = panel;
            ParseControlAttributes(panel, context);

            foreach (var childElement in context.CurrentElement.Elements)
            {
                context.CurrentElement = childElement;
                var childControl = CreateControl(context);
                context.CurrentControl = childControl;
                panel.Add(childControl);

                if (childControl is ConsolePanel)
                {
                    ParsePanel(context, childControl as ConsolePanel);
                }
                else
                {
                    ParseControlAttributes(childControl, context);
                }
            }

            context.CurrentElement = myElement;
            context.CurrentControl = panel;
        }
Beispiel #5
0
 private void InitLayout()
 {
     layout = ProtectedPanel.Add(new GridLayout(new GridLayoutOptions()
     {
         Columns = new List <GridColumnDefinition>()
         {
             new GridColumnDefinition()
             {
                 Type = GridValueType.Pixels, Width = 15
             },
             new GridColumnDefinition()
             {
                 Type = GridValueType.RemainderValue, Width = 1
             },
         },
         Rows = new List <GridRowDefinition>()
         {
             new GridRowDefinition()
             {
                 Type = GridValueType.Pixels, Height = 3
             },
             new GridRowDefinition()
             {
                 Type = GridValueType.RemainderValue, Height = 1
             }
         }
     })).Fill();
     layout.RefreshLayout();
     commandBar   = layout.Add(new ConsolePanel(), 0, 0, columnSpan: 2);
     framePanel   = layout.Add(new ConsolePanel(), 0, 1);
     previewPanel = layout.Add(new ConsolePanel(), 1, 1);
     layout.RefreshLayout();
 }
Beispiel #6
0
        internal override ConsoleControl GetContent()
        {
            ConsolePanel content = new ConsolePanel();

            content.Width  = ConsoleApp.Current.LayoutRoot.Width / 2;
            content.Height = ConsoleApp.Current.LayoutRoot.Height / 2;

            Label messageLabel = content.Add(new Label()
            {
                Text = Message, X = 2, Y = 2
            });

            TextBox = TextBox ?? new TextBox()
            {
                Foreground = ConsoleColor.Black, Background = ConsoleColor.White
            };
            content.Add(TextBox).CenterHorizontally();
            TextBox.Y = 4;

            content.SynchronizeForLifetime(nameof(content.Bounds), () => { TextBox.Width = content.Width - 4; }, content);

            TextBox.KeyInputReceived.SubscribeForLifetime((k) =>
            {
                if (k.Key == ConsoleKey.Enter)
                {
                    Dialog.Dismiss();
                }
            }, TextBox);

            TextBox.AddedToVisualTree.SubscribeOnce(() => TextBox.Application.QueueAction(() => TextBox.TryFocus()));
            return(content);
        }
Beispiel #7
0
        private void SetupMinimumSizeExperience()
        {
            ConsolePanel   shield = null;
            ConsoleControl min    = null;

            min = ProtectedPanel.Add(new MinimumSizeEnforcerPanel(new MinimumSizeEnforcerPanelOptions()
            {
                MinWidth            = MinWidth,
                MinHeight           = MinHeight,
                OnMinimumSizeNotMet = () =>
                {
                    if (min == null)
                    {
                        return;
                    }
                    min.IsVisible = false;
                    shield        = ProtectedPanel.Add(new ConsolePanel()
                    {
                        Background = Foreground
                    }).Fill();
                    var date = new DateTime(Options.Year, Options.Month, 1);
                    shield.Add(new Label()
                    {
                        Text = date.ToString("Y").ToConsoleString(Background, Foreground)
                    }).CenterBoth();
                },
                OnMinimumSizeMet = () => shield?.Dispose()
            })).Fill();
        }
Beispiel #8
0
        /// <summary>
        /// Visits every control in the control tree, recursively, using the visit action provided
        /// </summary>
        /// <param name="visitAction">the visitor function that will be run for each child control, the function can return true if it wants to stop further visitation</param>
        /// <param name="root">set to null, used for recursion</param>
        /// <returns>true if the visitation was short ciruited by a visitor, false otherwise</returns>
        public bool VisitControlTree(Func <ConsoleControl, bool> visitAction, ConsolePanel root = null)
        {
            bool shortCircuit = false;

            root = root ?? this;

            foreach (var child in root.Controls)
            {
                shortCircuit = visitAction(child);
                if (shortCircuit)
                {
                    return(true);
                }

                if (child is ConsolePanel)
                {
                    shortCircuit = VisitControlTree(visitAction, child as ConsolePanel);
                    if (shortCircuit)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Beispiel #9
0
        internal override ConsoleControl GetContent()
        {
            if (Options == null || Options.Count == 0)
            {
                throw new ArgumentException("You need to specify at least one button");
            }

            if (Mode == DialogButtonsPresentationMode.Buttons)
            {
                ConsolePanel    dialogContent = new ConsolePanel();
                ScrollablePanel messagePanel  = dialogContent.Add(new ScrollablePanel()).Fill(padding: new Thickness(0, 0, 1, 3));
                Label           messageLabel  = messagePanel.ScrollableContent.Add(new Label()
                {
                    Mode = LabelRenderMode.MultiLineSmartWrap, Text = Message
                }).FillHorizontally(padding: new Thickness(3, 3, 0, 0));
                StackPanel buttonPanel = dialogContent.Add(new StackPanel()
                {
                    Margin = 1, Height = 1, Orientation = Orientation.Horizontal
                }).FillHorizontally(padding: new Thickness(1, 0, 0, 0)).DockToBottom(padding: 1);

                foreach (var option in Options)
                {
                    var    myOption = option;
                    Button b        = new Button()
                    {
                        Text = option.DisplayText
                    };
                    b.Pressed.SubscribeOnce(() =>
                    {
                        SelectedOption = myOption;
                        Dialog.Dismiss();
                    });
                    buttonPanel.Controls.Add(b);
                }

                buttonPanel.Controls.Last().AddedToVisualTree.SubscribeOnce(() => buttonPanel.Application.QueueAction(() => { buttonPanel.Controls.Last().TryFocus(); }));
                return(dialogContent);
            }
            else
            {
                Grid optionsGrid = new Grid(Options.Select(o => o as object).ToList());
                optionsGrid.MoreDataMessage  = "More options below".ToYellow();
                optionsGrid.EndOfDataMessage = "End of menu";

                optionsGrid.VisibleColumns.Remove(optionsGrid.VisibleColumns.Where(v => v.ColumnName.ToString() == nameof(DialogOption.Id)).Single());
                optionsGrid.VisibleColumns[0].WidthPercentage   = 1;
                optionsGrid.VisibleColumns[0].ColumnDisplayName = Message.IsUnstyled ? Message.ToYellow() : Message;
                optionsGrid.VisibleColumns[0].OverflowBehavior  = new TruncateOverflowBehavior();
                (optionsGrid.VisibleColumns[0].OverflowBehavior as TruncateOverflowBehavior).ColumnWidth = 0;
                optionsGrid.SelectedItemActivated += () =>
                {
                    this.SelectedOption = optionsGrid.SelectedItem as DialogOption;
                    Dialog.Dismiss();
                };

                optionsGrid.AddedToVisualTree.SubscribeOnce(() => optionsGrid.Application.QueueAction(() => { optionsGrid.TryFocus(); }));

                return(optionsGrid);
            }
        }
Beispiel #10
0
        public static void ShowRichTextInput(ConsoleString message, Action <ConsoleString> resultCallback, Action cancelCallback = null, bool allowEscapeToCancel = true, int maxHeight = 12, TextBox inputBox = null, ConsoleString initialValue = null)
        {
            ConsoleApp.AssertAppThread();
            if (ConsoleApp.Current == null)
            {
                throw new InvalidOperationException("There is no console app running");
            }

            ConsolePanel content = new ConsolePanel();

            content.Width  = ConsoleApp.Current.LayoutRoot.Width / 2;
            content.Height = ConsoleApp.Current.LayoutRoot.Height / 2;

            var dialog = new Dialog(content);

            dialog.MaxHeight           = maxHeight;
            dialog.AllowEscapeToCancel = allowEscapeToCancel;
            dialog.Cancelled.SubscribeForLifetime(() => { if (cancelCallback != null)
                                                          {
                                                              cancelCallback();
                                                          }
                                                  }, dialog);

            Label messageLabel = content.Add(new Label()
            {
                Text = message, X = 2, Y = 2
            });

            if (inputBox == null)
            {
                inputBox = new TextBox()
                {
                    Foreground = ConsoleColor.Black, Background = ConsoleColor.White
                };
            }

            if (initialValue != null)
            {
                inputBox.Value = initialValue;
            }

            content.Add(inputBox).CenterHorizontally();
            inputBox.Y = 4;

            content.SynchronizeForLifetime(nameof(Bounds), () => { inputBox.Width = content.Width - 4; }, content);

            inputBox.KeyInputReceived.SubscribeForLifetime((k) =>
            {
                if (k.Key == ConsoleKey.Enter)
                {
                    ConsoleApp.Current.LayoutRoot.Controls.Remove(dialog);
                    resultCallback(inputBox.Value);
                }
            }, inputBox);

            ConsoleApp.Current.LayoutRoot.Controls.Add(dialog);
            inputBox.TryFocus();
        }
Beispiel #11
0
 /// <summary>
 /// Creates a new ConsolePanel
 /// </summary>
 public ProtectedConsolePanel()
 {
     this.CanFocus         = false;
     ProtectedPanel        = new ConsolePanel();
     ProtectedPanel.Parent = this;
     ProtectedPanel.Fill();
     this.SubscribeForLifetime(nameof(Background), () => ProtectedPanel.Background = Background, this);
     this.SubscribeForLifetime(nameof(Foreground), () => ProtectedPanel.Foreground = Foreground, this);
 }
Beispiel #12
0
        public static ConsolePanel CreatePanelWithCenteredLabel(ConsoleString str)
        {
            var ret = new ConsolePanel();

            ret.Add(new Label()
            {
                Text = str
            }).CenterBoth();
            return(ret);
        }
        public ScrollablePanel()
        {
            ScrollableContent = Add(new ConsolePanel() { IsVisible = false }).Fill();

            verticalScrollbar = Add(new Scrollbar(Orientation.Vertical) { Width = 1 }).DockToRight();
            horizontalScrollbar = Add(new Scrollbar(Orientation.Horizontal) { Height = 1 }).DockToBottom();

            AddedToVisualTree.SubscribeForLifetime(OnAddedToVisualTree, this.LifetimeManager);
            RemovedFromVisualTree.SubscribeForLifetime(OnRemovedFromVisualTree, this.LifetimeManager);
        }
Beispiel #14
0
 private void ComposeLoadingUX()
 {
     loadingPanel = ProtectedPanel.Add(new ConsolePanel()
     {
         ZIndex = int.MaxValue
     }).Fill();
     loadingPanel.Add(new Label()
     {
         Text = Options.LoadingMessage
     }).CenterBoth();
 }
        public static ConsolePanel ParsePanel(string markup, object viewModel = null)
        {
            ParserContext context = new ParserContext()
            {
                RootElement = new XmlElement(markup),
                RootViewModel = viewModel,
                CurrentViewModel = viewModel,
            };

            var panel = new ConsolePanel();
            ParsePanel(context, panel);
            return panel;
        }
Beispiel #16
0
        public static List <ConsoleControl> TraverseControlTree(ConsolePanel toTraverse)
        {
            List <ConsoleControl> ret = new List <ConsoleControl>();

            foreach (var control in toTraverse.Controls)
            {
                if (control is ConsolePanel)
                {
                    ret.AddRange(TraverseControlTree(control as ConsolePanel));
                }
                ret.Add(control);
            }
            return(ret);
        }
Beispiel #17
0
        private static List <ConsoleControl> GetDescendents(ConsolePanel toTraverse)
        {
            List <ConsoleControl> ret = new List <ConsoleControl>();

            foreach (var control in toTraverse.Controls)
            {
                if (control is ConsolePanel)
                {
                    ret.AddRange(GetDescendents(control as ConsolePanel));
                }
                ret.Add(control);
            }
            return(ret);
        }
Beispiel #18
0
        public static ConsolePanel ParsePanel(string markup, object viewModel = null)
        {
            ParserContext context = new ParserContext()
            {
                RootElement      = new XmlElement(markup),
                RootViewModel    = viewModel,
                CurrentViewModel = viewModel,
            };

            var panel = new ConsolePanel();

            ParsePanel(context, panel);
            return(panel);
        }
Beispiel #19
0
 private void ComposeLoadingUX()
 {
     using (var modifyLock = Unlock())
     {
         loadingPanel = Add(new ConsolePanel()
         {
             ZIndex = int.MaxValue
         }).Fill();
         loadingPanel.Add(new Label()
         {
             Text = Options.LoadingMessage
         }).CenterBoth();
     }
 }
Beispiel #20
0
        public ConsoleApp(int x, int y, int w, int h)
        {
            Bitmap     = new ConsoleBitmap(x, y, w, h);
            LayoutRoot = new ConsolePanel {
                Width = w, Height = h
            };
            LayoutRoot.Application     = this;
            focusableControls          = new List <ConsoleControl>();
            focusIndex                 = -1;
            ExitOnEscapeCharacter      = true;
            LayoutRoot.Controls.Added += (c) =>
            {
                c.Application = this;
                if (c.CanFocus)
                {
                    focusableControls.Add(c);
                }

                if (c is ConsolePanel)
                {
                    var children = TraverseControlTree(c as ConsolePanel);
                    focusableControls.AddRange(children.Where(child => child.CanFocus));
                    focusableControls = focusableControls.Distinct().ToList();
                    foreach (var child in children)
                    {
                        child.Application = this;
                    }
                }
            };

            LayoutRoot.Controls.Removed += (c) =>
            {
                c.Application = null;
                if (c.CanFocus)
                {
                    focusableControls.Remove(c);
                }

                if (c is ConsolePanel)
                {
                    var children = TraverseControlTree(c as ConsolePanel);
                    foreach (var child in children)
                    {
                        focusableControls.Remove(child);
                        child.Application = null;
                    }
                }
            };
        }
Beispiel #21
0
        private void Decompose()
        {
            for (var i = 0; i < recomposableControls.Count; i++)
            {
                gridLayout.Remove(recomposableControls[i]);
            }
            recomposableControls.Clear();
            ControlsByRow.Clear();

            if (loadingPanel != null)
            {
                ProtectedPanel.Controls.Remove(loadingPanel);
                loadingPanel = null;
            }
        }
Beispiel #22
0
 /// <summary>
 /// Creates a new console app given a set of boundaries
 /// </summary>
 /// <param name="x">The left position on the target console to bound this app</param>
 /// <param name="y">The right position on the target console to bound this app</param>
 /// <param name="w">The width of the app</param>
 /// <param name="h">The height of the app</param>
 public ConsoleApp(int x, int y, int w, int h)
     : base(ConsoleProvider.Current)
 {
     SetFocusOnStart = true;
     Theme = new Theme();
     Bitmap = new ConsoleBitmap(x, y, w, h);
     LayoutRoot = new ConsolePanel { Width = w, Height = h };
     FocusManager = new FocusManager();
     LayoutRoot.Application = this;
     AutoFillOnConsoleResize = false;
     FocusManager.SubscribeForLifetime(nameof(FocusManager.FocusedControl), Paint, LifetimeManager);
     LayoutRoot.Controls.BeforeAdded.SubscribeForLifetime((c) => { c.Application = this; c.BeforeAddedToVisualTreeInternal(); }, LifetimeManager);
     LayoutRoot.Controls.BeforeRemoved.SubscribeForLifetime((c) => { c.BeforeRemovedFromVisualTreeInternal(); }, LifetimeManager);
     LayoutRoot.Controls.Added.SubscribeForLifetime(ControlAddedToVisualTree, LifetimeManager);
     LayoutRoot.Controls.Removed.SubscribeForLifetime(ControlRemovedFromVisualTree, LifetimeManager);
     WindowResized.SubscribeForLifetime(HandleDebouncedResize, LifetimeManager);
 }
Beispiel #23
0
        public static void ShowMessage(ConsoleString message, Action <DialogButton> resultCallback, bool allowEscapeToCancel = true, int maxHeight = 10, params DialogButton [] buttons)
        {
            ConsoleApp.AssertAppThread();
            if (buttons.Length == 0)
            {
                throw new ArgumentException("You need to specify at least one button");
            }

            ConsolePanel dialogContent = new ConsolePanel();

            Dialog dialog = new Dialog(dialogContent);

            dialog.MaxHeight           = maxHeight;
            dialog.AllowEscapeToCancel = allowEscapeToCancel;
            dialog.Cancelled.SubscribeForLifetime(() => { resultCallback(null); }, dialog);

            ScrollablePanel messagePanel = dialogContent.Add(new ScrollablePanel()).Fill(padding: new Thickness(0, 0, 1, 3));
            Label           messageLabel = messagePanel.ScrollableContent.Add(new Label()
            {
                Mode = LabelRenderMode.MultiLineSmartWrap, Text = message
            }).FillHorizontally(padding: new Thickness(3, 3, 0, 0));

            StackPanel buttonPanel = dialogContent.Add(new StackPanel()
            {
                Margin = 1, Height = 1, Orientation = Orientation.Horizontal
            }).FillHorizontally(padding: new Thickness(1, 0, 0, 0)).DockToBottom(padding: 1);

            Button firstButton = null;

            foreach (var buttonInfo in buttons)
            {
                var    myButtonInfo = buttonInfo;
                Button b            = new Button()
                {
                    Text = buttonInfo.DisplayText
                };
                b.Pressed.SubscribeForLifetime(() =>
                {
                    ConsoleApp.Current.LayoutRoot.Controls.Remove(dialog);
                    resultCallback(myButtonInfo);
                }, dialog);
                buttonPanel.Controls.Add(b);
                firstButton = firstButton ?? b;
            }
            ConsoleApp.Current.LayoutRoot.Controls.Add(dialog);
        }
Beispiel #24
0
 /// <summary>
 /// Creates a new console app given a set of boundaries
 /// </summary>
 /// <param name="x">The left position on the target console to bound this app</param>
 /// <param name="y">The right position on the target console to bound this app</param>
 /// <param name="w">The width of the app</param>
 /// <param name="h">The height of the app</param>
 public ConsoleApp(int x, int y, int w, int h) : base(ConsoleProvider.Current)
 {
     SetFocusOnStart = true;
     Bitmap          = new ConsoleBitmap(x, y, w, h);
     LayoutRoot      = new ConsolePanel {
         Width = w, Height = h
     };
     FocusManager            = new FocusManager();
     LayoutRoot.Application  = this;
     AutoFillOnConsoleResize = false;
     FocusManager.SubscribeForLifetime(nameof(FocusManager.FocusedControl), () => Paint(), this);
     LayoutRoot.Controls.BeforeAdded.SubscribeForLifetime((c) => { c.Application = this; c.BeforeAddedToVisualTreeInternal(); }, this);
     LayoutRoot.Controls.BeforeRemoved.SubscribeForLifetime((c) => { c.BeforeRemovedFromVisualTreeInternal(); }, this);
     LayoutRoot.Controls.Added.SubscribeForLifetime(ControlAddedToVisualTree, this);
     LayoutRoot.Controls.Removed.SubscribeForLifetime(ControlRemovedFromVisualTree, this);
     WindowResized.SubscribeForLifetime(HandleDebouncedResize, this);
 }
Beispiel #25
0
        private void Decompose()
        {
            for (var i = 0; i < recomposableControls.Count; i++)
            {
                gridLayout.Remove(recomposableControls[i]);
            }
            recomposableControls.Clear();
            ControlsByRow.Clear();

            if (loadingPanel != null)
            {
                using (var modifyLock = Unlock())
                {
                    Controls.Remove(loadingPanel);
                    loadingPanel = null;
                }
            }
        }
Beispiel #26
0
 /// <summary>
 /// Creates a new console app given a set of boundaries
 /// </summary>
 /// <param name="x">The left position on the target console to bound this app</param>
 /// <param name="y">The right position on the target console to bound this app</param>
 /// <param name="w">The width of the app</param>
 /// <param name="h">The height of the app</param>
 public ConsoleApp(int x, int y, int w, int h)
 {
     SetFocusOnStart = true;
     Theme           = new Theme();
     Bitmap          = new ConsoleBitmap(x, y, w, h);
     MessagePump     = new CliMessagePump(Bitmap.Console, KeyPressed);
     LayoutRoot      = new ConsolePanel {
         Width = w, Height = h
     };
     FocusManager            = new FocusManager();
     LayoutRoot.Application  = this;
     AutoFillOnConsoleResize = false;
     FocusManager.SubscribeForLifetime(nameof(FocusManager.FocusedControl), Paint, LifetimeManager);
     LayoutRoot.Controls.BeforeAdded.SubscribeForLifetime((c) => { c.Application = this; c.BeforeAddedToVisualTreeInternal(); }, LifetimeManager);
     LayoutRoot.Controls.BeforeRemoved.SubscribeForLifetime((c) => { c.BeforeRemovedFromVisualTreeInternal(); }, LifetimeManager);
     LayoutRoot.Controls.Added.SubscribeForLifetime(ControlAddedToVisualTree, LifetimeManager);
     LayoutRoot.Controls.Removed.SubscribeForLifetime(ControlRemovedFromVisualTree, LifetimeManager);
     MessagePump.WindowResized.SubscribeForLifetime(HandleDebouncedResize, LifetimeManager);
 }
Beispiel #27
0
        private void PopulateDayOfWeekLabels()
        {
            var dayLabels = new List <Label>();

            for (var day = 0; day < 7; day++)
            {
                var dayOfWeek = (DayOfWeek)day;
                var panel     = new ConsolePanel();
                panel.Background = Foreground;
                var label = panel.Add(new Label()
                {
                    Mode = LabelRenderMode.ManualSizing, Background = Foreground
                }).FillHorizontally(padding: new Thickness(day == 0 ? 2 : 0, 0, 0, 0)).CenterVertically();
                dayLabels.Add(label);
                gridLayout.Add(panel, day, 0);
                Func <int> smallestDayLabelWidth = () => dayLabels.Select(l => l.Width).Min();
                this.SynchronizeForLifetime(nameof(Bounds), () => label.Text = GetDayOfWeekDisplay(dayOfWeek, smallestDayLabelWidth()), this);
            }
        }
Beispiel #28
0
        public ScrollablePanel()
        {
            ScrollableContent = Add(new ConsolePanel()
            {
                IsVisible = false
            }).Fill();

            verticalScrollbar = Add(new Scrollbar(Orientation.Vertical)
            {
                Width = 1
            }).DockToRight();
            horizontalScrollbar = Add(new Scrollbar(Orientation.Horizontal)
            {
                Height = 1
            }).DockToBottom();

            AddedToVisualTree.SubscribeForLifetime(OnAddedToVisualTree, this.LifetimeManager);
            RemovedFromVisualTree.SubscribeForLifetime(OnRemovedFromVisualTree, this.LifetimeManager);
        }
Beispiel #29
0
        public ScrollablePanel()
        {
            ScrollableContent = Add(new ConsolePanel()
            {
                IsVisible = true
            }).Fill();
            SynchronizeForLifetime(nameof(Background), () => ScrollableContent.Background = Background, this);
            verticalScrollbar = Add(new Scrollbar(Orientation.Vertical)
            {
                Width = 1
            }).DockToRight();
            horizontalScrollbar = Add(new Scrollbar(Orientation.Horizontal)
            {
                Height = 1
            }).DockToBottom();

            AddedToVisualTree.SubscribeForLifetime(OnAddedToVisualTree, this);
            RemovedFromVisualTree.SubscribeForLifetime(OnRemovedFromVisualTree, this);
        }
        public void ConsoleAppLifecycleTestBasic()
        {
            ConsoleProvider.Current = new CliUnitTestConsole();
            ConsoleApp app = new ConsoleApp(0, 0, 80, 10);

            int addCounter = 0, removeCounter = 0;

            app.ControlAdded.SubscribeForLifetime((c) => { addCounter++; }, app.LifetimeManager);
            app.ControlRemoved.SubscribeForLifetime((c) => { removeCounter++; }, app.LifetimeManager);
            app.LayoutRoot.Id = "LayoutRoot";
            ConsolePanel panel = app.LayoutRoot.Add(new ConsolePanel() { Id = "First panel" });
            // direct child
            Assert.AreEqual(1, addCounter);
            Assert.AreEqual(0, removeCounter);

            var button = panel.Add(new Button() { Id = "Button on first panel" });

            // grandchild
            Assert.AreEqual(2, addCounter);
            Assert.AreEqual(0, removeCounter);

            var innerPanel = new ConsolePanel() { Id="InnerPanel" };
            var innerInnerPanel = innerPanel.Add(new ConsolePanel() { Id = "Inner Inner Panel"});

            // no change since not added to the app yet
            Assert.AreEqual(2, addCounter);
            Assert.AreEqual(0, removeCounter);

            panel.Add(innerPanel);

            // both child and grandchild found on add
            Assert.AreEqual(4, addCounter);
            Assert.AreEqual(0, removeCounter);

            // remove a nested child
            innerPanel.Controls.Remove(innerInnerPanel);
            Assert.AreEqual(4, addCounter);
            Assert.AreEqual(1, removeCounter);

            app.LayoutRoot.Controls.Clear();
            Assert.AreEqual(4, addCounter);
            Assert.AreEqual(4, removeCounter);
        }
Beispiel #31
0
        /// <summary>
        /// create content panels for each cell so that other pieces of code don't need to worry about
        /// the grid layout implementation
        /// </summary>
        private void InitCellContainers()
        {
            for (var x = 0; x < gridLayout.Options.Columns.Count; x++)
            {
                // start at 1 since the first row is for day of week labels
                for (var y = 1; y < gridLayout.Options.Rows.Count; y++)
                {
                    var key        = GetKeyForCoordinates(y, x);
                    var outerPanel = new ConsolePanel()
                    {
                        Background = Foreground
                    };
                    var innerPanel = outerPanel.Add(new ConsolePanel()
                    {
                        Background = Foreground
                    }).Fill(padding: new Thickness(x == 0 ? 2 : 0, 1, 0, 1));
                    dateCells.Add(key, innerPanel);
                    gridLayout.Add(outerPanel, x, y);

                    // the first row gets an outer border
                    if (x == 0)
                    {
                        outerPanel.Add(new ConsolePanel()
                        {
                            Width = 2, Background = Foreground
                        }).FillVertically().DockToLeft();
                    }

                    outerPanel.Add(new ConsolePanel()
                    {
                        Width = 2, Background = Foreground
                    }).FillVertically().DockToRight();
                    outerPanel.Add(new ConsolePanel()
                    {
                        Height = 1, Background = Foreground
                    }).FillHorizontally().DockToBottom();
                }
            }
            gridLayout.RefreshLayout();
        }
Beispiel #32
0
        public ConsoleApp(int x, int y, int w, int h)
        {
            Bitmap = new ConsoleBitmap(x,y, w, h);
            LayoutRoot = new ConsolePanel { Width = w, Height = h };
            LayoutRoot.Application = this;
            focusableControls = new List<ConsoleControl>();
            focusIndex = -1;
            ExitOnEscapeCharacter = true;
            LayoutRoot.Controls.Added += (c) =>
            {
                c.Application = this;
                if (c.CanFocus) focusableControls.Add(c);

                if (c is ConsolePanel)
                {
                    var children = TraverseControlTree(c as ConsolePanel);
                    focusableControls.AddRange(children.Where(child => child.CanFocus));
                    focusableControls = focusableControls.Distinct().ToList();
                    foreach (var child in children) child.Application = this;
                }
            };

            LayoutRoot.Controls.Removed += (c) =>
            {
                c.Application = null;
                if (c.CanFocus) focusableControls.Remove(c);

                if (c is ConsolePanel)
                {
                    var children = TraverseControlTree(c as ConsolePanel);
                    foreach (var child in children)
                    {
                        focusableControls.Remove(child);
                        child.Application = null;
                    }
                }
            };
        }
Beispiel #33
0
        private void ComposePager()
        {
            pagerContainer = gridLayout.Add(new ConsolePanel(), 0, Height - 1, gridLayout.Options.Columns.Count, 1);
            recomposableControls.Add(pagerContainer);
            pager           = pagerContainer.Add(new RandomAccessPager()).CenterHorizontally();
            pager.IsVisible = Options.ShowPager;
            pager.FirstPageButton.Pressed.SubscribeForLifetime(FirstPageClicked.Fire, pager);
            pager.PreviousPageButton.Pressed.SubscribeForLifetime(PreviousPageClicked.Fire, pager);
            pager.NextPageButton.Pressed.SubscribeForLifetime(NextPageClicked.Fire, pager);
            pager.LastPageButton.Pressed.SubscribeForLifetime(LastPageClicked.Fire, pager);
            pager.FirstPageButton.CanFocus    = Options.PagerState.CanGoBackwards;
            pager.PreviousPageButton.CanFocus = Options.PagerState.CanGoBackwards;
            pager.NextPageButton.CanFocus     = Options.PagerState.CanGoForwards;
            pager.LastPageButton.CanFocus     = Options.PagerState.CanGoForwards;
            pager.CurrentPageLabel.Text       = Options.PagerState.CurrentPageLabelValue;
            if (Options.PagerState.AllowRandomAccess == false)
            {
                pager.Controls.Remove(pager.LastPageButton);
            }

            if (firstButtonFocused)
            {
                pager.FirstPageButton.TryFocus();
            }
            else if (previousButtonFocused)
            {
                pager.PreviousPageButton.TryFocus();
            }
            else if (nextButtonFocused)
            {
                pager.NextPageButton.TryFocus();
            }
            else if (lastButtonFocused)
            {
                pager.LastPageButton.TryFocus();
            }
        }
Beispiel #34
0
 public Border2(ConsolePanel content = null)
 {
     this.Content = content ?? new ConsolePanel();
     this.Add(Content).Fill(padding: new Thickness(2, 2, 1, 1));
 }
Beispiel #35
0
        private List<ConsoleControl> TraverseControlTree(ConsolePanel toTraverse)
        {
            List<ConsoleControl> ret = new List<ConsoleControl>();
            foreach (var control in toTraverse.Controls)
            {
                if (control is ConsolePanel)
                {
                    ret.AddRange(TraverseControlTree(control as ConsolePanel));
                }
                ret.Add(control);

            }
            return ret;
        }
Beispiel #36
0
        public static void ShowRichTextInput(ConsoleString message, Action<ConsoleString> resultCallback, Action cancelCallback = null, bool allowEscapeToCancel = true, int maxHeight = 12, TextBox inputBox = null)
        {
            if (ConsoleApp.Current == null)
            {
                throw new InvalidOperationException("There is no console app running");
            }

            ConsolePanel content = new ConsolePanel();

            content.Width = ConsoleApp.Current.LayoutRoot.Width / 2;
            content.Height = ConsoleApp.Current.LayoutRoot.Height / 2;

            var dialog = new Dialog(content);
            dialog.MaxHeight = maxHeight;
            dialog.AllowEscapeToCancel = allowEscapeToCancel;
            dialog.Cancelled.SubscribeForLifetime(() => { if (cancelCallback != null) cancelCallback(); }, dialog.LifetimeManager);

            Label messageLabel = content.Add(new Label() { Text = message,  X = 2, Y = 2 });
            if (inputBox == null)
            {
                inputBox = new TextBox() { Foreground = ConsoleColor.Black, Background = ConsoleColor.White };
            }

            content.Add(inputBox).CenterHorizontally();
            inputBox.Y = 4;

            content.SynchronizeForLifetime(nameof(Bounds), () => { inputBox.Width = content.Width - 4; }, content.LifetimeManager);

            inputBox.KeyInputReceived.SubscribeForLifetime((k) =>
            {
                if (k.Key == ConsoleKey.Enter)
                {
                    resultCallback(inputBox.Value);
                    ConsoleApp.Current.LayoutRoot.Controls.Remove(dialog);
                }
            }, inputBox.LifetimeManager);

            ConsoleApp.Current.LayoutRoot.Controls.Add(dialog);
            inputBox.TryFocus();
        }
Beispiel #37
0
        /// <summary>
        /// Shows a dialog on top of the current ConsoleApp.
        /// </summary>
        /// <param name="contentFactory">A callback where you are given a handle that can be used to configure the dialog.
        /// It also has a method that lets you close the dialog. This callback should return the dialog content.</param>
        public static async void Show(Func <DialogHandle, ConsolePanel> contentFactory, ConsolePanel parent = null, bool pushPop = true)
        {
            parent = parent ?? ConsoleApp.Current.LayoutRoot;
            using (var dialogLt = new Lifetime())
            {
                if (pushPop)
                {
                    ConsoleApp.Current.FocusManager.Push();
                    dialogLt.OnDisposed(ConsoleApp.Current.FocusManager.Pop);
                }
                var handle  = new DialogHandle();
                var content = contentFactory(handle);
                content.IsVisible = false;
                var dialogContainer = parent.Add(new BorderPanel(content)
                {
                    ZIndex = int.MaxValue, BorderColor = handle.BorderColor, Background = content.Background, Width = 1, Height = 1
                }).CenterBoth();
                await Forward(300, dialogLt, percentage => dialogContainer.Width  = Math.Max(1, (int)Math.Round((4 + content.Width) * percentage)));
                await Forward(200, dialogLt, percentage => dialogContainer.Height = Math.Max(1, (int)Math.Round((2 + content.Height) * percentage)));

                content.IsVisible = true;
                await handle.CallerLifetime.AwaitEndOfLifetime();

                content.IsVisible = false;
                await Reverse(150, dialogLt, percentage => dialogContainer.Height = Math.Max(1, (int)Math.Floor((2 + content.Height) * percentage)));

                await Task.Delay(200);
                await Reverse(200, dialogLt, percentage => dialogContainer.Width = Math.Max(1, (int)Math.Round((4 + content.Width) * percentage)));

                dialogContainer.Dispose();
            }
        }
Beispiel #38
0
        private void InitFramePanel()
        {
            // vertical divider
            framePanel.Add(new ConsolePanel()
            {
                Width = 1, Background = RGB.White
            }).DockToRight().FillVertically();

            var options = new ListGridOptions <InMemoryConsoleBitmapFrame>()
            {
                DataSource = new SyncList <InMemoryConsoleBitmapFrame>(animation.Frames),
                Columns    = new List <ListGridColumnDefinition <InMemoryConsoleBitmapFrame> >()
                {
                    new ListGridColumnDefinition <InMemoryConsoleBitmapFrame>()
                    {
                        Width     = framePanel.Width - 2,
                        Type      = GridValueType.Pixels,
                        Formatter = f => new Label()
                        {
                            Text = $"Frame {animation.Frames.IndexOf(f)+1}".ToWhite()
                        },
                        Header = "Frame".ToYellow(),
                    }
                },
                ShowColumnHeaders            = false,
                ShowPager                    = false,
                EnablePagerKeyboardShortcuts = false,
            };

            frameList = framePanel.Add(new ListGrid <InMemoryConsoleBitmapFrame>(options)).Fill(padding: new Thickness(1, 1, 0, 0));

            refreshed.SubscribeForLifetime(() =>
            {
                frameList.Refresh();
            }, frameList);

            BorderPanel fakeDialog      = null;
            Label       fakeDialogLabel = null;

            frameList.SelectionChanged.SubscribeForLifetime(() =>
            {
                CurrentFrameIndex = frameList.SelectedRowIndex;
                Refresh();
                if (fakeDialog != null)
                {
                    fakeDialog.X         = frameList.AbsoluteX + frameList.Width - 2;
                    fakeDialog.Y         = frameList.Y + 1 + frameList.SelectedRowIndex;
                    fakeDialogLabel.Text = FormatTimespanForFramePopup(CurrentFrame.FrameTime);
                }
            }, frameList);

            frameList.Focused.SubscribeForLifetime(() =>
            {
                var fakeDialogContent = new ConsolePanel()
                {
                    Background = TimespanPopupBGColor
                };

                fakeDialog             = ConsoleApp.Current.LayoutRoot.Add(new BorderPanel(fakeDialogContent));
                fakeDialog.BorderColor = RGB.Blue;
                fakeDialog.Width       = 30;
                fakeDialog.Height      = 5;
                fakeDialog.X           = frameList.AbsoluteX + frameList.Width - 2;
                fakeDialog.Y           = frameList.Y + 1 + frameList.SelectedRowIndex;
                fakeDialogContent.Fill();

                fakeDialogLabel = fakeDialogContent.Add(new Label()
                {
                    Text = FormatTimespanForFramePopup(CurrentFrame.FrameTime)
                }).CenterBoth();

                refreshed.SubscribeForLifetime(() =>
                {
                    fakeDialogLabel.Text = FormatTimespanForFramePopup(CurrentFrame.FrameTime);
                }, fakeDialogLabel);

                ConsoleApp.Current.FocusManager.GlobalKeyHandlers.PushForLifetime(ConsoleKey.OemPlus, null, () =>
                {
                    undoRedo.Do(new ShiftTimeStampForwardAction(this, CurrentFrameIndex, 50));
                }, fakeDialog);

                ConsoleApp.Current.FocusManager.GlobalKeyHandlers.PushForLifetime(ConsoleKey.OemMinus, null, () =>
                {
                    undoRedo.Do(new ShiftTimeStampBackwardAction(this, CurrentFrameIndex, 50));
                }, fakeDialog);

                ConsoleApp.Current.FocusManager.GlobalKeyHandlers.PushForLifetime(ConsoleKey.OemPlus, ConsoleModifiers.Shift, () =>
                {
                    undoRedo.Do(new ShiftTimeStampForwardAction(this, CurrentFrameIndex, 10));
                }, fakeDialog);

                ConsoleApp.Current.FocusManager.GlobalKeyHandlers.PushForLifetime(ConsoleKey.OemMinus, ConsoleModifiers.Shift, () =>
                {
                    undoRedo.Do(new ShiftTimeStampBackwardAction(this, CurrentFrameIndex, 10));
                }, fakeDialog);
            }, frameList);

            frameList.Unfocused.SubscribeForLifetime(() =>
            {
                fakeDialog?.Dispose();
                fakeDialogLabel = null;
                fakeDialog      = null;
            }, frameList);
        }
        private static void ParsePanel(ParserContext context, ConsolePanel panel)
        {
            var myElement = context.CurrentElement;
            context.CurrentControl = panel;
            ParseControlAttributes(panel, context);

            foreach (var childElement in context.CurrentElement.Elements)
            {
                context.CurrentElement = childElement;
                var childControl = CreateControl(context);
                context.CurrentControl = childControl;
                panel.Add(childControl);

                if (childControl is ConsolePanel)
                {
                    ParsePanel(context, childControl as ConsolePanel);
                }
                else
                {
                    ParseControlAttributes(childControl, context);
                }
            }

            context.CurrentElement = myElement;
            context.CurrentControl = panel;
        }