diff --git a/.idea/.idea.DiscImageChef/.idea/contentModel.xml b/.idea/.idea.DiscImageChef/.idea/contentModel.xml
index 29e916aa9..c6fa165b2 100644
--- a/.idea/.idea.DiscImageChef/.idea/contentModel.xml
+++ b/.idea/.idea.DiscImageChef/.idea/contentModel.xml
@@ -1677,6 +1677,7 @@
+
diff --git a/DiscImageChef.Gui/Controls/ColoredGrid.cs b/DiscImageChef.Gui/Controls/ColoredGrid.cs
new file mode 100644
index 000000000..48dbe007c
--- /dev/null
+++ b/DiscImageChef.Gui/Controls/ColoredGrid.cs
@@ -0,0 +1,92 @@
+using System.Collections.ObjectModel;
+using Eto.Drawing;
+using Eto.Forms;
+
+namespace DiscImageChef.Gui.Controls
+{
+ ///
+ /// Draws a grid of colored blocks
+ ///
+ public class ColoredGrid : Drawable
+ {
+ ///
+ /// Size of the block, including its top and left border, in pixels
+ ///
+ const int BLOCK_SIZE = 5;
+
+ public ColoredGrid()
+ {
+ ColoredBlocks = new ObservableCollection();
+ ColoredBlocks.CollectionChanged += (sender, args) => Invalidate();
+ }
+
+ new bool CanFocus => false;
+ ///
+ /// How many columns are in the grid
+ ///
+ public int Columns { get; private set; }
+ ///
+ /// How many rows are in the grid
+ ///
+ public int Rows { get; private set; }
+ ///
+ /// How many blocks are in the grid
+ ///
+ public int Blocks { get; private set; }
+
+ public ObservableCollection ColoredBlocks { get; }
+
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ base.OnPaint(e);
+
+ Graphics graphics = e.Graphics;
+ RectangleF rect = e.ClipRectangle;
+
+ int remainder = (int)rect.Width % (BLOCK_SIZE + 1);
+ int width = (int)rect.Width - remainder - 1;
+ remainder = (int)rect.Height % (BLOCK_SIZE + 1);
+ int height = (int)rect.Height - remainder - 1;
+
+ for(float i = rect.X; i <= width; i += 5)
+ graphics.DrawLine(Color.FromRgb(0x00000000), i, rect.Y, i, height);
+
+ for(float i = rect.Y; i <= height; i += 5)
+ graphics.DrawLine(Color.FromRgb(0x00000000), rect.X, i, width, i);
+
+ Columns = width / BLOCK_SIZE;
+ Rows = height / BLOCK_SIZE;
+ Blocks = Columns * Rows;
+
+ foreach(ColoredBlock coloredBlock in ColoredBlocks)
+ PaintBlock(graphics, coloredBlock.Color, coloredBlock.Block);
+ }
+
+ void PaintBlock(Graphics graphics, Color color, int block)
+ {
+ if(block > Blocks) return;
+
+ int row = block / Columns;
+ int col = block % Columns;
+ int x = col * BLOCK_SIZE;
+ int y = row * BLOCK_SIZE;
+
+ graphics.FillRectangle(color, x + 1, y + 1, BLOCK_SIZE - 1, BLOCK_SIZE - 1);
+ }
+ }
+
+ ///
+ /// Defines a block that has a corresponding color
+ ///
+ public class ColoredBlock
+ {
+ public readonly int Block;
+ public readonly Color Color;
+
+ public ColoredBlock(int block, Color color)
+ {
+ Block = block;
+ Color = color;
+ }
+ }
+}
\ No newline at end of file