Skip to content

File NativeListItem{T}.cs

File List > LemonUI > LemonUI > Menus > NativeListItem{T}.cs

Go to the documentation of this file


using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;

namespace LemonUI.Menus
{
    public class NativeListItem<T> : NativeListItem, IEnumerable<T>
    {
        #region Fields

        private int index = 0;
        private List<T> items = new List<T>();

        #endregion

        #region Properties

        public int SelectedIndex
        {
            get
            {
                if (Items.Count == 0)
                {
                    return -1;
                }
                return index;
            }
            set
            {
                if (Items.Count == 0)
                {
                    throw new InvalidOperationException("There are no available items.");
                }
                if (value < 0)
                {
                    throw new InvalidOperationException("The index is under zero.");
                }
                if (value >= Items.Count)
                {
                    throw new InvalidOperationException($"The index is over the limit of {Items.Count - 1}");
                }
                if (index == value)
                {
                    return;
                }
                index = value;
                TriggerEvent(value, Direction.Unknown);
                UpdateIndex();
            }
        }
        public T SelectedItem
        {
            get
            {
                if (Items.Count == 0)
                {
                    return default;
                }

                return Items[SelectedIndex];
            }
            set
            {
                if (Items.Count == 0)
                {
                    return;
                }

                int newIndex = Items.IndexOf(value);

                if (newIndex == -1)
                {
                    throw new InvalidOperationException("The object is not the list of Items.");
                }

                SelectedIndex = newIndex;
            }
        }
        public List<T> Items
        {
            get => items;
            set
            {
                items = value;
                UpdateIndex();
            }
        }

        #endregion

        #region Events

        public event ItemChangedEventHandler<T> ItemChanged;

        #endregion

        #region Constructors

        public NativeListItem(string title, params T[] objs) : this(title, string.Empty, objs)
        {
        }
        public NativeListItem(string title, string subtitle, params T[] objs) : base(title, subtitle)
        {
            items = new List<T>();
            items.AddRange(objs);
            UpdateIndex();
        }

        #endregion

        #region Tools

        private void TriggerEvent(int index, Direction direction)
        {
            ItemChanged?.Invoke(this, new ItemChangedEventArgs<T>(items[index], index, direction));
        }
        private void FixIndexIfRequired()
        {
            if (index >= items.Count)
            {
                index = items.Count - 1;
                UpdateIndex();
            }
        }
        private void UpdateIndex()
        {
            text.Text = SelectedItem == null ? string.Empty : SelectedItem.ToString();

            text.Position = new PointF(RightArrow.Position.X - text.Width + 3, text.Position.Y);
            LeftArrow.Position = new PointF(text.Position.X - LeftArrow.Size.Width, LeftArrow.Position.Y);
        }

        #endregion

        #region Functions

        public IEnumerator<T> GetEnumerator() => Items.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
        public void Add(T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (items.Contains(item))
            {
                throw new InvalidOperationException("Item is already part of this NativeListItem.");
            }

            items.Add(item);

            if (items.Count == 1)
            {
                UpdateIndex();
            }
        }
        public void Add(int position, T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (position < 0 || position > Items.Count)
            {
                throw new ArgumentOutOfRangeException(nameof(position), "The position is out of the range of items.");
            }

            Items.Insert(position, item);

            FixIndexIfRequired();
        }
        public void Remove(T item)
        {
            if (items.Remove(item))
            {
                FixIndexIfRequired();
            }
        }
        public void RemoveAt(int position)
        {
            if (position >= items.Count)
            {
                return;
            }

            items.RemoveAt(position);
            FixIndexIfRequired();
        }
        public void Remove(Func<T, bool> pred)
        {
            if (items.RemoveAll(pred.Invoke) > 0)
            {
                FixIndexIfRequired();
            }
        }
        public void Clear()
        {
            items.Clear();

            UpdateIndex();
        }
        public override void Recalculate(PointF pos, SizeF size, bool selected)
        {
            base.Recalculate(pos, size, selected);

            text.Position = new PointF(pos.X + size.Width - RightArrow.Size.Width - 1 - text.Width, pos.Y + 3);
            LeftArrow.Position = new PointF(text.Position.X - LeftArrow.Size.Width, pos.Y + 4);
        }
        public override void GoLeft()
        {
            if (Items.Count == 0)
            {
                return;
            }

            if (index == 0)
            {
                index = Items.Count - 1;
            }
            else
            {
                index--;
            }

            TriggerEvent(index, Direction.Left);
            UpdateIndex();
        }
        public override void GoRight()
        {
            if (Items.Count == 0)
            {
                return;
            }

            if (index == Items.Count - 1)
            {
                index = 0;
            }
            else
            {
                index++;
            }

            TriggerEvent(index, Direction.Right);
            UpdateIndex();
        }
        public override void Draw()
        {
            base.Draw(); // Arrows, Title and Left Badge
            text.Draw();
        }
        public override void UpdateColors()
        {
            base.UpdateColors();

            if (!Enabled)
            {
                text.Color = Colors.TitleDisabled;
            }
            else if (lastSelected)
            {
                text.Color = Colors.TitleHovered;
            }
            else
            {
                text.Color = Colors.TitleNormal;
            }
        }

        #endregion
    }
}