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); }
/// <summary> /// Creates a new ConsolePanel /// </summary> public ProtectedConsolePanel() { this.CanFocus = false; ProtectedPanel = new ConsolePanel(); ProtectedPanel.Parent = this; ProtectedPanel.Fill(); }
/// <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); }
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; }
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(); }
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); }
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(); }
/// <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); }
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); } }
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(); }
/// <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); }
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); }
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; }
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); }
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); }
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); }
private void ComposeLoadingUX() { using (var modifyLock = Unlock()) { loadingPanel = Add(new ConsolePanel() { ZIndex = int.MaxValue }).Fill(); loadingPanel.Add(new Label() { Text = Options.LoadingMessage }).CenterBoth(); } }
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; } } }; }
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; } }
/// <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); }
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); }
/// <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); }
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; } } }
/// <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); }
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); } }
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); }
/// <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(); }
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; } } }; }
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(); } }
public Border2(ConsolePanel content = null) { this.Content = content ?? new ConsolePanel(); this.Add(Content).Fill(padding: new Thickness(2, 2, 1, 1)); }
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; }
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(); }
/// <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(); } }
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); }