read

To display the sprite thumbnails in my level editor application, I wrote a couple of simple custom controls.

The first control extends from the .NET PictureBox control, and just has an additional property to track whether it’s been selected. Then, in the OnPaint method, if the SelectablePictureBox is selected, then I draw a border over the top of it.

The second control extends from the .NET FlowLayoutPanel control, and has an event that is raised when any child SelectablePictureBox is clicked, and then some code to handle Ctrl-clicking and Shift-clicking to select and deselect individual SelectablePictureBox child controls.

The source code for both controls is below. Feel free to use it if you want to, but note that it’s pretty simple and inflexible, so the SelectableImageFlowLayoutPanel will only work with the SelectablePictureBox.

Let me know if you have any questions about it.

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace Editor
{
    public class SelectablePictureBox : PictureBox
    {
        private bool _selected = false;

        public bool Selected
        {
            get { return _selected; }
            set
            {
                _selected = value;
            }
        }

        public SelectablePictureBox()
            : base()
        {
            this.SizeMode = PictureBoxSizeMode.Zoom;
            this.BorderStyle = BorderStyle.FixedSingle;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            if (_selected)
            {
                this.BorderStyle = BorderStyle.None;
            }
            else
            {
                this.BorderStyle = BorderStyle.FixedSingle;
            }

            base.OnPaint(pe);

            if (_selected)
            {
                this.BorderStyle = BorderStyle.None;
                Pen pen = new Pen(System.Drawing.Color.CornflowerBlue, 6.0f);
                int penWidth = (int)pen.Width;
                Point[] points = new Point[5] { new Point(pe.ClipRectangle.Left, pe.ClipRectangle.Top),
                    new Point(pe.ClipRectangle.Right, pe.ClipRectangle.Top),
                    new Point(pe.ClipRectangle.Right, pe.ClipRectangle.Bottom),
                    new Point(pe.ClipRectangle.Left, pe.ClipRectangle.Bottom),
                    new Point(pe.ClipRectangle.Left, pe.ClipRectangle.Top )};
                pe.Graphics.DrawLines(pen, points);
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace Editor
{
    public class SelectableImageFlowLayoutPanel : FlowLayoutPanel
    {
        public delegate void OnSelectedIndexChanged();
        public event OnSelectedIndexChanged SelectedIndexChanged;

        public SelectableImageFlowLayoutPanel()
            : base()
        {
        }

        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);

            if (e.Control.GetType() == typeof(SelectablePictureBox))
            {
                e.Control.Click += new EventHandler(SelectablePictureBox_Click);
            }
        }

        public int SelectedIndex
        {
            get
            {
                int i = 0;
                bool found = false; ;
                foreach (Control c in Controls)
                {
                    if (((SelectablePictureBox)c).Selected)
                    {
                        found = true;
                        break;
                    }
                    i++;
                }

                if (found)
                {
                    return i;
                }
                else
                {
                    return -1;
                }
            }
            set
            {
                int i = 0;
                foreach (Control c in Controls)
                {
                    if (i == value)
                    {
                        // select controls
                        ((SelectablePictureBox)c).Selected = true;
                        // force a redraw
                        c.Invalidate();
                        break;
                    }
                    else
                    {
                        // deselect controls
                        ((SelectablePictureBox)c).Selected = false;
                        // force a redraw
                        c.Invalidate();
                    }
                    i++;
                }
            }
        }

        public List<SelectablePictureBox> SelectedItems
        {
            get
            {
                List<SelectablePictureBox> selectedItems = new List<SelectablePictureBox>();

                foreach (Control c in Controls)
                {
                    if (((SelectablePictureBox)c).Selected)
                    {
                        selectedItems.Add(((SelectablePictureBox)c));
                    }
                }
                return selectedItems;
            }
        }

        public List<SelectablePictureBox> Items
        {
            get
            {
                List<SelectablePictureBox> items = new List<SelectablePictureBox>();

                foreach (Control c in Controls)
                {
                    items.Add(((SelectablePictureBox)c));
                }
                return items;
            }
        }

        void SelectablePictureBox_Click(object sender, EventArgs e)
        {
            if (InputHelper.IsKeyDown(Keys.ControlKey))
            {
                ((SelectablePictureBox)sender).Selected = true;
                // force a redraw
                ((SelectablePictureBox)sender).Invalidate();
            }
            else if (InputHelper.IsKeyDown(Keys.ShiftKey))
            {
                int startIdx = 0, endIdx = 0;
                bool foundStart = false;

                endIdx = Controls.IndexOf(((SelectablePictureBox)sender));

                foreach (Control c in Controls)
                {
                    if (!foundStart && ((SelectablePictureBox)c).Selected)
                    {
                        foundStart = true;
                        startIdx = Controls.IndexOf(c);
                    }
                    else
                    {
                        // deselect controls
                        ((SelectablePictureBox)c).Selected = false;
                        // force a redraw
                        c.Invalidate();
                    }
                }

                if (!foundStart)
                {
                    startIdx = endIdx;
                }

                for (int i = startIdx; i <= endIdx; i++)
                {
                    // select the controls in range
                    ((SelectablePictureBox)Controls[i]).Selected = true;
                    // force a redraw
                    Controls[i].Invalidate();
                }
            }
            else
            {
                foreach (Control c in Controls)
                {
                    if (c == sender)
                    {
                        ((SelectablePictureBox)c).Selected = true;
                    }
                    else
                    {
                        ((SelectablePictureBox)c).Selected = false;
                    }
                    // force a redraw
                    c.Invalidate();
                }
            }

            if (SelectedIndexChanged != null)
            {
                SelectedIndexChanged();
            }
        }
    }
}

dylan


Published on

Dylan Black

Back to Home