For general use I appreciate MyDefrag uses a pixel on the screen as the basic display unit. However, when inspecting contents of the disk it'd be useful if it was possible to make it bigger, e.g. 2x2, 4x4 or even 8x8 pixels. Starting at 4x4 they could even have a border.
Sometimes it's hard for me to point my mouse exactly at specific pixel to check the file name.
Yes I wish this option, but for me the border is not necessary; in fact it would dramatically increase the number of calls to GDI, because the blocks would need to be drawn individually, instead of by large rectangles.
In general, displaying a block should just need drawing at most three rectangles:
Let's say that the diskmap's sizes are given by (w,h) so that the rendering zone is between 0 and (w-1) horizontally, and between 0 and (h-1) vertically. Let's say that the first cluster rendered at (0,0) is number (first) when scrolling it, and that the current zoom level allows displaying (N) clusters in the current zoom level.
First round the display area according to the current "pixel" square size (currently, pixels are displayed as 1x1 "squares", but this should become a preference, independant of the "zoom level" currently defined, defined just as an integer between 1 and 8 ). This means that you have to adjust (w, h) :
w0 = w/square; h0 = h/square;
Then compute the total number of displayable "squares" in the display area: n0 = (w0*h0)
Let's say that (V) is number of representable/visible clusters (this depends of the current "zoom level" (Z), when it is 1, you are showing the map for the whole volume, and the user doesn't need to scroll the visible area) and that (N) is the total number of clusters on the whole volume:
V = N / Z.
The effective scale factor for converting cluster numbers to relative square numbers will then be (scale = n0 / V), but for precision of rendering, and speed, it must be kept as two integers rather than as floating point).
According to the zoom level and vertical scrollbar position, the "First" representable cluster will be at position (F), where (F) is necessary between (0) and (N - V) inclusive.
Now you want to render an area between clusters (c) and (c+n-1), where (n) is the number of clusters in that area (note that part or all of this area may be hidden at the current zoom level, or simply non representable as it is too small to even fill one square).
First check if this area fits, at least partly, on screen:
if (c + n <= F || c >= F + V) then exit (nothing to draw);
Convert the inclusive start and exclusive end clusters using the scale factor (M) defined above (rounding down the integer divisions):
c1 = (c - F) * n0 / V;
c2 = (c - F + n) * n0 / V;
Compute (x1,y1) for the logical square position of the start of visible area to draw:
y1 = c1 / w0;
x1 = (y1 >= 0) ? c1 % w0 : (y1 = 0);
Compute (x2,y2) for the logical square position of the end of visible aera to draw:
y2 = c2 / w0;
x2 = (y2 < h0) ? c2 % w0 : (y2 = h0, w0);
Draw 1 to 3 rectangles conditionnally:
// First rectangle, possibly the last one
if (x1 > 0) {
if(y1 == y2) {
drawRectangle(
from (x1 * square, y1 * square) inclusive
to (x2 * square, (y1 + 1)* square) exclusive);
exit;
}
drawRectangle(
from (x1 * square, y1 * square) inclusive
to (w0 * square, (y1 + 1) * square) exclusive);
x1=0; y1++;
}
// Second rectangle (conditional)
if (y1 < y2) {
drawRectangle(
from (0, y1 * square) inclusive
to (w0 * square, y2 * square) exclusive);
}
// Third rectangle (conditional)
if (x2 > 0) {
drawRectangle(
from (0, y2 * square) inclusive
to (x2 * square, (y2 + 1) * square) exclusive);
}
(Note: to simplify I have not taken account that the start of the volume is represented at the bottom of the display area: you should need to adjust the vertical coordinate negatively for GDI which uses the top as the starting position, and you still need to add the position of the display area within the window: this is assumed to be performed in the drawRectangle "call" above).
Most of the time, there will be only one rectangle drawn if it is visible, but many rectangle will not be drawn at all (because they are too small): this saves a lot of very slow GDI calls.
Note that you may speed up a bit this, if your "square" sizes are exact powers of two. In which case, some multiplications will become binary shifts.
This algorithm will not draw borders around squares: this would be too slow if there are many visible small squares on screen, with the smallest square sizes (like 3x3 drawn as 2x2 with a 1 pixel separation). But you could alternatively still use a representation in horizontal bands, without much performance impact with just a 1 pixel vertical separation between horizontal bands (bands should not be drawn for squares lower than 3x3), using an incremantal loop on (y1) for the second rectangle above.