Add a block map (a colored grid where each block can be one or more blocks in the grid).

This commit is contained in:
2019-04-21 16:39:51 +01:00
parent e2d745db4a
commit b0efcddd25
2 changed files with 142 additions and 15 deletions

View File

@@ -0,0 +1,115 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
namespace DiscImageChef.Gui.Controls
{
public class BlockMap : ColoredGrid
{
ulong _sectors;
public uint blocksToRead;
public uint sectorsToRead;
public BlockMap()
{
ColoredSectors = new ObservableCollection<ColoredBlock>();
ColoredSectors.CollectionChanged += OnColoredSectorsChanged;
}
public ulong Sectors
{
get => _sectors;
set
{
_sectors = value;
CalculateBoundaries();
Invalidate();
}
}
public ulong SectorsPerBlock { get; private set; }
public uint SectorsToRead
{
get => sectorsToRead;
set
{
sectorsToRead = value;
blocksToRead = (uint)(sectorsToRead / SectorsPerBlock);
if(sectorsToRead % SectorsPerBlock > 0) blocksToRead++;
}
}
public ObservableCollection<ColoredBlock> ColoredSectors { get; }
void OnColoredSectorsChanged(object sender, NotifyCollectionChangedEventArgs args)
{
switch(args.Action)
{
case NotifyCollectionChangedAction.Add:
foreach(object item in args.NewItems)
{
if(!(item is ColoredBlock block)) continue;
for(ulong i = 0; i < blocksToRead; i++)
ColoredBlocks.Add(new ColoredBlock(block.Block / SectorsPerBlock + i, block.Color));
}
break;
case NotifyCollectionChangedAction.Move: break;
case NotifyCollectionChangedAction.Remove:
foreach(object item in args.OldItems)
{
if(!(item is ColoredBlock block)) continue;
for(ulong i = 0; i < blocksToRead; i++)
ColoredBlocks.Remove(ColoredBlocks.FirstOrDefault(t => t.Block == block.Block /
SectorsPerBlock + i));
}
break;
case NotifyCollectionChangedAction.Replace:
foreach(object item in args.OldItems)
{
if(!(item is ColoredBlock block)) continue;
for(ulong i = 0; i < blocksToRead; i++)
ColoredBlocks.Remove(ColoredBlocks.FirstOrDefault(t => t.Block == block.Block /
SectorsPerBlock + i));
}
foreach(object item in args.NewItems)
{
if(!(item is ColoredBlock block)) continue;
for(ulong i = 0; i < blocksToRead; i++)
ColoredBlocks.Add(new ColoredBlock(block.Block / SectorsPerBlock + i, block.Color));
}
break;
case NotifyCollectionChangedAction.Reset:
ColoredBlocks.Clear();
break;
default: throw new ArgumentOutOfRangeException();
}
}
void CalculateBoundaries()
{
SectorsPerBlock = Blocks == 0 ? 0 : _sectors / Blocks;
ColoredBlocks.Clear();
if(SectorsPerBlock > 0) return;
SectorsPerBlock = 1;
for(ulong i = Sectors; i < Blocks; i++) ColoredBlocks.Add(new ColoredBlock(i, GridColor));
}
public void Clear()
{
ColoredSectors.Clear();
}
}
}

View File

@@ -14,10 +14,13 @@ namespace DiscImageChef.Gui.Controls
/// </summary> /// </summary>
const int BLOCK_SIZE = 5; const int BLOCK_SIZE = 5;
Color gridColor;
public ColoredGrid() public ColoredGrid()
{ {
ColoredBlocks = new ObservableCollection<ColoredBlock>(); ColoredBlocks = new ObservableCollection<ColoredBlock>();
ColoredBlocks.CollectionChanged += (sender, args) => Invalidate(); ColoredBlocks.CollectionChanged += (sender, args) => Invalidate();
gridColor = Colors.Black;
} }
new bool CanFocus => false; new bool CanFocus => false;
@@ -32,7 +35,18 @@ namespace DiscImageChef.Gui.Controls
/// <summary> /// <summary>
/// How many blocks are in the grid /// How many blocks are in the grid
/// </summary> /// </summary>
public int Blocks { get; private set; } public ulong Blocks { get; private set; }
public Color GridColor
{
get => gridColor;
set
{
if(gridColor == value) return;
gridColor = value;
Invalidate();
}
}
public ObservableCollection<ColoredBlock> ColoredBlocks { get; } public ObservableCollection<ColoredBlock> ColoredBlocks { get; }
@@ -48,28 +62,26 @@ namespace DiscImageChef.Gui.Controls
remainder = (int)rect.Height % (BLOCK_SIZE + 1); remainder = (int)rect.Height % (BLOCK_SIZE + 1);
int height = (int)rect.Height - remainder - 1; int height = (int)rect.Height - remainder - 1;
for(float i = rect.X; i <= width; i += 5) for(float i = rect.X; i <= width; i += 5) graphics.DrawLine(gridColor, i, rect.Y, i, height);
graphics.DrawLine(Color.FromRgb(0x00000000), i, rect.Y, i, height);
for(float i = rect.Y; i <= height; i += 5) for(float i = rect.Y; i <= height; i += 5) graphics.DrawLine(gridColor, rect.X, i, width, i);
graphics.DrawLine(Color.FromRgb(0x00000000), rect.X, i, width, i);
Columns = width / BLOCK_SIZE; Columns = width / BLOCK_SIZE;
Rows = height / BLOCK_SIZE; Rows = height / BLOCK_SIZE;
Blocks = Columns * Rows; Blocks = (ulong)(Columns * Rows);
foreach(ColoredBlock coloredBlock in ColoredBlocks) foreach(ColoredBlock coloredBlock in ColoredBlocks)
PaintBlock(graphics, coloredBlock.Color, coloredBlock.Block); PaintBlock(graphics, coloredBlock.Color, coloredBlock.Block);
} }
void PaintBlock(Graphics graphics, Color color, int block) void PaintBlock(Graphics graphics, Color color, ulong block)
{ {
if(block > Blocks) return; if(block > Blocks) return;
int row = block / Columns; int row = (int)(block / (ulong)Columns);
int col = block % Columns; int col = (int)(block % (ulong)Columns);
int x = col * BLOCK_SIZE; int x = col * BLOCK_SIZE;
int y = row * BLOCK_SIZE; int y = row * BLOCK_SIZE;
graphics.FillRectangle(color, x + 1, y + 1, BLOCK_SIZE - 1, BLOCK_SIZE - 1); graphics.FillRectangle(color, x + 1, y + 1, BLOCK_SIZE - 1, BLOCK_SIZE - 1);
} }
@@ -80,10 +92,10 @@ namespace DiscImageChef.Gui.Controls
/// </summary> /// </summary>
public class ColoredBlock public class ColoredBlock
{ {
public readonly int Block; public readonly ulong Block;
public readonly Color Color; public readonly Color Color;
public ColoredBlock(int block, Color color) public ColoredBlock(ulong block, Color color)
{ {
Block = block; Block = block;
Color = color; Color = color;