/// <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(); } }
/// <summary> /// Enables modification of the Controls connection until the given /// lifetime expires /// </summary> /// <returns>A lifetime that you should dispose when you want to disable controls modification</returns> protected Lifetime Unlock() { var ret = new Lifetime(); activeModifierCount++; ret.OnDisposed(() => activeModifierCount--); return(ret); }
public Lifetime Push() { PushInternal(); var ret = new Lifetime(); ret.OnDisposed(new Subscription(() => { PopInternal(); })); return(ret); }
/// <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, Container> contentFactory, AnimatedDialogOptions options = null) { options = options ?? new AnimatedDialogOptions(); options.Parent = options.Parent ?? ConsoleApp.Current.LayoutRoot; using (var dialogLt = new Lifetime()) { var handle = new DialogHandle(); if (options.PushPop) { ConsoleApp.Current.FocusManager.Push(); if (options.AllowEscapeToClose) { ConsoleApp.Current.FocusManager.GlobalKeyHandlers.PushForLifetime(ConsoleKey.Escape, null, () => { handle.CloseDialog(); }, dialogLt); } if (options.AllowEnterToClose) { ConsoleApp.Current.FocusManager.GlobalKeyHandlers.PushForLifetime(ConsoleKey.Enter, null, () => { handle.CloseDialog(); }, dialogLt); } dialogLt.OnDisposed(ConsoleApp.Current.FocusManager.Pop); } var content = contentFactory(handle); content.IsVisible = false; var dialogContainer = options.Parent.Add(new BorderPanel(content) { BorderColor = handle.BorderColor, Background = content.Background, Width = 1, Height = 1 }).CenterBoth(); dialogContainer.ZIndex = options.ZIndex; await Forward(300 *options.SpeedPercentage, dialogLt, percentage => dialogContainer.Width = Math.Max(1, Geometry.Round((4 + content.Width) * percentage))); await Forward(200 *options.SpeedPercentage, dialogLt, percentage => dialogContainer.Height = Math.Max(1, Geometry.Round((2 + content.Height) * percentage))); content.IsVisible = true; await handle.CallerLifetime.AwaitEndOfLifetime(); content.IsVisible = false; await Reverse(150 *options.SpeedPercentage, dialogLt, percentage => dialogContainer.Height = Math.Max(1, (int)Math.Floor((2 + content.Height) * percentage))); await Task.Delay((int)(200 * options.SpeedPercentage)); await Reverse(200 *options.SpeedPercentage, dialogLt, percentage => dialogContainer.Width = Math.Max(1, Geometry.Round((4 + content.Width) * percentage))); dialogContainer.Dispose(); } }
private void AssertSizeRequirements(bool initialCheck) { if (initialCheck) { if (RequiredWidth.HasValue && this.Bitmap.Console.WindowWidth < RequiredWidth.Value) { this.Bitmap.Console.WindowWidth = RequiredWidth.Value; this.Bitmap.Console.BufferWidth = RequiredWidth.Value; } if (RequiredHeight.HasValue && this.Bitmap.Console.WindowHeight < RequiredHeight.Value) { this.Bitmap.Console.WindowHeight = RequiredHeight.Value; } } var currentHeight = ConsoleProvider.Current.WindowHeight; var currentWidth = ConsoleProvider.Current.WindowWidth; var tallEnough = this.RequiredHeight.HasValue == false || currentHeight >= this.RequiredHeight.Value; var wideEnough = this.RequiredWidth.HasValue == false || currentWidth >= this.RequiredWidth.Value; if (tallEnough && wideEnough) { if (tooSmallLifetime != null || initialCheck) { tooSmallLifetime?.Dispose(); RequiredSizeMet.Fire(); } } else if (tooSmallLifetime == null) { isKeyboardInputEnabled = false; RequiredSizeNotMet.Fire(); tooSmallLifetime = new Lifetime(); var mask = LayoutRoot.Add(new ConsolePanel()).Fill(); mask.ZIndex = int.MaxValue; mask.Add(new Label() { Text = "Increase the console window's size to view the app".ToYellow() }).CenterBoth(); tooSmallLifetime.OnDisposed(() => { isKeyboardInputEnabled = true; LayoutRoot.Controls.Remove(mask); tooSmallLifetime = null; }); } }
internal ILifetime PushUnmanaged(ConsoleKey key, ConsoleModifiers?modifier, Action <ConsoleKeyInfo> handler) { Dictionary <ConsoleKey, Stack <Action <ConsoleKeyInfo> > > target; if (modifier.HasValue == false) { target = handlerStack.Peek().NakedHandlers; } else if (modifier.Value.HasFlag(ConsoleModifiers.Alt)) { target = handlerStack.Peek().AltHandlers; } else if (modifier.Value.HasFlag(ConsoleModifiers.Shift)) { target = handlerStack.Peek().ShiftHandlers; } else if (modifier.Value.HasFlag(ConsoleModifiers.Control)) { target = handlerStack.Peek().ControlHandlers; } else { throw new ArgumentException("Unsupported modifier: " + modifier.Value); } Stack <Action <ConsoleKeyInfo> > targetStack; if (target.TryGetValue(key, out targetStack) == false) { targetStack = new Stack <Action <ConsoleKeyInfo> >(); target.Add(key, targetStack); } targetStack.Push(handler); var lt = new Lifetime(); lt.OnDisposed(() => { targetStack.Pop(); if (targetStack.Count == 0) { target.Remove(key); } }); return(lt); }
/// <summary> /// The state change handler that defines what happens whenever the player changes state /// </summary> private void StateChanged() { if (State != PlayerState.Playing) { playLifetime = null; } if (State == PlayerState.Playing) { if (duration.HasValue == false) { throw new InvalidOperationException("Playback is not permitted before a video is loaded"); } playStartPosition = TimeSpan.FromSeconds(playerProgressBar.PlayCursorPosition * duration.Value.TotalSeconds); playStartTime = DateTime.UtcNow; lastFrameIndex = 0; // start a play loop for as long as the state remains unchanged this.playLifetime = this.GetPropertyValueLifetime(nameof(State)); playLifetime.OnDisposed(Application.SetInterval(() => { if (State != PlayerState.Playing) { return; } var now = DateTime.UtcNow; var delta = now - playStartTime; var newPlayerPosition = playStartPosition + delta; var videoLocationPercentage = Math.Round(100.0 * newPlayerPosition.TotalSeconds / duration.Value.TotalSeconds, 1); videoLocationPercentage = Math.Min(videoLocationPercentage, 100); playerProgressBar.PlayCursorPosition = videoLocationPercentage / 100.0; playButton.Text = $"Pause".ToConsoleString(); InMemoryConsoleBitmapFrame seekedFrame; if ((lastFrameIndex = inMemoryVideo.Seek(newPlayerPosition, out seekedFrame, lastFrameIndex >= 0 ? lastFrameIndex : 0)) < 0) { State = PlayerState.Buffering; } else { CurrentFrame = seekedFrame.Bitmap; OnFramePlayed.Fire(seekedFrame.FrameTime); } if (newPlayerPosition > duration) { State = PlayerState.Stopped; } }, TimeSpan.FromMilliseconds(1))); } else if (State == PlayerState.Stopped) { pictureFrame.BorderColor = ConsoleColor.Yellow; playButton.Text = "Play".ToConsoleString(); } else if (State == PlayerState.Paused) { playButton.Text = "Play".ToConsoleString(); } else if (State == PlayerState.NotLoaded) { playButton.Text = "Play".ToConsoleString(); playButton.CanFocus = false; } else if (State == PlayerState.Buffering) { playButton.Text = "Play".ToConsoleString(); } else if (State == PlayerState.Failed) { pictureFrame.BorderColor = ConsoleColor.Red; Dialog.ShowMessage(failedMessage.ToRed()); } else { throw new Exception("Unknown state: " + State); } }