// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using FlaxEditor.GUI; using FlaxEditor.GUI.Input; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; namespace FlaxEditor.Surface { /// /// Visject Surface comment control. /// /// [HideInEditor] public class SurfaceComment : SurfaceNode { private Rectangle _colorButtonRect; private Rectangle _resizeButtonRect; private Float2 _startResizingSize; /// /// True if sizing tool is in use. /// protected bool _isResizing; /// /// Gets or sets the color of the comment. /// public Color Color { get => BackgroundColor; set => BackgroundColor = value; } private string TitleValue { get => (string)Values[0]; set => SetValue(0, value, false); } private Color ColorValue { get => (Color)Values[1]; set => SetValue(1, value, false); } private Float2 SizeValue { get => (Float2)Values[2]; set => SetValue(2, value, false); } /// public SurfaceComment(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) : base(id, context, nodeArch, groupArch) { } /// public override void OnSurfaceLoaded() { base.OnSurfaceLoaded(); // Read node data Title = TitleValue; Color = ColorValue; Size = SizeValue; } /// public override void OnSpawned() { base.OnSpawned(); // Randomize color Color = ColorValue = Color.FromHSV(new Random().NextFloat(0, 360), 0.7f, 0.25f, 0.8f); } /// public override void OnValuesChanged() { base.OnValuesChanged(); // Read node data Title = TitleValue; Color = ColorValue; Size = SizeValue; } private void EndResizing() { // Clear state _isResizing = false; if (_startResizingSize != Size) { SizeValue = Size; Surface.MarkAsEdited(false); } EndMouseCapture(); } /// public override bool CanSelect(ref Float2 location) { return _headerRect.MakeOffsetted(Location).Contains(ref location) && !_resizeButtonRect.MakeOffsetted(Location).Contains(ref location); } /// public override bool IsSelectionIntersecting(ref Rectangle selectionRect) { return _headerRect.MakeOffsetted(Location).Intersects(ref selectionRect); } /// protected override void UpdateRectangles() { const float headerSize = Constants.NodeHeaderSize; const float buttonMargin = Constants.NodeCloseButtonMargin; const float buttonSize = Constants.NodeCloseButtonSize; _headerRect = new Rectangle(0, 0, Width, headerSize); _closeButtonRect = new Rectangle(Width - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize); _colorButtonRect = new Rectangle(_closeButtonRect.Left - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize); _resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin, buttonSize, buttonSize); } /// public override void Draw() { var style = Style.Current; var color = Color; var backgroundRect = new Rectangle(Float2.Zero, Size); var headerColor = new Color(Mathf.Clamp(color.R, 0.1f, 0.3f), Mathf.Clamp(color.G, 0.1f, 0.3f), Mathf.Clamp(color.B, 0.1f, 0.3f), 0.4f); if (IsSelected) headerColor *= 2.0f; // Paint background Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), BackgroundColor); // Draw child controls DrawChildren(); // Header Render2D.FillRectangle(_headerRect, headerColor); Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center); // Close button Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey); // Color button Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey); // Check if is resizing if (_isResizing) { // Draw overlay Render2D.FillRectangle(_resizeButtonRect, Color.Orange * 0.3f); } // Resize button Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey); // Selection outline if (_isSelected) { backgroundRect.Expand(1.5f); var colorTop = Color.Orange; var colorBottom = Color.OrangeRed; Render2D.DrawRectangle(backgroundRect, colorTop, colorTop, colorBottom, colorBottom); } } /// protected override Float2 CalculateNodeSize(float width, float height) { return Size; } /// public override void OnLostFocus() { // Check if was resizing if (_isResizing) { EndResizing(); } // Base base.OnLostFocus(); } /// public override void OnEndMouseCapture() { // Check if was resizing if (_isResizing) { EndResizing(); } else { base.OnEndMouseCapture(); } } /// public override bool ContainsPoint(ref Float2 location) { return _headerRect.Contains(ref location) || _resizeButtonRect.Contains(ref location); } /// public override bool OnMouseDown(Float2 location, MouseButton button) { if (base.OnMouseDown(location, button)) return true; // Check if can start resizing if (button == MouseButton.Left && _resizeButtonRect.Contains(ref location) && Surface.CanEdit) { // Start sliding _isResizing = true; _startResizingSize = Size; StartMouseCapture(); return true; } return false; } /// public override void OnMouseMove(Float2 location) { // Check if is resizing if (_isResizing) { // Update size Size = Float2.Max(location, new Float2(140.0f, _headerRect.Bottom)); } else { // Base base.OnMouseMove(location); } } /// public override bool OnMouseDoubleClick(Float2 location, MouseButton button) { if (base.OnMouseDoubleClick(location, button)) return true; // Rename if (_headerRect.Contains(ref location) && Surface.CanEdit) { StartRenaming(); return true; } return false; } /// /// Starts the renaming of the comment. Shows the UI for the user. /// public void StartRenaming() { Surface.Select(this); var dialog = RenamePopup.Show(this, _headerRect, Title, false); dialog.Renamed += OnRenamed; } private void OnRenamed(RenamePopup renamePopup) { Title = TitleValue = renamePopup.Text; Surface.MarkAsEdited(false); } /// public override bool OnMouseUp(Float2 location, MouseButton button) { if (button == MouseButton.Left && _isResizing) { EndResizing(); return true; } if (base.OnMouseUp(location, button)) return true; // Close if (_closeButtonRect.Contains(ref location) && Surface.CanEdit) { Surface.Delete(this); return true; } // Color if (_colorButtonRect.Contains(ref location) && Surface.CanEdit) { ColorValueBox.ShowPickColorDialog?.Invoke(this, Color, OnColorChanged); return true; } return false; } private void OnColorChanged(Color color, bool sliding) { Color = ColorValue = color; Surface.MarkAsEdited(false); } } }