mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 12:57:36 +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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -11,6 +13,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
@ -18,11 +21,12 @@ using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Screens.Edit.Components;
|
||||
using osu.Game.Screens.Edit.Components.Menus;
|
||||
using osu.Game.Skinning.Components;
|
||||
|
||||
namespace osu.Game.Skinning.Editor
|
||||
{
|
||||
[Cached(typeof(SkinEditor))]
|
||||
public class SkinEditor : VisibilityContainer
|
||||
public class SkinEditor : VisibilityContainer, ICanAcceptFiles
|
||||
{
|
||||
public const double TRANSITION_DURATION = 500;
|
||||
|
||||
@ -36,6 +40,9 @@ namespace osu.Game.Skinning.Editor
|
||||
|
||||
private Bindable<Skin> currentSkin;
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private OsuGame game { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private SkinManager skins { get; set; }
|
||||
|
||||
@ -171,6 +178,8 @@ namespace osu.Game.Skinning.Editor
|
||||
|
||||
Show();
|
||||
|
||||
game?.RegisterImportHandler(this);
|
||||
|
||||
// as long as the skin editor is loaded, let's make sure we can modify the current skin.
|
||||
currentSkin = skins.CurrentSkin.GetBoundCopy();
|
||||
|
||||
@ -186,6 +195,13 @@ namespace osu.Game.Skinning.Editor
|
||||
SelectedComponents.BindCollectionChanged((_, __) => Scheduler.AddOnce(populateSettings), true);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
game?.UnregisterImportHandler(this);
|
||||
}
|
||||
|
||||
public void UpdateTargetScreen(Drawable targetScreen)
|
||||
{
|
||||
this.targetScreen = targetScreen;
|
||||
@ -229,15 +245,20 @@ namespace osu.Game.Skinning.Editor
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (targetContainer == null)
|
||||
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;
|
||||
|
||||
// give newly added components a sane starting location.
|
||||
@ -313,5 +334,32 @@ namespace osu.Game.Skinning.Editor
|
||||
foreach (var item in items)
|
||||
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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading;
|
||||
@ -23,6 +24,7 @@ using osu.Game.Audio;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
|
||||
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.
|
||||
/// </remarks>
|
||||
[ExcludeFromDynamicCompile]
|
||||
public class SkinManager : ISkinSource, IStorageResourceProvider, IModelImporter<SkinInfo>
|
||||
public class SkinManager : ISkinSource, IStorageResourceProvider, IModelImporter<SkinInfo>, IModelManager<SkinInfo>, IModelFileManager<SkinInfo, RealmNamedFileUsage>
|
||||
{
|
||||
private readonly AudioManager audio;
|
||||
|
||||
@ -306,5 +308,45 @@ namespace osu.Game.Skinning
|
||||
}
|
||||
|
||||
#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>
|
||||
/// A skinnable element which uses a stable sprite and can therefore share implementation logic.
|
||||
/// </summary>
|
||||
public class SkinnableSprite : SkinnableDrawable
|
||||
public class SkinnableSprite : SkinnableDrawable, ISkinnableDrawable
|
||||
{
|
||||
protected override bool ApplySizeRestrictionsToDefault => true;
|
||||
|
||||
@ -42,5 +42,7 @@ namespace osu.Game.Skinning
|
||||
|
||||
public string LookupName { get; }
|
||||
}
|
||||
|
||||
public bool UsesFixedAnchor { get; set; }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user