@@ -0,0 +1,66 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Utility;
|
||||
using static Content.Shared._White.InteractiveBoard.SharedInteractiveBoardComponent;
|
||||
|
||||
namespace Content.Client._White.InteractiveBoard.UI;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class InteractiveBoardBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private InteractiveBoardWindow? _window;
|
||||
|
||||
public InteractiveBoardBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = new InteractiveBoardWindow();
|
||||
_window.OnClose += Close;
|
||||
_window.Input.OnKeyBindDown += args =>
|
||||
{
|
||||
if (args.Function == EngineKeyFunctions.TextSubmit)
|
||||
{
|
||||
var text = Rope.Collapse(_window.Input.TextRope);
|
||||
Input_OnTextEntered(text);
|
||||
args.Handle();
|
||||
}
|
||||
};
|
||||
|
||||
if (EntMan.TryGetComponent<InteractiveBoardVisualsComponent>(Owner, out var visuals))
|
||||
{
|
||||
_window.InitVisuals(Owner, visuals);
|
||||
}
|
||||
|
||||
_window.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
_window?.Populate((InteractiveBoardBoundUserInterfaceState) state);
|
||||
}
|
||||
|
||||
private void Input_OnTextEntered(string text)
|
||||
{
|
||||
SendMessage(new InteractiveBoardInputTextMessage(text));
|
||||
|
||||
if (_window != null)
|
||||
{
|
||||
_window.Input.TextRope = Rope.Leaf.Empty;
|
||||
_window.Input.CursorPosition = new TextEdit.CursorPos(0, TextEdit.LineBreakBias.Top);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Client._White.InteractiveBoard.UI;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class InteractiveBoardVisualsComponent : Component
|
||||
{
|
||||
public string ImagePath = "/Textures/White/Interface/InteractiveBoard/interactiveboardbackground.png";
|
||||
|
||||
public Box2 BackgroundPatchMargin = default;
|
||||
|
||||
public Color BackgroundModulate = Color.White;
|
||||
|
||||
public bool BackgroundImageTile = false;
|
||||
|
||||
public Vector2 BackgroundScale = Vector2.One;
|
||||
|
||||
public string? HeaderImagePath;
|
||||
|
||||
public Color HeaderImageModulate = Color.White;
|
||||
|
||||
public Box2 HeaderMargin = default;
|
||||
|
||||
public string? ContentImagePath;
|
||||
|
||||
public Color ContentImageModulate = Color.White;
|
||||
|
||||
public Box2 ContentMargin = default;
|
||||
|
||||
public int ContentImageNumLines = 1;
|
||||
|
||||
public Color FontAccentColor = new(223, 223, 213);
|
||||
|
||||
public Vector2? MaxWritableArea = null;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<controls:InteractiveBoardWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client._White.InteractiveBoard.UI"
|
||||
MouseFilter="Stop" MinSize="500 500"
|
||||
SetSize="600 650">
|
||||
<BoxContainer Name="ContentsRoot" Orientation="Vertical">
|
||||
<PanelContainer StyleClasses="AngleRect" VerticalAlignment="Top">
|
||||
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton" HorizontalAlignment="Right"/>
|
||||
<Button Name="CopyButton" Text="Копировать текст" StyleClasses="windowCopyButton" HorizontalAlignment="Left"/>
|
||||
</PanelContainer>
|
||||
<PanelContainer Name="Background" StyleClasses="DefaultBorder" VerticalExpand="True" HorizontalExpand="True">
|
||||
<ScrollContainer Name="ScrollingContents" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="False">
|
||||
<PanelContainer Name="Content" VerticalExpand="True" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" VerticalAlignment="Stretch">
|
||||
<TextureButton Name="HeaderImage" HorizontalAlignment="Center" VerticalAlignment="Top" MouseFilter="Ignore"/>
|
||||
<Control Name="TextAlignmentPadding" VerticalAlignment="Top"/>
|
||||
<RichTextLabel Name="BlankIndicator" StyleClasses="LabelSecondaryColor" VerticalAlignment="Top" HorizontalAlignment="Center"/>
|
||||
<RichTextLabel StyleClasses="WrittenText" Name="WrittenTextLabel" VerticalAlignment="Stretch" Margin="4" HorizontalExpand="True"/>
|
||||
<PanelContainer Name="InputContainer" StyleClasses="TransparentBorderedWindowPanel" MinHeight="100"
|
||||
VerticalAlignment="Stretch" VerticalExpand="True" HorizontalExpand="True">
|
||||
<TextEdit Name="Input" StyleClasses="LineEdit" Access="Public" />
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</ScrollContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</controls:InteractiveBoardWindow>
|
||||
@@ -0,0 +1,207 @@
|
||||
using System.Numerics;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.RichText;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility;
|
||||
using static Content.Shared._White.InteractiveBoard.SharedInteractiveBoardComponent;
|
||||
|
||||
namespace Content.Client._White.InteractiveBoard.UI
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class InteractiveBoardWindow : BaseWindow
|
||||
{
|
||||
private static readonly Color DefaultTextColor = new(255, 255, 255);
|
||||
|
||||
private const int MarginSize = 12;
|
||||
|
||||
private StyleBoxTexture _contentTex = new();
|
||||
|
||||
private float _contentLineScale = 1.0f;
|
||||
|
||||
private DragMode _allowedResizeModes = ~DragMode.None;
|
||||
|
||||
private readonly Type[] _allowedTags = new Type[]
|
||||
{
|
||||
typeof(BoldItalicTag),
|
||||
typeof(BoldTag),
|
||||
typeof(BulletTag),
|
||||
typeof(ColorTag),
|
||||
typeof(HeadingTag),
|
||||
typeof(ItalicTag)
|
||||
};
|
||||
|
||||
public InteractiveBoardWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
CloseButton.OnPressed += _ => Close();
|
||||
CopyButton.OnPressed += _ => CopyToClipboard();
|
||||
}
|
||||
|
||||
public void InitVisuals(EntityUid entity, InteractiveBoardVisualsComponent visuals)
|
||||
{
|
||||
var resCache = IoCManager.Resolve<IResourceCache>();
|
||||
|
||||
Background.ModulateSelfOverride = visuals.BackgroundModulate;
|
||||
var backgroundImage = resCache.GetResource<TextureResource>(visuals.ImagePath);
|
||||
{
|
||||
var backgroundImageMode = visuals.BackgroundImageTile ? StyleBoxTexture.StretchMode.Tile : StyleBoxTexture.StretchMode.Stretch;
|
||||
var backgroundPatchMargin = visuals.BackgroundPatchMargin;
|
||||
Background.PanelOverride = new StyleBoxTexture
|
||||
{
|
||||
Texture = backgroundImage,
|
||||
TextureScale = visuals.BackgroundScale,
|
||||
Mode = backgroundImageMode,
|
||||
PatchMarginLeft = backgroundPatchMargin.Left,
|
||||
PatchMarginBottom = backgroundPatchMargin.Bottom,
|
||||
PatchMarginRight = backgroundPatchMargin.Right,
|
||||
PatchMarginTop = backgroundPatchMargin.Top
|
||||
};
|
||||
}
|
||||
|
||||
if (visuals.HeaderImagePath != null)
|
||||
{
|
||||
HeaderImage.TexturePath = visuals.HeaderImagePath;
|
||||
HeaderImage.MinSize = HeaderImage.TextureNormal?.Size ?? Vector2.Zero;
|
||||
}
|
||||
|
||||
HeaderImage.ModulateSelfOverride = visuals.HeaderImageModulate;
|
||||
HeaderImage.Margin = new Thickness(visuals.HeaderMargin.Left, visuals.HeaderMargin.Top,
|
||||
visuals.HeaderMargin.Right, visuals.HeaderMargin.Bottom);
|
||||
|
||||
Content.ModulateSelfOverride = visuals.ContentImageModulate;
|
||||
WrittenTextLabel.ModulateSelfOverride = visuals.FontAccentColor;
|
||||
|
||||
var contentImage = visuals.ContentImagePath != null ? resCache.GetResource<TextureResource>(visuals.ContentImagePath) : null;
|
||||
if (contentImage != null)
|
||||
{
|
||||
_contentTex = new StyleBoxTexture
|
||||
{
|
||||
Texture = contentImage,
|
||||
Mode = StyleBoxTexture.StretchMode.Tile,
|
||||
};
|
||||
Content.PanelOverride = _contentTex;
|
||||
_contentLineScale = visuals.ContentImageNumLines;
|
||||
}
|
||||
|
||||
Content.Margin = new Thickness(
|
||||
visuals.ContentMargin.Left, visuals.ContentMargin.Top,
|
||||
visuals.ContentMargin.Right, visuals.ContentMargin.Bottom);
|
||||
|
||||
if (visuals.MaxWritableArea != null)
|
||||
{
|
||||
var a = (Vector2)visuals.MaxWritableArea;
|
||||
ScrollingContents.MinSize = Vector2.Zero;
|
||||
ScrollingContents.MinSize = a;
|
||||
|
||||
if (a.X > 0.0f)
|
||||
{
|
||||
ScrollingContents.MaxWidth = a.X;
|
||||
_allowedResizeModes &= ~(DragMode.Left | DragMode.Right);
|
||||
SetWidth = float.NaN;
|
||||
}
|
||||
|
||||
if (a.Y > 0.0f)
|
||||
{
|
||||
ScrollingContents.MaxHeight = a.Y;
|
||||
_allowedResizeModes &= ~(DragMode.Top | DragMode.Bottom);
|
||||
SetHeight = float.NaN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
if (WrittenTextLabel.TryGetStyleProperty<Font>("font", out var font))
|
||||
{
|
||||
float fontLineHeight = font.GetLineHeight(1.0f);
|
||||
_contentTex.ExpandMarginTop = font.GetDescent(UIScale);
|
||||
var scaleY = _contentLineScale * fontLineHeight / _contentTex.Texture?.Height ?? fontLineHeight;
|
||||
_contentTex.TextureScale = new Vector2(1, scaleY);
|
||||
{
|
||||
var headerHeight = HeaderImage.Size.Y + HeaderImage.Margin.Top + HeaderImage.Margin.Bottom;
|
||||
var headerInLines = headerHeight / (fontLineHeight * _contentLineScale);
|
||||
var paddingRequiredInLines = (float)Math.Ceiling(headerInLines) - headerInLines;
|
||||
var verticalMargin = fontLineHeight * paddingRequiredInLines * _contentLineScale;
|
||||
TextAlignmentPadding.Margin = new Thickness(0.0f, verticalMargin, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
base.Draw(handle);
|
||||
}
|
||||
|
||||
public void Populate(InteractiveBoardBoundUserInterfaceState state)
|
||||
{
|
||||
var isEditing = state.Mode == InteractiveBoardAction.Write;
|
||||
var wasEditing = InputContainer.Visible;
|
||||
InputContainer.Visible = isEditing;
|
||||
|
||||
var msg = new FormattedMessage();
|
||||
msg.AddMarkupPermissive(state.Text);
|
||||
|
||||
var shouldCopyText = 0 == Input.TextLength && 0 != state.Text.Length;
|
||||
if (!wasEditing || shouldCopyText)
|
||||
{
|
||||
Input.TextRope = Rope.Leaf.Empty;
|
||||
Input.CursorPosition = new TextEdit.CursorPos();
|
||||
Input.InsertAtCursor(state.Text);
|
||||
}
|
||||
|
||||
WrittenTextLabel.SetMessage(msg, _allowedTags, DefaultTextColor);
|
||||
|
||||
WrittenTextLabel.Visible = !isEditing && state.Text.Length > 0;
|
||||
BlankIndicator.Visible = !isEditing && state.Text.Length == 0;
|
||||
}
|
||||
|
||||
protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
|
||||
{
|
||||
var mode = DragMode.None;
|
||||
|
||||
if (relativeMousePos.Y < MarginSize)
|
||||
{
|
||||
mode |= DragMode.Top;
|
||||
}
|
||||
else if (relativeMousePos.Y > Size.Y - MarginSize)
|
||||
{
|
||||
mode |= DragMode.Bottom;
|
||||
}
|
||||
|
||||
if (relativeMousePos.X < MarginSize)
|
||||
{
|
||||
mode |= DragMode.Left;
|
||||
}
|
||||
else if (relativeMousePos.X > Size.X - MarginSize)
|
||||
{
|
||||
mode |= DragMode.Right;
|
||||
}
|
||||
|
||||
if((mode & _allowedResizeModes) == DragMode.None)
|
||||
{
|
||||
return DragMode.Move;
|
||||
}
|
||||
return mode & _allowedResizeModes;
|
||||
}
|
||||
|
||||
private void CopyToClipboard()
|
||||
{
|
||||
if (WrittenTextLabel.GetMessage() == null)
|
||||
return;
|
||||
|
||||
if (InputContainer.Visible)
|
||||
{
|
||||
InputContainer.Visible = false;
|
||||
Input.Editable = true;
|
||||
WrittenTextLabel.Visible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
InputContainer.Visible = true;
|
||||
Input.Editable = false;
|
||||
WrittenTextLabel.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user