// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Testing; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Play.HUD; using osuTK; namespace osu.Game.Skinning.Editor { public class SkinEditor : FocusedOverlayContainer { public const double TRANSITION_DURATION = 500; private readonly Drawable targetScreen; private OsuTextFlowContainer headerText; protected override bool StartHidden => true; [Resolved] private SkinManager skins { get; set; } public SkinEditor(Drawable targetScreen) { this.targetScreen = targetScreen; RelativeSizeAxes = Axes.Both; } [BackgroundDependencyLoader] private void load(OsuColour colours) { InternalChild = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { headerText = new OsuTextFlowContainer { TextAnchor = Anchor.TopCentre, Padding = new MarginPadding(20), Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X }, new SkinBlueprintContainer(targetScreen), new SkinComponentToolbox(600) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, RequestPlacement = placeComponent }, new FillFlowContainer { Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.Both, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Spacing = new Vector2(5), Padding = new MarginPadding { Top = 10, Left = 10, }, Margin = new MarginPadding { Right = 10, Bottom = 10, }, Children = new Drawable[] { new TriangleButton { Text = "Save Changes", Width = 140, Action = save, }, new DangerousTriangleButton { Text = "Revert to default", Width = 140, Action = revert, }, } }, } }; headerText.AddParagraph("Skin editor (preview)", cp => cp.Font = OsuFont.Default.With(size: 24)); headerText.AddParagraph("This is a preview of what is to come. Changes are lost on changing screens.", cp => { cp.Font = OsuFont.Default.With(size: 12); cp.Colour = colours.Yellow; }); } private void placeComponent(Type type) { Drawable instance = (Drawable)Activator.CreateInstance(type); getTarget(SkinnableTarget.MainHUDComponents)?.Add(instance); } private ISkinnableTarget getTarget(SkinnableTarget target) { return targetScreen.ChildrenOfType().FirstOrDefault(c => c.Target == target); } protected override void LoadComplete() { base.LoadComplete(); Show(); } private void revert() { var currentSkin = skins.CurrentSkin.Value; var legacySkin = currentSkin as LegacySkin; if (legacySkin == null) return; SkinnableElementTargetContainer[] targetContainers = targetScreen.ChildrenOfType().ToArray(); foreach (var t in targetContainers) { legacySkin.ResetDrawableTarget(t); // add back default components getTarget(t.Target).Reload(); } } private void save() { var currentSkin = skins.CurrentSkin.Value; var legacySkin = currentSkin as LegacySkin; if (legacySkin == null) return; SkinnableElementTargetContainer[] targetContainers = targetScreen.ChildrenOfType().ToArray(); foreach (var t in targetContainers) legacySkin.UpdateDrawableTarget(t); skins.Save(skins.CurrentSkin.Value); } protected override bool OnHover(HoverEvent e) => true; protected override bool OnMouseDown(MouseDownEvent e) => true; protected override void PopIn() { this.FadeIn(TRANSITION_DURATION, Easing.OutQuint); } protected override void PopOut() { this.FadeOut(TRANSITION_DURATION, Easing.OutQuint); } } }