<commit_before>// Copyright (c) 2007-2019 ppy Pty Ltd <<EMAIL>>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE

using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;

namespace osu.Framework.Screens
{
    public interface IScreen : IDrawable
    {
        bool ValidForResume { get; set; }

        /// <summary>
        /// Called when this Screen is being entered. Only happens once, ever.
        /// </summary>
        /// <param name="last">The next Screen.</param>
        void OnEntering(IScreen last);

        /// <summary>
        /// Called when this Screen is exiting. Only happens once, ever.
        /// </summary>
        /// <param name="next">The next Screen.</param>
        /// <returns>Return true to cancel the exit process.</returns>
        bool OnExiting(IScreen next);

        /// <summary>
        /// Called when this Screen is being returned to from a child exiting.
        /// </summary>
        /// <param name="last">The next Screen.</param>
        void OnResuming(IScreen last);

        /// <summary>
        /// Called when this Screen is being left to a new child.
        /// </summary>
        /// <param name="next">The new Screen</param>
        void OnSuspending(IScreen next);
    }

    public class ScreenStack : CompositeDrawable
    {
        public event Action<IScreen> ScreenPushed;
        public event Action<IScreen> ScreenExited;

        private readonly Stack<ScreenDescriptor> screens = new Stack<ScreenDescriptor>();

        public ScreenStack(IScreen baseScreen)
        {
            var descriptor = new ScreenDescriptor { Screen = baseScreen };

            screens.Push(descriptor);

            AddInternal(descriptor.ScreenDrawable);

            baseScreen.OnEntering(null);
        }

        internal void Push(IScreen source, IScreen newScreen)
        {
            if (source != screens.Peek().Screen)
                throw new Screen.ScreenNotCurrentException(nameof(Push));

            if (screens.Any(d => d.Screen == newScreen))
                throw new Screen.ScreenAlreadyEnteredException();

            var last = screens.Peek();
            var next = new ScreenDescriptor { Screen = newScreen };

            if (next.ScreenDrawable.RemoveWhenNotAlive)
                throw new Screen.ScreenWillBeRemovedOnPushException(newScreen.GetType());

            // Suspend the current screen
            last.Screen.OnSuspending(newScreen);
            last.ScreenDrawable.Expire();

            // Push the new screen
            screens.Push(next);
            ScreenPushed?.Invoke(newScreen);

            void finishLoad()
            {
                if (!screens.Contains(last) || !screens.Contains(next))
                    return;

                AddInternal(next.ScreenDrawable);
                next.Screen.OnEntering(last.Screen);
            }

            LoadScreen(last.ScreenDrawable, next.ScreenDrawable, finishLoad);
        }

        protected virtual void LoadScreen(CompositeDrawable last, CompositeDrawable next, Action continuation)
        {
            if (next.LoadState >= LoadState.Ready)
                continuation?.Invoke();
            else
                last.LoadComponentAsync(next, _ => continuation?.Invoke());
        }
<commit_msg>Allow pushing exited screens<commit_after>// Copyright (c) 2007-2019 ppy Pty Ltd <<EMAIL>>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE

using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;

namespace osu.Framework.Screens
{
    public interface IScreen : IDrawable
    {
        bool ValidForResume { get; set; }

        /// <summary>
        /// Called when this Screen is being entered. Only happens once, ever.
        /// </summary>
        /// <param name="last">The next Screen.</param>
        void OnEntering(IScreen last);

        /// <summary>
        /// Called when this Screen is exiting. Only happens once, ever.
        /// </summary>
        /// <param name="next">The next Screen.</param>
        /// <returns>Return true to cancel the exit process.</returns>
        bool OnExiting(IScreen next);

        /// <summary>
        /// Called when this Screen is being returned to from a child exiting.
        /// </summary>
        /// <param name="last">The next Screen.</param>
        void OnResuming(IScreen last);

        /// <summary>
        /// Called when this Screen is being left to a new child.
        /// </summary>
        /// <param name="next">The new Screen</param>
        void OnSuspending(IScreen next);
    }

    public class ScreenStack : CompositeDrawable
    {
        public event Action<IScreen> ScreenPushed;
        public event Action<IScreen> ScreenExited;

        private readonly Stack<ScreenDescriptor> screens = new Stack<ScreenDescriptor>();

        public ScreenStack(IScreen baseScreen)
        {
            var descriptor = new ScreenDescriptor { Screen = baseScreen };

            screens.Push(descriptor);

            AddInternal(descriptor.ScreenDrawable);

            baseScreen.OnEntering(null);
        }

        internal void Push(IScreen source, IScreen newScreen)
        {
            if (source != screens.Peek().Screen)
                throw new Screen.ScreenNotCurrentException(nameof(Push));

            if (screens.Any(d => d.Screen == newScreen))
                throw new Screen.ScreenAlreadyEnteredException();

            var last = screens.Peek();
            var next = new ScreenDescriptor { Screen = newScreen };

            if (next.ScreenDrawable.RemoveWhenNotAlive)
                throw new Screen.ScreenWillBeRemovedOnPushException(newScreen.GetType());

            // Suspend the current screen
            last.Screen.OnSuspending(newScreen);
            last.ScreenDrawable.Expire();

            next.ScreenDrawable.LifetimeEnd = double.MaxValue;

            // Push the new screen
            screens.Push(next);
            ScreenPushed?.Invoke(newScreen);

            void finishLoad()
            {
                if (!screens.Contains(last) || !screens.Contains(next))
                    return;

                AddInternal(next.ScreenDrawable);
                next.Screen.OnEntering(last.Screen);
            }

            LoadScreen(last.ScreenDrawable, next.ScreenDrawable, finishLoad);
        }

        protected virtual void LoadScreen(CompositeDrawable last, CompositeDrawable next, Action continuation)
        {
            if (next.LoadState >= LoadState.Ready)
                continuation?.Invoke();
            else
                last.LoadComponentAsync(next, _ => continuation?.Invoke());
        }

{'fraction_non_alphanumeric': 0.10464270120797554, 'fraction_numerical': 0.002328627565128802, 'mean_word_length': 2.0259797446059005, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 57, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4989525', 'n_tokens_mistral': 1780, 'n_tokens_neox': 1706, 'n_words': 451}