mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 19:42:55 +08:00
Add SkinnableSprite
for arbitrary sprite additions
This commit is contained in:
parent
3a16483214
commit
fca9faac9b
49
osu.Game/Skinning/Components/SkinnableSprite.cs
Normal file
49
osu.Game/Skinning/Components/SkinnableSprite.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
|
namespace osu.Game.Skinning.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Intended to be a test bed for skinning. May be removed at some point in the future.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class SkinSprite : CompositeDrawable, ISkinnableDrawable
|
||||||
|
{
|
||||||
|
public bool UsesFixedAnchor { get; set; }
|
||||||
|
|
||||||
|
[SettingSource("Sprite name", "The filename of the sprite")]
|
||||||
|
public Bindable<string> SpriteName { get; } = new Bindable<string>(string.Empty);
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ISkinSource source { get; set; }
|
||||||
|
|
||||||
|
public SkinSprite()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
SpriteName.BindValueChanged(spriteName =>
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
Texture = source.GetTexture(SpriteName.Value),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -11,6 +13,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
@ -18,11 +21,12 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens.Edit.Components;
|
using osu.Game.Screens.Edit.Components;
|
||||||
using osu.Game.Screens.Edit.Components.Menus;
|
using osu.Game.Screens.Edit.Components.Menus;
|
||||||
|
using osu.Game.Skinning.Components;
|
||||||
|
|
||||||
namespace osu.Game.Skinning.Editor
|
namespace osu.Game.Skinning.Editor
|
||||||
{
|
{
|
||||||
[Cached(typeof(SkinEditor))]
|
[Cached(typeof(SkinEditor))]
|
||||||
public class SkinEditor : VisibilityContainer
|
public class SkinEditor : VisibilityContainer, ICanAcceptFiles
|
||||||
{
|
{
|
||||||
public const double TRANSITION_DURATION = 500;
|
public const double TRANSITION_DURATION = 500;
|
||||||
|
|
||||||
@ -36,6 +40,9 @@ namespace osu.Game.Skinning.Editor
|
|||||||
|
|
||||||
private Bindable<Skin> currentSkin;
|
private Bindable<Skin> currentSkin;
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private OsuGame game { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinManager skins { get; set; }
|
private SkinManager skins { get; set; }
|
||||||
|
|
||||||
@ -171,6 +178,8 @@ namespace osu.Game.Skinning.Editor
|
|||||||
|
|
||||||
Show();
|
Show();
|
||||||
|
|
||||||
|
game?.RegisterImportHandler(this);
|
||||||
|
|
||||||
// as long as the skin editor is loaded, let's make sure we can modify the current skin.
|
// as long as the skin editor is loaded, let's make sure we can modify the current skin.
|
||||||
currentSkin = skins.CurrentSkin.GetBoundCopy();
|
currentSkin = skins.CurrentSkin.GetBoundCopy();
|
||||||
|
|
||||||
@ -186,6 +195,13 @@ namespace osu.Game.Skinning.Editor
|
|||||||
SelectedComponents.BindCollectionChanged((_, __) => Scheduler.AddOnce(populateSettings), true);
|
SelectedComponents.BindCollectionChanged((_, __) => Scheduler.AddOnce(populateSettings), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
game?.UnregisterImportHandler(this);
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateTargetScreen(Drawable targetScreen)
|
public void UpdateTargetScreen(Drawable targetScreen)
|
||||||
{
|
{
|
||||||
this.targetScreen = targetScreen;
|
this.targetScreen = targetScreen;
|
||||||
@ -229,15 +245,20 @@ namespace osu.Game.Skinning.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void placeComponent(Type type)
|
private void placeComponent(Type type)
|
||||||
|
{
|
||||||
|
if (!(Activator.CreateInstance(type) is ISkinnableDrawable component))
|
||||||
|
throw new InvalidOperationException($"Attempted to instantiate a component for placement which was not an {typeof(ISkinnableDrawable)}.");
|
||||||
|
|
||||||
|
placeComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void placeComponent(ISkinnableDrawable component)
|
||||||
{
|
{
|
||||||
var targetContainer = getFirstTarget();
|
var targetContainer = getFirstTarget();
|
||||||
|
|
||||||
if (targetContainer == null)
|
if (targetContainer == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(Activator.CreateInstance(type) is ISkinnableDrawable component))
|
|
||||||
throw new InvalidOperationException($"Attempted to instantiate a component for placement which was not an {typeof(ISkinnableDrawable)}.");
|
|
||||||
|
|
||||||
var drawableComponent = (Drawable)component;
|
var drawableComponent = (Drawable)component;
|
||||||
|
|
||||||
// give newly added components a sane starting location.
|
// give newly added components a sane starting location.
|
||||||
@ -313,5 +334,32 @@ namespace osu.Game.Skinning.Editor
|
|||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item);
|
availableTargets.FirstOrDefault(t => t.Components.Contains(item))?.Remove(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task Import(params string[] paths)
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
var file = new FileInfo(paths.First());
|
||||||
|
|
||||||
|
// import to skin
|
||||||
|
currentSkin.Value.SkinInfo.PerformWrite(skinInfo =>
|
||||||
|
{
|
||||||
|
using (var contents = file.OpenRead())
|
||||||
|
skins.AddFile(skinInfo, contents, file.Name);
|
||||||
|
});
|
||||||
|
|
||||||
|
// place component
|
||||||
|
placeComponent(new SkinSprite
|
||||||
|
{
|
||||||
|
SpriteName = { Value = Path.GetFileNameWithoutExtension(file.Name) }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Import(params ImportTask[] tasks) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public IEnumerable<string> HandledExtensions => new[] { ".jpg", ".jpeg", ".png" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -23,6 +24,7 @@ using osu.Game.Audio;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.IO.Archives;
|
using osu.Game.IO.Archives;
|
||||||
|
using osu.Game.Models;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
|
|
||||||
namespace osu.Game.Skinning
|
namespace osu.Game.Skinning
|
||||||
@ -35,7 +37,7 @@ namespace osu.Game.Skinning
|
|||||||
/// For gameplay components, see <see cref="RulesetSkinProvidingContainer"/> which adds extra legacy and toggle logic that may affect the lookup process.
|
/// For gameplay components, see <see cref="RulesetSkinProvidingContainer"/> which adds extra legacy and toggle logic that may affect the lookup process.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[ExcludeFromDynamicCompile]
|
[ExcludeFromDynamicCompile]
|
||||||
public class SkinManager : ISkinSource, IStorageResourceProvider, IModelImporter<SkinInfo>
|
public class SkinManager : ISkinSource, IStorageResourceProvider, IModelImporter<SkinInfo>, IModelManager<SkinInfo>, IModelFileManager<SkinInfo, RealmNamedFileUsage>
|
||||||
{
|
{
|
||||||
private readonly AudioManager audio;
|
private readonly AudioManager audio;
|
||||||
|
|
||||||
@ -306,5 +308,45 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public bool Delete(SkinInfo item)
|
||||||
|
{
|
||||||
|
return skinModelManager.Delete(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(List<SkinInfo> items, bool silent = false)
|
||||||
|
{
|
||||||
|
skinModelManager.Delete(items, silent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Undelete(List<SkinInfo> items, bool silent = false)
|
||||||
|
{
|
||||||
|
skinModelManager.Undelete(items, silent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Undelete(SkinInfo item)
|
||||||
|
{
|
||||||
|
skinModelManager.Undelete(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAvailableLocally(SkinInfo model)
|
||||||
|
{
|
||||||
|
return skinModelManager.IsAvailableLocally(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceFile(SkinInfo model, RealmNamedFileUsage file, Stream contents)
|
||||||
|
{
|
||||||
|
skinModelManager.ReplaceFile(model, file, contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteFile(SkinInfo model, RealmNamedFileUsage file)
|
||||||
|
{
|
||||||
|
skinModelManager.DeleteFile(model, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddFile(SkinInfo model, Stream contents, string filename)
|
||||||
|
{
|
||||||
|
skinModelManager.AddFile(model, contents, filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Skinning
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A skinnable element which uses a stable sprite and can therefore share implementation logic.
|
/// A skinnable element which uses a stable sprite and can therefore share implementation logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SkinnableSprite : SkinnableDrawable
|
public class SkinnableSprite : SkinnableDrawable, ISkinnableDrawable
|
||||||
{
|
{
|
||||||
protected override bool ApplySizeRestrictionsToDefault => true;
|
protected override bool ApplySizeRestrictionsToDefault => true;
|
||||||
|
|
||||||
@ -42,5 +42,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public string LookupName { get; }
|
public string LookupName { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool UsesFixedAnchor { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user