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

using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Chat;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using osu.Framework.Configuration;
using System;
using osu.Framework.Input.EventArgs;
using osu.Framework.Input.States;
using osu.Game.Graphics.Containers;

namespace osu.Game.Overlays.Chat
{
    public class ChatTabControl : OsuTabControl<Channel>
    {
        private const float shear_width = 10;

        public Action<Channel> OnRequestLeave;

        public readonly Bindable<bool> ChannelSelectorActive = new Bindable<bool>();

        private readonly ChannelTabItem.ChannelSelectorTabItem selectorTab;

        public ChatTabControl()
        {
            TabContainer.Margin = new MarginPadding { Left = 50 };
            TabContainer.Spacing = new Vector2(-shear_width, 0);
            TabContainer.Masking = false;

            AddInternal(new SpriteIcon
            {
                Icon = FontAwesome.fa_comments,
                Anchor = Anchor.CentreLeft,
                Origin = Anchor.CentreLeft,
                Size = new Vector2(20),
                Margin = new MarginPadding(10),
            });

            AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" }));

            ChannelSelectorActive.BindTo(selectorTab.Active);
        }

        protected override void AddTabItem(TabItem<Channel> item, bool addToDropdown = true)
        {
            if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue)
                // performTabSort might've made selectorTab's position wonky, fix it
                TabContainer.SetLayoutPosition(selectorTab, float.MaxValue);

            base.AddTabItem(item, addToDropdown);

            if (SelectedTab == null)
                SelectTab(item);
        }

        protected override TabItem<Channel> CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested };

        protected override void SelectTab(TabItem<Channel> tab)
        {
            if (tab is ChannelTabItem.ChannelSelectorTabItem)
            {
                tab.Active.Toggle();
                return;
            }

            selectorTab.Active.Value = false;

            base.SelectTab(tab);
        }

        private void tabCloseRequested(TabItem<Channel> tab)
        {
            int totalTabs = TabContainer.Count - 1; // account for selectorTab
            int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs);

            if (tab == SelectedTab && totalTabs > 1)
                // Select the tab after tab-to-be-removed's index, or the tab before if current == last
                SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]);
            else if (totalTabs == 1 && !selectorTab.Active)
                // Open channel selection overlay if all channel tabs will be closed after removing this tab
                SelectTab(selectorTab);

            OnRequestLeave?.Invoke(tab.Value);
        }

        private class ChannelTabItem : TabItem<Channel>
        {
            private Color4 backgroundInactive;
            private Color4 backgroundHover;
            private Color4 backgroundActive;

            public override bool IsRemovable => !Pinned;

            private readonly SpriteText text;
            private readonly SpriteText textBold;
            private readonly ClickableContainer closeButton;
            private readonly Box box;
            private readonly Box highlightBox;
            private readonly SpriteIcon icon;

            public Action<ChannelTabItem> OnRequestClose;

            private void updateState()
            {
                if (Active)
                    fadeActive();
                else
                    fadeInactive();
            }

            private const float transition_length = 400;

            private void fadeActive()
            {
                this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint);

                box.FadeColour(backgroundActive, transition_length, Easing.OutQuint);
                highlightBox.FadeIn(transition_length, Easing.OutQuint);

                text.FadeOut(transition_length, Easing.OutQuint);
                textBold.FadeIn(transition_length, Easing.OutQuint);
            }

            private void fadeInactive()
            {
                this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint);

                box.FadeColour(backgroundInactive, transition_length, Easing.OutQuint);
                highlightBox.FadeOut(transition_length, Easing.OutQuint);

                text.FadeIn(transition_length, Easing.OutQuint);
                textBold.FadeOut(transition_length, Easing.OutQuint);
            }

            protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
            {
                if (args.Button == MouseButton.Middle)
                    closeButton.Action();
                return true;
            }

            protected override bool OnHover(InputState state)
            {
                if (IsRemovable)
                    closeButton.FadeIn(200, Easing.OutQuint);

                if (!Active)
                    box.FadeColour(backgroundHover, transition_length, Easing.OutQuint);
                return true;
            }

            protected override void OnHoverLost(InputState state)
            {
                closeButton.FadeOut(200, Easing.OutQuint);<commit_msg>only return true on Mclick<commit_after>﻿// Copyright (c) 2007-2018 ppy Pty Ltd <<EMAIL>>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Chat;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using osu.Framework.Configuration;
using System;
using osu.Framework.Input.EventArgs;
using osu.Framework.Input.States;
using osu.Game.Graphics.Containers;

namespace osu.Game.Overlays.Chat
{
    public class ChatTabControl : OsuTabControl<Channel>
    {
        private const float shear_width = 10;

        public Action<Channel> OnRequestLeave;

        public readonly Bindable<bool> ChannelSelectorActive = new Bindable<bool>();

        private readonly ChannelTabItem.ChannelSelectorTabItem selectorTab;

        public ChatTabControl()
        {
            TabContainer.Margin = new MarginPadding { Left = 50 };
            TabContainer.Spacing = new Vector2(-shear_width, 0);
            TabContainer.Masking = false;

            AddInternal(new SpriteIcon
            {
                Icon = FontAwesome.fa_comments,
                Anchor = Anchor.CentreLeft,
                Origin = Anchor.CentreLeft,
                Size = new Vector2(20),
                Margin = new MarginPadding(10),
            });

            AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" }));

            ChannelSelectorActive.BindTo(selectorTab.Active);
        }

        protected override void AddTabItem(TabItem<Channel> item, bool addToDropdown = true)
        {
            if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue)
                // performTabSort might've made selectorTab's position wonky, fix it
                TabContainer.SetLayoutPosition(selectorTab, float.MaxValue);

            base.AddTabItem(item, addToDropdown);

            if (SelectedTab == null)
                SelectTab(item);
        }

        protected override TabItem<Channel> CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested };

        protected override void SelectTab(TabItem<Channel> tab)
        {
            if (tab is ChannelTabItem.ChannelSelectorTabItem)
            {
                tab.Active.Toggle();
                return;
            }

            selectorTab.Active.Value = false;

            base.SelectTab(tab);
        }

        private void tabCloseRequested(TabItem<Channel> tab)
        {
            int totalTabs = TabContainer.Count - 1; // account for selectorTab
            int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs);

            if (tab == SelectedTab && totalTabs > 1)
                // Select the tab after tab-to-be-removed's index, or the tab before if current == last
                SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]);
            else if (totalTabs == 1 && !selectorTab.Active)
                // Open channel selection overlay if all channel tabs will be closed after removing this tab
                SelectTab(selectorTab);

            OnRequestLeave?.Invoke(tab.Value);
        }

        private class ChannelTabItem : TabItem<Channel>
        {
            private Color4 backgroundInactive;
            private Color4 backgroundHover;
            private Color4 backgroundActive;

            public override bool IsRemovable => !Pinned;

            private readonly SpriteText text;
            private readonly SpriteText textBold;
            private readonly ClickableContainer closeButton;
            private readonly Box box;
            private readonly Box highlightBox;
            private readonly SpriteIcon icon;

            public Action<ChannelTabItem> OnRequestClose;

            private void updateState()
            {
                if (Active)
                    fadeActive();
                else
                    fadeInactive();
            }

            private const float transition_length = 400;

            private void fadeActive()
            {
                this.ResizeTo(new Vector2(Width, 1.1f), transition_length, Easing.OutQuint);

                box.FadeColour(backgroundActive, transition_length, Easing.OutQuint);
                highlightBox.FadeIn(transition_length, Easing.OutQuint);

                text.FadeOut(transition_length, Easing.OutQuint);
                textBold.FadeIn(transition_length, Easing.OutQuint);
            }

            private void fadeInactive()
            {
                this.ResizeTo(new Vector2(Width, 1), transition_length, Easing.OutQuint);

                box.FadeColour(backgroundInactive, transition_length, Easing.OutQuint);
                highlightBox.FadeOut(transition_length, Easing.OutQuint);

                text.FadeIn(transition_length, Easing.OutQuint);
                textBold.FadeOut(transition_length, Easing.OutQuint);
            }

            protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
            {
                var isMclick = args.Button == MouseButton.Middle;
                if (isMclick)
                    closeButton.Action();
                return isMclick;
            }

            protected override bool OnHover(InputState state)
            {
                if (IsRemovable)
                    closeButton.FadeIn(200, Easing.OutQuint);

                if (!Active)
                    box.FadeColour(backgroundHover, transition_length, Easing.OutQuint);
                return true;
            }

            protected override void OnHoverLost(InputState state)
            {
                closeButton.FadeOut(200, Easing.OutQuint);
{'fraction_non_alphanumeric': 0.07902535396773132, 'fraction_numerical': 0.00707935462627593, 'mean_word_length': 2.067154758899268, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 33, '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': '2480184', 'n_tokens_mistral': 3262, 'n_tokens_neox': 3038, 'n_words': 708}