| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 | using FastReport;using FastReport.Utils;using System;using System.Collections.Generic;using System.ComponentModel;using System.Drawing;using System.Drawing.Drawing2D;using System.Windows;using System.Windows.Forms;using HorizontalAlignment = System.Windows.HorizontalAlignment;namespace InABox.Wpf.Reports.CustomObjects{    public enum DisplayType    {        /// <summary>        /// Display as a grid of images        /// </summary>        Grid,        /// <summary>        /// Display as a list, which breaks onto new rows if necessary        /// </summary>        List    }    public abstract class MultiItemObject : ReportComponentBase    {        [Category("Layout")]        public Padding Padding { get; set; }        [Category("Layout")]        public float Gap { get; set; }        /// <summary>        /// Sets the number of columns in the object. If it is 0, generates the number automatically. Ignored if <see cref="DisplayType"/> is <see cref="DisplayType.List"/>.        /// </summary>        [Category("Layout")]        public int Columns { get; set; }        /// <summary>        /// Sets the number of rows in the object. If it is 0, generates the number automatically.         /// Ignored if <see cref="DisplayType"/> is <see cref="DisplayType.Grid"/>        /// </summary>        [Category("Layout")]        public int Rows { get; set; }        /// <summary>        /// If <see cref="ReportComponentBase.CanGrow"/> is <c>true</c>, or <see cref="Rows"/> is 0 and not ignored,        /// sets the height of the row. Otherwise, this property is ignored.        /// </summary>        [Category("Layout")]        public float RowHeight { get; set; }        /// <summary>        /// The horizontal alignment of the images within their cells, if their width does not fill the cell.         /// Ignored if <see cref="DisplayType"/> is <see cref="DisplayType.List"/>.        /// </summary>        [Category("Layout")]        public HorizontalAlignment HorizontalAlignment { get; set; }        /// <summary>        /// The vertical alignment of the images within their cells, if their height does not fill the cell.        /// Ignored if <see cref="DisplayType"/> is <see cref="DisplayType.List"/>.        /// </summary>        [Category("Layout")]        public VerticalAlignment VerticalAlignment { get; set; }        /// <summary>        /// The display type of the image object        /// </summary>        [Category("Layout")]        public DisplayType DisplayType { get; set; }        protected interface Item        {            float Width { get; }            float Height { get; }        }        public MultiItemObject()        {            Padding = Padding.Empty;            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<Item>? 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<Item> 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<Item> 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    }}
 |