Skip to content

Instantly share code, notes, and snippets.

@peppy
Created September 27, 2016 09:50
Show Gist options
  • Save peppy/40ab53ed6870ccd70eb8e798ce4859c5 to your computer and use it in GitHub Desktop.
Save peppy/40ab53ed6870ccd70eb8e798ce4859c5 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Text;
using osu.Audio;
using OpenTK.Graphics;
using osu.Graphics.Skinning;
using osu.Graphics.Sprites;
using osu.Graphics.Textures;
using osu_common;
using osu_common.Helpers;
using OpenTK;
namespace osu.Graphics.UserInterface
{
internal class BackButton : Drawable
{
const float layer_left_idle = 22;
const float layer_left_active = 40;
const float layer_right_idle = 60;
const float layer_right_active = 86;
const float centre_offset = 2.4f;
const int animation_delay = 600;
const float vertical_offset = 21; //todo: use relative position
/// <summary>
/// depending on localisation we may need to give the FontText a bit more room.
/// </summary>
float layerRightTextAllowance;
Color4 colour_idle = new Color4(238, 51, 153, 255);
Color4 colour_active = new Color4(187, 17, 119, 255);
private FontText text;
private TextAwesome icon;
private Container iconBounce;
private Sprite layerLeft;
private Sprite layerRight;
private Animation backSprite2;
private Animation backSprite1;
EventHandler Action;
public BackButton(EventHandler action, bool skinnable = true, bool dialog = false)
: base(int.MaxValue)
{
Action = action;
Anchor = Anchor.BottomLeft;
Origin = Anchor.BottomLeft;
SizeMode = SizeMode.Automatic;
ObsoleteOnMouseDown += back_OnClick;
ObsoleteOnHover += back_OnHover;
Texture[] textures = null;
if (skinnable)
textures = TextureManager.LoadAll(@"menu-back", SkinSource.Osu | SkinSource.Skin);
if (textures != null && textures.Length > 0)
{
//old back button behaviour
backSprite1 = new Animation(textures, Clocks.Game, Vector2.Zero, 0.9f, Color4.White)
{
Origin = Anchor.BottomLeft
};
backSprite1.SetFramerateFromSkin();
Add(backSprite1);
backSprite2 = new Animation(textures, Clocks.Game, Vector2.Zero, 0.91f, Color4.White)
{
Origin = Anchor.BottomLeft,
Alpha = 0.01f,
Additive = true,
HoverEffect = new Transformation(TransformationType.Fade, 1 / 255f, 0.4f, 0, 250)
};
backSprite2.SetFramerateFromSkin();
Add(backSprite2);
}
else
{
Add(text = new FontText(LocalisationManager.GetString(OsuString.General_Back).ToLower(), 15, new Vector2(0, vertical_offset), 0.91f, Color4.White)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.Centre,
});
iconBounce = new Container()
{
Position = new Vector2(0, vertical_offset),
Depth = 0.92f,
Anchor = Anchor.BottomLeft,
Origin = Anchor.Centre
};
iconBounce.Add(icon = new TextAwesome(FontAwesome.chevron_circle_left, 18 * 1.25f, Vector2.Zero) { Anchor = Anchor.Centre, Scale = 0.8f });
Add(iconBounce);
float backTextWidth = text.Size.X;
if (backTextWidth > layer_right_idle - layer_left_idle)
layerRightTextAllowance = backTextWidth - (layer_right_idle - layer_left_idle);
Add(layerLeft = new Sprite(TextureManager.Load(@"back-button-layer", SkinSource.Osu), Vector2.Zero, 0.91f, colour_idle)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomRight
});
iconBounce.OnUpdate += delegate
{
if (OsuGame.Audio.SyncNewBeat)
{
int length = (int)OsuGame.Audio.BeatLength;
if (length == 0) length = 500;
iconBounce.Scale = expanded ? 1.1f : 0.9f;
//icon.Delay(-length / 4);
iconBounce.ScaleTo(1, length * 3, EasingTypes.OutElastic);
}
};
Add(layerRight = new Sprite(TextureManager.Load(@"back-button-layer", SkinSource.Osu), Vector2.Zero, 0.9f, colour_idle)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomRight
});
layerRight.ObsoleteOnMouseDown += (o, e) =>
{
back_OnClick(this, null);
contract(EasingTypes.InOutBack, 400);
return true;
};
layerRight.ObsoleteOnHover += (o, e) =>
{
expand(EasingTypes.OutElastic);
return true;
};
layerRight.ObsoleteOnHover += back_OnHover;
layerRight.ObsoleteOnHoverLost += (o, e) =>
{
contract(EasingTypes.OutElastic);
return true;
};
contract(EasingTypes.OutElastic, 0);
}
}
private bool back_OnHover(object sender, EventArgs e)
{
if (OsuGame.Instance.IsActive)
OsuGame.Audio.PlaySamplePositional(@"back-button-hover", @"menuclick");
return true;
}
bool expanded;
void expand(EasingTypes easing, int delay = animation_delay)
{
expanded = true;
layerLeft.MoveTo(new Vector2(layer_left_active, layerLeft.Position.Y), delay, easing);
iconBounce.MoveTo(new Vector2(layer_left_active / centre_offset, iconBounce.Position.Y), delay, easing);
layerRight.MoveTo(new Vector2(layer_right_active + layerRightTextAllowance, layerRight.Position.Y), delay, easing);
text.MoveTo(new Vector2((layer_right_active + layerRightTextAllowance - layer_left_active) / centre_offset + layer_left_active, text.Position.Y), delay, easing);
icon.ScaleTo(1, delay, easing);
layerLeft.FadeColour(colour_active, delay, easing);
}
void contract(EasingTypes easing, int delay = animation_delay)
{
expanded = false;
layerLeft.MoveTo(new Vector2(layer_left_idle, layerLeft.Position.Y), delay, easing);
iconBounce.MoveTo(new Vector2(layer_left_idle / centre_offset, iconBounce.Position.Y), delay, easing);
layerRight.MoveTo(new Vector2(layer_right_idle + layerRightTextAllowance, layerRight.Position.Y), delay, easing);
text.MoveTo(new Vector2((layer_right_idle + layerRightTextAllowance - layer_left_idle) / centre_offset + layer_left_idle, text.Position.Y), delay, easing);
icon.ScaleTo(0.8f, delay, easing);
layerLeft.FadeColour(colour_idle, delay, easing);
}
private bool back_OnClick(object sender, EventArgs e)
{
Click();
return true;
}
internal void Click()
{
OsuGame.Audio.PlaySamplePositional(@"back-button-click", @"menuback");
Action?.Invoke(this, null);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment