using FastReport;
using FastReport.Utils;
using InABox.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using HorizontalAlignment = System.Windows.HorizontalAlignment;
namespace InABox.Reports.CustomObjects
{
public enum DisplayType
{
///
/// Display as a grid of images
///
Grid,
///
/// Display as a list, which breaks onto new rows if necessary
///
List
}
public abstract class MultiItemObject : ReportComponentBase
{
[Category("Layout")]
public Padding Padding { get; set; }
[Category("Layout")]
public float Gap { get; set; }
///
/// Sets the number of columns in the object. If it is 0, generates the number automatically. Ignored if is .
///
[Category("Layout")]
public int Columns { get; set; }
///
/// Sets the number of rows in the object. If it is 0, generates the number automatically.
/// Ignored if is
///
[Category("Layout")]
public int Rows { get; set; }
///
/// If is true, or is 0 and not ignored,
/// sets the height of the row. Otherwise, this property is ignored.
///
[Category("Layout")]
public float RowHeight { get; set; }
///
/// The horizontal alignment of the images within their cells, if their width does not fill the cell.
/// Ignored if is .
///
[Category("Layout")]
public HorizontalAlignment HorizontalAlignment { get; set; }
///
/// The vertical alignment of the images within their cells, if their height does not fill the cell.
/// Ignored if is .
///
[Category("Layout")]
public VerticalAlignment VerticalAlignment { get; set; }
///
/// The display type of the image object
///
[Category("Layout")]
public DisplayType DisplayType { get; set; }
protected interface Item
{
float Width { get; }
float Height { get; }
}
public MultiItemObject()
{
Columns = 3;
Rows = 1;
RowHeight = 100;
CanGrow = true;
HorizontalAlignment = HorizontalAlignment.Center;
VerticalAlignment = VerticalAlignment.Top;
DisplayType = DisplayType.Grid;
}
#region Serialization
public override void Serialize(FRWriter writer)
{
base.Serialize(writer);
MultiItemObject c = writer.DiffObject as MultiItemObject;
if (Padding != c.Padding)
writer.WriteValue("Padding", Padding);
if (Gap != c.Gap)
writer.WriteValue("Gap", Gap);
if (Columns != c.Columns)
writer.WriteValue("Columns", Columns);
if (Rows != c.Rows)
writer.WriteValue("Rows", Rows);
if (RowHeight != c.RowHeight)
writer.WriteValue("RowHeight", RowHeight);
if (HorizontalAlignment != c.HorizontalAlignment)
writer.WriteValue("HorizontalAlignment", HorizontalAlignment);
if (VerticalAlignment != c.VerticalAlignment)
writer.WriteValue("VerticalAlignment", VerticalAlignment);
if (DisplayType != c.DisplayType)
writer.WriteValue("DisplayType", DisplayType);
}
#endregion
public override void Assign(Base source)
{
base.Assign(source);
if (source is MultiItemObject src)
{
Padding = src.Padding;
Gap = src.Gap;
Columns = src.Columns;
Rows = src.Rows;
RowHeight = src.RowHeight;
HorizontalAlignment = src.HorizontalAlignment;
VerticalAlignment = src.VerticalAlignment;
DisplayType = src.DisplayType;
}
}
#region Drawing
protected abstract IList- ? LoadItems();
protected abstract void DrawItem(FRPaintEventArgs e, Item item, float x, float y, float w, float h);
public override void Draw(FRPaintEventArgs e)
{
base.Draw(e);
DrawItems(e);
DrawMarkers(e);
Border.Draw(e, new RectangleF(AbsLeft, AbsTop, Width, Height));
//DrawDesign(e);
}
private void DrawGrid(FRPaintEventArgs e, IList
- items)
{
IGraphics g = e.Graphics;
float drawLeft = AbsLeft + Padding.Left;
float drawTop = AbsTop + Padding.Top;
float drawWidth = Width - Padding.Horizontal;
float drawHeight = Height - Padding.Vertical;
int numColumns, numRows;
if (Columns == 0)
{
double rows;
if (CanGrow)
{
rows = Math.Ceiling(Math.Sqrt(items.Count));
numRows = Convert.ToInt32(rows);
drawHeight = numRows * RowHeight;
numColumns = Convert.ToInt32(Math.Ceiling(items.Count / rows));
}
else
{
var cols = Math.Ceiling(Math.Sqrt(items.Count));
numColumns = Convert.ToInt32(cols);
numRows = Convert.ToInt32(Math.Ceiling(Math.Ceiling(items.Count / cols)));
}
}
else
{
numColumns = Columns;
numRows = Convert.ToInt32(Math.Ceiling(items.Count / (double)Columns));
if (CanGrow)
{
drawHeight = numRows * RowHeight;
}
}
Width = drawWidth + Padding.Horizontal;
Height = drawHeight + Padding.Vertical;
RectangleF drawRect = new RectangleF(drawLeft * e.ScaleX, drawTop * e.ScaleY, drawWidth * e.ScaleX, drawHeight * e.ScaleY);
//if (Config.IsRunningOnMono) // strange behavior of mono - we need to reset clip before we set new one
g.ResetClip();
g.SetClip(drawRect);
Report report = Report;
if (report != null && report.SmoothGraphics)
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.AntiAlias;
}
var imageWidth = (drawWidth + Gap) / numColumns - Gap;
var imageHeight = CanGrow ? RowHeight : (drawHeight + Gap) / numRows - Gap;
int column = 0;
int row = 0;
for (int i = 0; i < items.Count; i++)
{
var image = items[i];
var aspectRatio = image.Width / image.Height;
float width, height;
if (aspectRatio <= imageWidth / imageHeight)
{
height = imageHeight;
width = height * aspectRatio;
}
else
{
width = imageWidth;
height = width / aspectRatio;
}
float x = column * (imageWidth + Gap) + Padding.Left + drawLeft;
float y = row * (imageHeight + Gap) + Padding.Top + drawTop;
switch (HorizontalAlignment)
{
case HorizontalAlignment.Center:
x += imageWidth / 2 - width / 2;
break;
case HorizontalAlignment.Right:
x += imageWidth - width;
break;
case HorizontalAlignment.Stretch:
width = imageWidth;
break;
}
switch (VerticalAlignment)
{
case VerticalAlignment.Center:
y += imageHeight / 2 - height / 2;
break;
case VerticalAlignment.Bottom:
y += imageHeight - height;
break;
case VerticalAlignment.Stretch:
height = imageHeight;
break;
}
DrawItem(e, image, x, y, width, height);
if (++column >= numColumns)
{
column = 0;
row++;
}
}
}
private void DrawList(FRPaintEventArgs e, IList
- items)
{
IGraphics g = e.Graphics;
float drawLeft = AbsLeft + Padding.Left;
float drawTop = AbsTop + Padding.Top;
float drawWidth = Width - Padding.Horizontal;
float drawHeight = Height - Padding.Vertical;
float rowHeight;
if (Rows == 0)
{
rowHeight = RowHeight;
}
else
{
if (CanGrow)
{
rowHeight = RowHeight;
}
else
{
rowHeight = drawHeight / Rows;
}
}
RectangleF drawRect = new RectangleF(drawLeft * e.ScaleX, drawTop * e.ScaleY, drawWidth * e.ScaleX, drawHeight * e.ScaleY);
//if (Config.IsRunningOnMono) // strange behavior of mono - we need to reset clip before we set new one
g.ResetClip();
g.SetClip(drawRect);
Report report = Report;
if (report != null && report.SmoothGraphics)
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.AntiAlias;
}
float pointX = 0f;
float pointY = 0f;
for (int i = 0; i < items.Count; i++)
{
var image = items[i];
var aspectRatio = image.Width / image.Height;
float height = rowHeight;
float width = rowHeight * aspectRatio;
float x;
if (pointX + width > drawWidth)
{
if (pointX > 0.001f)
{
pointY += rowHeight + Gap;
}
pointX = 0;
x = 0;
}
else
{
x = pointX;
}
float y = pointY;
x += Padding.Left + drawLeft;
y += Padding.Top + drawTop;
DrawItem(e, image, x * e.ScaleX, y * e.ScaleY, width * e.ScaleX, height * e.ScaleY);
pointX += width + Gap;
}
float totalHeight = pointY + rowHeight + Padding.Vertical;
if ((CanGrow && totalHeight > Height) || (CanShrink && totalHeight < Height))
{
Height = totalHeight;
}
}
protected void DrawItems(FRPaintEventArgs e)
{
IGraphics g = e.Graphics;
var items = LoadItems();
if (items == null)
{
return;
}
IGraphicsState state = g.Save();
try
{
switch (DisplayType)
{
case DisplayType.Grid:
DrawGrid(e, items);
break;
case DisplayType.List:
DrawList(e, items);
break;
}
}
finally
{
g.Restore(state);
}
if (IsPrinting)
{
//DisposeImage();
}
}
#endregion
}
}