using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Forms;
using FeMM.Grasshopper.Helpers;
using Grasshopper;
using Grasshopper.GUI;
using Grasshopper.GUI.Canvas;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Attributes;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.Versioning;
using System.Windows.Forms;
namespace FeMM.Grasshopper.Components.Parameters
{
#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
public class LoadCombinationsParam : GH_PersistentParam<GH_Combination>
{
protected List<CaseModel> _loadCases;
public List<CaseModel> LoadCaseList => _loadCases;
public LoadCombinationsParam()
: base("Load Combinations", "LCS", "The load combinations definition", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_PARAMETERS)
{
_loadCases = [];
}
public void UpdateLoadCases(IEnumerable<CaseModel> loadCases)
{
// Recreate the LoadCase names list
_loadCases.Clear();
loadCases = loadCases.Where(lc => lc.GetType() != typeof(LoadCaseCombinationModel));
foreach (CaseModel loadCase in loadCases)
{
if (_loadCases.Count(lc => lc.Name == loadCase.Name) == 0)
_loadCases.Add(loadCase);
}
if (VolatileDataCount == 0)
return;
// Update the exiting combinations
bool changed = false;
List<GH_Combination> combinations = (List<GH_Combination>)VolatileData.get_Branch(0);
for (int i = 0; i < combinations.Count; i++)
{
GH_Combination combo = combinations[i];
// Remove the non existing values
CaseModel[] to_remove = [.. combo.Value.Values.
Where(v => !loadCases.Contains(v.Key)).
Select(c => c.Key)];
for (int j = 0; j < to_remove.Length; j++)
{
CaseModel lc = to_remove[j];
combo.Value.Values.Remove(lc);
}
if (to_remove.Length > 0)
changed = true;
foreach (CaseModel loadCase in loadCases)
{
if (!combo.Value.Values.Keys.Contains(loadCase))
combo.Value.Values.Add(loadCase, 1);
}
}
if (changed)
{
PersistentData.Clear();
SetPersistentData(combinations);
ExpireSolution(true);
}
}
protected override GH_GetterResult Prompt_Plural(ref List<GH_Combination> values)
{
return GH_GetterResult.cancel;
}
protected override GH_GetterResult Prompt_Singular(ref GH_Combination value)
{
return GH_GetterResult.success;
}
public override void CreateAttributes()
{
m_attributes = new LoadCombinationsAttributes(this);
}
public override GH_Exposure Exposure => GH_Exposure.secondary;
public override Guid ComponentGuid => new("0BE68174-01FC-4EA5-B9D9-7839A7F2C64B");
protected override Bitmap Icon => Properties.Resources.LoadCombinationsParamIcon;
}
#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
internal class LoadCombinationsAttributes : GH_ResizableAttributes<LoadCombinationsParam>
{
private Rectangle _internalRect;
protected override Size MinimumSize => new(120, 60);
protected override Size MaximumSize { get { return new Size(730, 240); } }
protected override Padding SizingBorders { get { return new Padding(10); } }
public LoadCombinationsAttributes(LoadCombinationsParam owner)
: base(owner)
{
Bounds = new RectangleF(Pivot, new Size(150, 80));
}
protected override void Layout()
{
base.Layout();
_internalRect = GH_Convert.ToRectangle(Bounds);
_internalRect.Inflate(-5, -5);
}
protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasChannel channel)
{
if (channel == GH_CanvasChannel.Objects)
{
GH_Palette palette = GH_Palette.Normal;
// Adjust palette based on the Owner's worst case messaging level.
switch (Owner.RuntimeMessageLevel)
{
case GH_RuntimeMessageLevel.Warning:
palette = GH_Palette.Warning;
break;
case GH_RuntimeMessageLevel.Error:
palette = GH_Palette.Error;
break;
}
var capsuleBox = new RectangleF(Bounds.Location, Bounds.Size);
GH_Capsule capsule = GH_Capsule.CreateCapsule(capsuleBox, palette);
capsule.AddOutputGrip(OutputGrip.Y);
capsule.Render(graphics, Selected, Owner.Locked, false);
capsule.Dispose();
using (var pen = new Pen(Color.Black))
graphics.DrawRectangle(pen, _internalRect);
var format = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center,
Trimming = StringTrimming.EllipsisCharacter
};
RectangleF textRectangle = _internalRect;
textRectangle.Y += 2;
textRectangle.Height = 20;
textRectangle.Inflate(-2, 0);
graphics.DrawString("Combinations", GH_FontServer.Standard, Brushes.Black, textRectangle, format);
format.Alignment = StringAlignment.Near;
textRectangle.X += 2;
if (!Owner.VolatileData.IsEmpty)
{
IList<GH_Combination> list = (IList<GH_Combination>)Owner.VolatileData.get_Branch(0);
for (int i = 0; i < list.Count; i++)
{
if (list[i] == null)
continue;
textRectangle.Y += textRectangle.Height;
int textLen = GH_FontServer.StringWidth(list[i].ToString(), GH_FontServer.Standard);
if (textLen <= textRectangle.Width)
textRectangle.Height = 20;
else
textRectangle.Height = GH_FontServer.Standard.Height * (float)Math.Ceiling(textLen / textRectangle.Width);
if (textRectangle.Y + textRectangle.Height + (i < list.Count - 1 ? 20 : 0) > Bounds.Y + Bounds.Height)
{
textRectangle.Height = 20;
graphics.DrawString($"{list.Count - i} more...", GH_FontServer.Standard, Brushes.Black, textRectangle, format);
break;
}
graphics.DrawString(list[i].ToString(), GH_FontServer.Standard, Brushes.Black, textRectangle, format);
}
}
else
{
textRectangle.Y += textRectangle.Height;
graphics.DrawString("No combination defined...", GH_FontServer.Standard, Brushes.Black, textRectangle, format);
}
}
else
{
base.Render(canvas, graphics, channel);
}
}
public override GH_ObjectResponse RespondToMouseDoubleClick(GH_Canvas sender, GH_CanvasMouseEvent e)
{
if (e.Button == MouseButtons.Left)
{
List<GH_Combination> list = null;
if (!Owner.VolatileData.IsEmpty)
list = (List<GH_Combination>)Owner.VolatileData.get_Branch(0);
var form = new LoadCombinationsForm([.. Owner.LoadCaseList], list);
GH_WindowsFormUtil.CenterFormOnCursor(form, true);
if (form.ShowDialog(Instances.DocumentEditor) == DialogResult.OK)
{
Owner.PersistentData.Clear();
Owner.SetPersistentData(form.Values);
Owner.ExpireSolution(true);
}
return GH_ObjectResponse.Handled;
}
return base.RespondToMouseDoubleClick(sender, e);
}
}
}