Files
se-launcher/PluginLoader/GUI/PluginDetails.cs

439 lines
15 KiB
C#

using PluginLoader.Data;
using PluginLoader.GUI.GuiControls;
using PluginLoader.Stats;
using PluginLoader.Stats.Model;
using Sandbox.Graphics.GUI;
using VRage.Game;
using VRage.Utils;
using VRageMath;
namespace PluginLoader.GUI;
public class PluginDetailsPanel : MyGuiControlParent
{
private readonly PluginStat dummyStat = new();
private readonly MyGuiScreenPluginConfig pluginsDialog;
private MyGuiControlLabel authorLabel;
private MyGuiControlLabel authorText;
private MyGuiControlButton configButton;
private MyGuiControlCompositePanel descriptionPanel;
private MyGuiControlMultilineText descriptionText;
private MyGuiControlButton downvoteButton;
private MyGuiControlLabel downvoteCountText;
private MyGuiControlImage downvoteIcon;
private MyGuiControlCheckbox enableCheckbox;
private MyGuiControlLabel enableLabel;
private MyGuiControlButton infoButton;
private PluginInstance instance;
// Layout management
private MyLayoutTable layoutTable;
// Plugin currently loaded into the panel or null if none are loaded
private PluginData plugin;
// Panel controls
private MyGuiControlLabel pluginNameLabel;
private MyGuiControlLabel pluginNameText;
private RatingControl ratingControl;
private MyGuiControlLabel ratingLabel;
private MyGuiControlLabel statusLabel;
private MyGuiControlLabel statusText;
private MyGuiControlButton upvoteButton;
private MyGuiControlLabel upvoteCountText;
private MyGuiControlImage upvoteIcon;
private MyGuiControlLabel usageLabel;
private MyGuiControlLabel usageText;
private MyGuiControlLabel versionLabel;
private MyGuiControlLabel versionText;
public PluginDetailsPanel(MyGuiScreenPluginConfig dialog)
{
pluginsDialog = dialog;
}
public PluginData Plugin
{
get => plugin;
set
{
if (ReferenceEquals(value, Plugin))
return;
plugin = value;
if (plugin == null)
{
DisableControls();
ClearPluginData();
return;
}
if (Main.Instance.TryGetPluginInstance(plugin.Id, out var instance))
this.instance = instance;
else
this.instance = null;
EnableControls();
LoadPluginData();
}
}
private PluginStat PluginStat => pluginsDialog.PluginStats?.Stats.GetValueOrDefault(plugin.Id) ?? dummyStat;
public event Action<PluginData, bool> OnPluginToggled;
private void DisableControls()
{
foreach (var control in Controls)
control.Enabled = false;
}
private void EnableControls()
{
foreach (var control in Controls)
control.Enabled = true;
}
private void ClearPluginData()
{
pluginNameText.Text = "";
authorText.Text = "";
versionText.Text = "";
statusText.Text = "";
usageText.Text = "";
ratingControl.Value = 0;
upvoteButton.Checked = false;
downvoteButton.Checked = false;
descriptionText.Text.Clear();
enableCheckbox.IsChecked = false;
}
public void LoadPluginData()
{
if (plugin == null)
return;
var stat = PluginStat;
var vote = stat.Vote;
var nonLocal = !plugin.IsLocal;
var canVote = (plugin.Enabled || stat.Tried) && nonLocal;
var showVotes = canVote || nonLocal;
pluginNameText.Text = plugin.FriendlyName ?? "N/A";
authorText.Text = plugin.Author ?? (plugin.IsLocal ? "Local" : "N/A");
versionText.Text = plugin.Version?.ToString() ?? "N/A";
statusLabel.Visible = nonLocal;
statusText.Visible = nonLocal;
statusText.Text = plugin.Status == PluginStatus.None
? plugin.Enabled ? "Up to date" : "N/A"
: plugin.StatusString;
usageLabel.Visible = nonLocal;
usageText.Visible = nonLocal;
usageText.Text = stat.Players.ToString();
ratingLabel.Visible = showVotes;
upvoteIcon.Visible = showVotes;
upvoteButton.Visible = canVote;
upvoteButton.Checked = vote > 0;
upvoteCountText.Visible = showVotes;
upvoteCountText.Text = $"{stat.Upvotes}";
downvoteIcon.Visible = showVotes;
downvoteButton.Visible = canVote;
downvoteButton.Checked = vote < 0;
downvoteCountText.Visible = showVotes;
downvoteCountText.Text = $"{stat.Downvotes}";
ratingControl.Value = stat.Rating;
plugin.GetDescriptionText(descriptionText);
descriptionPanel.Visible = descriptionText.Visible;
enableCheckbox.IsChecked = pluginsDialog.AfterRebootEnableFlags[plugin.Id];
configButton.Enabled = instance != null && instance.HasConfigDialog;
configButton.Visible = instance != null;
}
public virtual void CreateControls(Vector2 rightSideOrigin)
{
// Plugin name
pluginNameLabel = new()
{
Text = "Name",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
pluginNameText = new()
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
// Author
authorLabel = new()
{
Text = "Author",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
authorText = new()
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
// Version
versionLabel = new()
{
Text = "Version",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
versionText = new()
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
// Status
statusLabel = new()
{
Text = "Status",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
statusText = new()
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
// Usage
usageLabel = new()
{
Text = "Usage",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
usageText = new()
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
// Rating
ratingLabel = new()
{
Text = "Rating",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
upvoteButton = new(null, MyGuiControlButtonStyleEnum.Rectangular, onButtonClick: OnRateUpClicked,
size: new Vector2(0.03f))
{
CanHaveFocus = false
};
upvoteIcon = CreateRateIcon(upvoteButton, "Textures\\GUI\\Icons\\Blueprints\\like_test.png");
upvoteIcon.CanHaveFocus = false;
upvoteCountText = new()
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
downvoteButton = new(null, MyGuiControlButtonStyleEnum.Rectangular, onButtonClick: OnRateDownClicked,
size: new Vector2(0.03f))
{
CanHaveFocus = false
};
downvoteIcon = CreateRateIcon(downvoteButton, "Textures\\GUI\\Icons\\Blueprints\\dislike_test.png");
downvoteIcon.CanHaveFocus = false;
downvoteCountText = new()
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
ratingControl = new()
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP,
Visible = false // FIXME: Make the rating (stars) visible later! Its positioning should already be good.
};
// Plugin description
descriptionText = new()
{
Name = "DescriptionText",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP,
TextAlign = MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP,
TextBoxAlign = MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP
};
descriptionText.OnLinkClicked += (x, url) => MyGuiSandbox.OpenUrl(url, UrlOpenMode.SteamOrExternalWithConfirm);
descriptionPanel = new()
{
BackgroundTexture = MyGuiConstants.TEXTURE_RECTANGLE_DARK_BORDER
};
// Enable checkbox
enableLabel = new()
{
Text = "Enabled",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP
};
enableCheckbox = new(toolTip: "Enables loading the plugin when SE is started.")
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP,
Enabled = false
};
enableCheckbox.IsCheckedChanged += TogglePlugin;
// Info button
infoButton = new(onButtonClick: _ => Plugin?.Show())
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP,
Text = "Plugin Info"
};
// Plugin config button
configButton = new(onButtonClick: _ => instance?.OpenConfig())
{
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP,
Text = "Plugin Config"
};
LayoutControls(rightSideOrigin);
}
private void LayoutControls(Vector2 rightSideOrigin)
{
layoutTable = new(this, rightSideOrigin, new(1f, 1f));
layoutTable.SetColumnWidths(168f, 468f);
layoutTable.SetRowHeights(60f, 60f, 60f, 60f, 60f, 60f, 420f, 60f, 60f);
var row = 0;
layoutTable.Add(pluginNameLabel, MyAlignH.Left, MyAlignV.Center, row, 0);
layoutTable.Add(pluginNameText, MyAlignH.Left, MyAlignV.Center, row, 1);
row++;
layoutTable.Add(authorLabel, MyAlignH.Left, MyAlignV.Center, row, 0);
layoutTable.Add(authorText, MyAlignH.Left, MyAlignV.Center, row, 1);
row++;
layoutTable.Add(versionLabel, MyAlignH.Left, MyAlignV.Center, row, 0);
layoutTable.Add(versionText, MyAlignH.Left, MyAlignV.Center, row, 1);
row++;
layoutTable.Add(statusLabel, MyAlignH.Left, MyAlignV.Center, row, 0);
layoutTable.Add(statusText, MyAlignH.Left, MyAlignV.Center, row, 1);
row++;
layoutTable.Add(usageLabel, MyAlignH.Left, MyAlignV.Center, row, 0);
layoutTable.Add(usageText, MyAlignH.Left, MyAlignV.Center, row, 1);
row++;
layoutTable.Add(ratingLabel, MyAlignH.Left, MyAlignV.Center, row, 0);
layoutTable.Add(upvoteCountText, MyAlignH.Left, MyAlignV.Center, row, 1);
layoutTable.Add(upvoteButton, MyAlignH.Left, MyAlignV.Center, row, 1);
layoutTable.Add(upvoteIcon, MyAlignH.Left, MyAlignV.Center, row, 1);
layoutTable.Add(downvoteCountText, MyAlignH.Left, MyAlignV.Center, row, 1);
layoutTable.Add(downvoteButton, MyAlignH.Left, MyAlignV.Center, row, 1);
layoutTable.Add(downvoteIcon, MyAlignH.Left, MyAlignV.Center, row, 1);
layoutTable.Add(ratingControl, MyAlignH.Left, MyAlignV.Center, row, 1);
const float counterWidth = 0.05f;
const float spacing = 0.005f;
var buttonWidth = upvoteButton.Size.X;
var voteWidth = buttonWidth + spacing + counterWidth + 3 * spacing;
var buttonToIconOffset = new Vector2(0.004f, -0.001f);
upvoteIcon.Position = upvoteButton.Position + buttonToIconOffset;
upvoteCountText.Position = upvoteButton.Position + new Vector2(buttonWidth + spacing, 0f);
downvoteButton.Position = upvoteButton.Position + new Vector2(voteWidth, 0f);
downvoteIcon.Position = downvoteButton.Position + buttonToIconOffset;
downvoteCountText.Position = downvoteButton.Position + new Vector2(buttonWidth + spacing, 0f);
ratingControl.Position = downvoteButton.Position + new Vector2(voteWidth, 0f);
row++;
layoutTable.AddWithSize(descriptionPanel, MyAlignH.Center, MyAlignV.Top, row, 0, 1, 2);
layoutTable.AddWithSize(descriptionText, MyAlignH.Center, MyAlignV.Center, row, 0, 1, 2);
row++;
layoutTable.Add(enableLabel, MyAlignH.Left, MyAlignV.Center, row, 0);
layoutTable.Add(enableCheckbox, MyAlignH.Left, MyAlignV.Center, row, 1);
row++;
const float infoConfigSpacing = 0.015f;
layoutTable.AddWithSize(infoButton, MyAlignH.Right, MyAlignV.Center, row, 0, 1, 2);
layoutTable.AddWithSize(configButton, MyAlignH.Right, MyAlignV.Center, row, 0, 1, 2);
configButton.Position += new Vector2(0f, infoConfigSpacing);
infoButton.Position = configButton.Position + new Vector2(-configButton.Size.X - infoConfigSpacing, 0);
// row++;
var border = 0.002f * Vector2.One;
descriptionPanel.Position -= border;
descriptionPanel.Size += 2 * border;
DisableControls();
}
private void TogglePlugin(MyGuiControlCheckbox obj)
{
if (plugin == null)
return;
OnPluginToggled?.Invoke(plugin, enableCheckbox.IsChecked);
}
private void OnRateUpClicked(MyGuiControlButton button)
{
Vote(1);
}
private void OnRateDownClicked(MyGuiControlButton button)
{
Vote(-1);
}
private void Vote(int vote)
{
if (PlayerConsent.ConsentGiven)
StoreVote(vote);
else
PlayerConsent.ShowDialog(() => StoreVote(vote));
}
private void StoreVote(int vote)
{
if (!PlayerConsent.ConsentGiven || pluginsDialog.PluginStats == null)
return;
var originalStat = PluginStat;
if (originalStat.Vote == vote)
vote = 0;
var updatedStat = StatsClient.Vote(plugin.Id, vote);
if (updatedStat == null)
return;
pluginsDialog.PluginStats.Stats[plugin.Id] = updatedStat;
LoadPluginData();
}
// From Sandbox.Game.Screens.MyGuiScreenNewWorkshopGame
#region Vote buttons
private MyGuiControlImage CreateRateIcon(MyGuiControlButton button, string texture)
{
var myGuiControlImage = new MyGuiControlImage(null, null, null, null, new[] { texture });
AdjustButtonForIcon(button, myGuiControlImage);
myGuiControlImage.Size = button.Size * 0.6f;
return myGuiControlImage;
}
private void AdjustButtonForIcon(MyGuiControlButton button, MyGuiControlImage icon)
{
button.Size = new(button.Size.X, button.Size.X * 4f / 3f);
button.HighlightChanged += delegate(MyGuiControlBase control)
{
icon.ColorMask = control.HasHighlight ? MyGuiConstants.HIGHLIGHT_TEXT_COLOR : Vector4.One;
};
}
#endregion
}