2019-01-24 16:43:03 +08:00
// 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.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2018-01-09 19:22:23 +08:00
using osu.Game.Online.Chat ;
using System ;
using System.Linq ;
using osu.Framework.Allocation ;
using osu.Framework.Graphics.Sprites ;
2018-01-09 23:11:45 +08:00
using System.Collections.Generic ;
2018-12-26 17:05:12 +08:00
using osu.Framework.Graphics ;
2021-08-01 23:12:04 +08:00
using osu.Framework.Graphics.Containers ;
2021-04-19 14:29:26 +08:00
using osu.Framework.Localisation ;
2023-12-01 05:59:02 +08:00
using osu.Framework.Logging ;
2021-07-30 12:21:26 +08:00
using osu.Framework.Platform ;
2022-06-21 02:04:21 +08:00
using osu.Game.Online ;
2021-11-04 17:22:21 +08:00
using osu.Game.Users ;
2023-09-03 10:51:08 +08:00
using osu.Game.Localisation ;
2018-04-13 17:19:50 +08:00
2018-01-09 19:22:23 +08:00
namespace osu.Game.Graphics.Containers
{
public partial class LinkFlowContainer : OsuTextFlowContainer
{
public LinkFlowContainer ( Action < SpriteText > defaultCreationParameters = null )
: base ( defaultCreationParameters )
{
}
2018-04-13 17:19:50 +08:00
2019-11-27 23:13:44 +08:00
[Resolved(CanBeNull = true)]
2022-06-21 02:04:21 +08:00
private ILinkHandler linkHandler { get ; set ; }
2018-04-13 17:19:50 +08:00
2021-07-30 12:21:26 +08:00
[Resolved]
private GameHost host { get ; set ; }
2018-01-09 23:11:45 +08:00
public void AddLinks ( string text , List < Link > links )
{
if ( string . IsNullOrEmpty ( text ) | | links = = null )
return ;
2018-04-13 17:19:50 +08:00
2018-01-09 23:11:45 +08:00
if ( links . Count = = 0 )
{
AddText ( text ) ;
return ;
}
2018-04-13 17:19:50 +08:00
2018-01-09 23:11:45 +08:00
int previousLinkEnd = 0 ;
2019-04-01 11:16:05 +08:00
2018-01-09 23:11:45 +08:00
foreach ( var link in links )
{
2023-12-01 05:59:02 +08:00
string displayText = text . Substring ( link . Index , link . Length ) ;
if ( previousLinkEnd > link . Index )
{
Logger . Log ( $@"Link ""{link.Url}"" with text ""{displayText}"" overlaps previous link, ignoring." ) ;
continue ;
}
2019-12-14 20:54:22 +08:00
AddText ( text [ previousLinkEnd . . link . Index ] ) ;
2021-02-12 14:18:16 +08:00
2021-11-08 13:17:47 +08:00
object linkArgument = link . Argument ;
2021-02-12 14:18:16 +08:00
string tooltip = displayText = = link . Url ? null : link . Url ;
AddLink ( displayText , link . Action , linkArgument , tooltip ) ;
2018-01-09 23:11:45 +08:00
previousLinkEnd = link . Index + link . Length ;
}
2018-04-13 17:19:50 +08:00
2018-01-30 16:47:22 +08:00
AddText ( text . Substring ( previousLinkEnd ) ) ;
2018-01-09 23:11:45 +08:00
}
2018-04-13 17:19:50 +08:00
2021-10-31 00:31:43 +08:00
public void AddLink ( LocalisableString text , string url , Action < SpriteText > creationParameters = null ) = >
2021-08-08 02:52:12 +08:00
createLink ( CreateChunkFor ( text , true , CreateSpriteText , creationParameters ) , new LinkDetails ( LinkAction . External , url ) , url ) ;
2018-12-26 17:05:12 +08:00
2021-10-31 00:31:43 +08:00
public void AddLink ( LocalisableString text , Action action , string tooltipText = null , Action < SpriteText > creationParameters = null )
2021-08-08 02:52:12 +08:00
= > createLink ( CreateChunkFor ( text , true , CreateSpriteText , creationParameters ) , new LinkDetails ( LinkAction . Custom , string . Empty ) , tooltipText , action ) ;
2018-12-26 17:05:12 +08:00
2021-11-08 13:17:47 +08:00
public void AddLink ( LocalisableString text , LinkAction action , object argument , string tooltipText = null , Action < SpriteText > creationParameters = null )
2021-10-31 00:31:43 +08:00
= > createLink ( CreateChunkFor ( text , true , CreateSpriteText , creationParameters ) , new LinkDetails ( action , argument ) , tooltipText ) ;
2018-12-26 17:05:12 +08:00
2021-11-08 13:17:47 +08:00
public void AddLink ( IEnumerable < SpriteText > text , LinkAction action , object linkArgument , string tooltipText = null )
2021-04-18 20:58:08 +08:00
{
2021-08-01 23:12:04 +08:00
createLink ( new TextPartManual ( text ) , new LinkDetails ( action , linkArgument ) , tooltipText ) ;
2021-04-18 20:58:08 +08:00
}
2021-11-04 17:22:21 +08:00
public void AddUserLink ( IUser user , Action < SpriteText > creationParameters = null )
2023-09-03 10:51:08 +08:00
= > createLink ( CreateChunkFor ( user . Username , true , CreateSpriteText , creationParameters ) , new LinkDetails ( LinkAction . OpenUserProfile , user ) , ContextMenuStrings . ViewProfile ) ;
2019-04-05 13:15:36 +08:00
2021-08-01 23:12:04 +08:00
private void createLink ( ITextPart textPart , LinkDetails link , LocalisableString tooltipText , Action action = null )
2018-01-09 19:22:23 +08:00
{
2021-08-01 23:12:04 +08:00
Action onClickAction = ( ) = >
2018-01-09 19:22:23 +08:00
{
2021-09-08 14:50:19 +08:00
if ( action ! = null )
action ( ) ;
2022-06-21 02:04:21 +08:00
else if ( linkHandler ! = null )
linkHandler . HandleLink ( link ) ;
2021-09-08 14:50:19 +08:00
// fallback to handle cases where OsuGame is not available, ie. tournament client.
else if ( link . Action = = LinkAction . External )
2021-11-08 13:17:47 +08:00
host . OpenUrlExternally ( link . Argument . ToString ( ) ) ;
2021-09-08 14:50:19 +08:00
} ;
2021-08-01 23:12:04 +08:00
AddPart ( new TextLink ( textPart , tooltipText , onClickAction ) ) ;
}
private class TextLink : TextPart
{
private readonly ITextPart innerPart ;
private readonly LocalisableString tooltipText ;
private readonly Action action ;
public TextLink ( ITextPart innerPart , LocalisableString tooltipText , Action action )
{
this . innerPart = innerPart ;
this . tooltipText = tooltipText ;
this . action = action ;
}
protected override IEnumerable < Drawable > CreateDrawablesFor ( TextFlowContainer textFlowContainer )
{
var linkFlowContainer = ( LinkFlowContainer ) textFlowContainer ;
innerPart . RecreateDrawablesFor ( linkFlowContainer ) ;
var drawables = innerPart . Drawables . ToList ( ) ;
drawables . Add ( linkFlowContainer . CreateLinkCompiler ( innerPart ) . With ( c = >
{
c . RelativeSizeAxes = Axes . Both ;
c . TooltipText = tooltipText ;
c . Action = action ;
} ) ) ;
return drawables ;
}
2018-01-09 19:22:23 +08:00
}
2019-01-08 17:58:44 +08:00
2021-08-01 23:12:04 +08:00
protected virtual DrawableLinkCompiler CreateLinkCompiler ( ITextPart textPart ) = > new DrawableLinkCompiler ( textPart ) ;
2021-09-08 14:50:19 +08:00
2019-01-10 13:55:36 +08:00
// We want the compilers to always be visible no matter where they are, so RelativeSizeAxes is used.
// However due to https://github.com/ppy/osu-framework/issues/2073, it's possible for the compilers to be relative size in the flow's auto-size axes - an unsupported operation.
// Since the compilers don't display any content and don't affect the layout, it's simplest to exclude them from the flow.
2019-01-08 17:58:44 +08:00
public override IEnumerable < Drawable > FlowingChildren = > base . FlowingChildren . Where ( c = > ! ( c is DrawableLinkCompiler ) ) ;
2018-01-09 19:22:23 +08:00
}
}