# Grid layout problems: different sizes when rendering on Mac and Windows

From the documentation for ItemSize:

{w,h} make all items the specified width and height

and

In Grid, w is measured in ems, and h in line heights.

This implies that a specification ItemSize->{4,2} means the item is 4ems wide and 2 line heights high, which in turn suggests that the item size in pixels will be CurrentValue["FontMWidth"]*4 wide and CurrentValue["FontLineHeight"]*high. Therefore to make grids that render to a fixed number of pixels across various platforms you presumably should do (for an item of pixel dimension w,h = 100,20):

ItemSize:>{100/CurrentValue["FontMWidth"],20/CurrentValue["FontLineHeight"]}


If this is not correct stop reading now and let me know!

The problem I have is that from Mac to Windows I am unable to get the same dimensions:

img1 = Rasterize[Grid[RandomInteger[{1, 100}, {10, 8}],
Alignment -> {Center, Center},
Background -> None,
BaseStyle ->
Directive[FontFamily :> CurrentValue["PanelFontFamily"],
FontSize :> CurrentValue["PanelFontSize"],
RGBColor[0, 0, 0.25]],
Frame -> All,
FrameStyle -> Directive[AbsoluteThickness[0.5], GrayLevel[0.7]],
ItemSize :> {{80, 260, {130}}/CurrentValue["FontMWidth"],
22/CurrentValue["FontLineHeight"]},
Spacings -> {0, 0}]]


ImageDimensions[img1]


Mma 8.0.4 on Mac 10.6.8

(* {751, 224} *)


Mma 8.0.4 on on Windows 7

(* {983, 274} *)


And when we check the em widths and line heights on both systems:

Mma 8.0.4 on Mac 10.6.8

{CurrentValue["FontMWidth"], CurrentValue["FontLineHeight"]}
(* {12.9621, 9.875} *)


Mma 8.0.4 on Windows

{CurrentValue["FontMWidth"], CurrentValue["FontLineHeight"]}
(* {12.6, 10} *)


In other words similar em widths and line heights. The upshot is that I have had problems creating a grid on a Mac that doesn't go offscale when viewed on Windows.

The screen resolutions (SystemInformation["Devices", "ScreenInformation"]) are 72 for Mac and 96 for Windows. The ratio of Windows image width for Mac width is close to 96/72 but the heights are not close to that ratio at all -- but in any case there is no mention of screen resolutions in the documentation.

Does anyone have any thoughts on what is happening here and how I can get a grid of the same size on both Mac and Windows?

Edit

I think this example by @SjoerdC.deVries nails it:

Grid[{{"MMMMMMMMMMM", "MMMMMMMMMMMMMMMMMMMM"}}, ItemSize -> 5,
Spacings -> {0, 0}]


If the item size is in ems then you should expect only 5 "M" characters to fit in a grid cell ...right?

Following the comment from @Silvia I have tested Serif, Sans-serif and monospace fonts:

Sans-serif -- Helvetica gives 4Ms

Serif -- Times gives 4Ms

Monospace -- Monaco gives many Ms

Note that using lower case "m" made no difference. Note that further investigation shows that the word wrapping has an effect here. With just 5Ms the item size almost works.

Initial summary: So either the documentation is wrong, or it is incomplete, or the implementation is broken.

Subsequent summary: the problem seems to reside with how Mathematica determines the font being used when doing the size calculations. It clearly responds when StandardForm is changed but does not respond to local font usage (apparently). Otherwise an item size of x/CurrentValue["FontMWidth"] should surely deliver an item xMs wide.

Edit #2

Confirmed as a bug by WRI tech support.

-
Any thoughts? Yes: Attributes[Grid] == {Sadistic || Bugged} –  Mr.Wizard Jan 15 '13 at 4:25
@Mr.Wizard yes very frustrating. –  Mike Honeychurch Jan 15 '13 at 5:23
Do you really need it to be the exact same number of pixels or show the same amount of text? Since Windows uses more pixels to show text of the same point size, don't you actually want your grid to consume more pixels on Windows? –  Verbeia Jan 15 '13 at 5:40
@Verbeia I make a notebook of a given size containing a grid of a given size. I looks a certain way on Mac but when opened in Windows is way way too big -- and i would prefer not to have scrollbars. I have both Mac and Windows computers but would prefer not to have to make a specific version (layout) for each. Presumably with pixels the screen resolution ratios between the platforms cannot account for some of the differences but not all. If an item size is a certain number of ems then surely we just need to know how many pixels to an em on each platform?? Ditto line heights. –  Mike Honeychurch Jan 15 '13 at 5:50
Is Mathematica's definition of 'em' not the same as the accepted definition (same as point size)?. –  cormullion Jan 15 '13 at 10:41

Here are a few things I have learnt trying to find work arounds -- they may or may not be useful to others. As I indicated in my final edit to the question Wolfram tech support have indicated that the behaviour is a bug.

1: Test items size for "M" width

The font family setting for ItemStylehas no effect on how the grid cell size is determined. It is solely controlled by BaseStyle but even then monospace fonts fail.

Grid[{{"MMMMM", "MMMMMMMMMM", "MMMMMMMMMMMMMMMMMMMM"}},
Alignment -> {Left, Top},
BaseStyle -> Directive[FontFamily -> "Times", 12],
Frame -> All,
ItemSize -> 5,
Spacings -> {0, 0}]


2: Consistent grid pixel widths across platforms

A barrier is that CurrentValue["FontMWidth"] when entered as an ItemSize specification does not return the CurrentValue["FontMWidth"] of the font being used in the grid. So while something like

ItemSize->Dynamic@{100/CurrentValue["FontMWidth"],2}


might be expected to give the same pixel size per cell regardless of font it does not. A work around is to determine CurrentValue["FontMWidth"] for a given font separately. You could have a library with this information or you could do it dynamically.

This

img = Rasterize@
Grid[{{"MMMMM", Dynamic@(m1 = CurrentValue["FontMWidth"]),
"MMMMMMMMMMMMMMMMMMMM"}},
Alignment -> {Left, Top},
BaseStyle -> Directive[FontFamily -> "Times", 12],
Frame -> All,
ItemSize -> Dynamic@(size/m1),
Spacings -> {0, 0}]

ImageDimensions[img]


only works on a second and subsequent evaluation because the value of m1 isn't available the first time around. The way around this is to use Overlay

Clear[m1];

img = Rasterize@Overlay[{
Grid[{{Dynamic@(m1 = CurrentValue["FontMWidth"])}},
Alignment -> {Left, Top},
BaseStyle -> Directive[FontFamily -> "Courier", 12, White],
Frame -> All,
Spacings -> {0, 0}],
Grid[{{"MMMMM", "MMMMM", "MMMMMMMMMMMMMMMMMMMM"}},
Alignment -> {Left, Top},
BaseStyle -> Directive[FontFamily -> "Courier", 12],
Frame -> All,
ItemSize -> Dynamic@(size/m1),
Spacings -> {0, 0}]
}]

ImageDimensions[img]


On my Mac (10.6.8 V8.0.4) this renders a grid width of 302 pixels for all fonts I tried except "Georgia" which gave 305 pixels. I then switched to Windows (V8.0.4) and got the same pixel width as well as the same exception (and width) for "Georgia".

-