# How to resize the text content of a grid with it?

I am in a resizing mood these days. This code works quite well, up to a point.

Grid[Partition[
Table[Pane[Style[FromCharacterCode[96 + i], FontSize -> 150],
ImageSizeAction -> "ResizeToFit",
ImageSize -> {Scaled[1], Scaled[1]},
Alignment -> {Center, Center}], {i, 1, 25}], 5], Dividers -> All,
ItemSize -> {Scaled[.2], Scaled[.2]}]


It makes a 5x5 grid of 25 letters with boxes extending and shrinking according to the Notebook's width, and the strings centered in each box. The letters also shrink and expand accordingly. That's the minimal example of what I wanted.

But when I shrink the window a little too much, the result is clipped instead of shrinked:

And when I enlarge the window a little too much, depending on the fontsize used, the letters stop to enlarge as well, as you could probably guess, this is not what I want. Moreover, I would like the code not to be dependent on an heuristic font size.

I have tried various options but without success. Any idea, any better code ?

-
On my machine it also seems to suddenly cause problems when the window becomes to large. Both when shrinking and enlarging, it appears like a sudden switch from re-sizing to clipping. It seems like some font-sizes are better handled then others, and particularly with FontSize ->14, the given example runs quite nicely. –  jVincent Jun 11 '12 at 9:46
On win7 mma8.0.1. I get "INTERNAL SELF-TEST ERROR: NoteFont2|c|1883". Strange:) –  Ajasja Jun 11 '12 at 10:05
@Ajasja With version 8.04 for Windows (32 bit) I get the same error when the Notebook's window is maximized. –  Alexey Popkov Jun 11 '12 at 10:22
@Alexey Popkov : thanks for these reports. It is even stranger than I thought. You are welcome to forward them to WRI with my original code. –  ogerard Jun 12 '12 at 5:25

I don't think that you need to use either Dynamic as in Heike's answer, or FilledCurve as Mr. Wizard suggested. For this application I would just do it this way:

Grid[
Partition[
Table[Pane[Style[FromCharacterCode[96 + i]],
ImageSizeAction -> "ResizeToFit",
ImageSize -> Scaled[.5],
Alignment -> {Center, Center}
], {i, 1, 25}],
5],
Dividers -> All,
ItemSize -> {Scaled[.2], Scaled[.2]}]


I specified ImageSize -> Scaled[.5] to the Pane containing the glyphs. The Scaled here refers to the size of the enclosing object, which is the grid item whose size in turn is scaled with respect to the window width.

The FilledCurve approach is indeed pretty useful, especially when you have to resize the glyphs in a more unconventional way. E.g., if you want to stretch and squeeze them, as in this answer. But here it seems that you don't need that.

The Dynamic approach based on the CurrentValue of WindowSize has problems when your users have set a non-default view magnification for the notebook via the preferences. In that case the grid may look either too large for the window, or too small.

Edit

Since several answers mention the FilledCurve idea: the point of that idea is to replace the font glyphs by their outlines, represented as FilledCurve objects. The way I did that in the answer linked above is to export as PDF and re-import the result. But here, if you're going convert to outlines anyway, you may as well convert the whole grid to outlines instead of worrying about the dimensions of each cell entry individually.

Therefore, you could simply proceed as follows:

Show[
First@ImportString[ExportString[#, "PDF"],
"TextOutlines" -> True] &@
Grid[Partition[
Table[Pane[Style[FromCharacterCode[96 + i], FontSize -> 48],
ImageSize -> {Scaled[1], Scaled[1]},
Alignment -> {Center, Center}], {i, 1, 25}], 5],
Dividers -> All, ItemSize -> 4],
ImageSize -> Full]


The first three lines take your grid (from which I removed the automatic resizing entirely and replaced it with a completely rigid, fixed size), converts it to a Graphics object with outlined fonts, and then displays the result using ImageSize -> Full (I keep getting Full and All mixed up, and in an earlier edit I had accidentally used All, but it fortunately made no difference there).

The result resizes very smoothly in all its dimensions.

-
There are several changes which means this solution would work even if it didn't. Sounds weird, but my point is that removing FontSize alone from OP's code also makes it work. Though your code works as well with Fontsize->150, so thats not a big issue. What makes it work is changeing the imagesize height in pane to automatic, which you did implicitly by not specifying it. –  jVincent Jun 11 '12 at 18:35
@jVincent Since you simplified my first answer, I went back and gave a simplified version of the "outlined text" answer now... –  Jens Jun 12 '12 at 3:19
That's a nice collaboration atmosphere between all answerers. Thanks a lot. I accept this answer as the most complete but I have taken pleasure in following all the thread and plussed accordingly. –  ogerard Jun 12 '12 at 5:19

You could do something like this:

Grid[Partition[
Table[Pane[Style[FromCharacterCode[96 + i], FontSize -> 150],
ImageSizeAction -> "ResizeToFit",
ImageSize -> Dynamic[.20 CurrentValue[SelectedNotebook[], WindowSize][[1]] - 25],
Alignment -> {Center, Center}], {i, 1, 25}], 5],
Dividers -> All, Spacings -> {0, 0}]


-
That appears to work too. :-) –  Mr.Wizard Jun 11 '12 at 10:51
Good, and thanks a lot, it is a definite improvement ! But what this amounts to is saying that Pane and Grid do not know how to update their value of Width (and ImageSize) or take care of Scaled coordinates properly and implicitely and that we have to help them. –  ogerard Jun 11 '12 at 12:10
@ogerard This solution doesn't work properly when you have (like me) set the Magnification of the notebook to 1.5 in the Advanced Options of the Preferences. However, Scaled does work fine if you use it in the right place - see my answer. –  Jens Jun 11 '12 at 17:47

I'm adding this as another answer, since I believe my other answer illustrates how to carry out Mr Wizards suggested graphics transform. And it also shows that a naive implementation of this has same problem as OP. Looking through Jens's answer, the only needed change in OP's code needed to get it to work is to change the pane image size form {Scaled[1],Scaled[1]} to Scaled[1] or equivelantly {Scaled[1],Automatic}.

 Grid[Partition[
Table[Pane[Style[FromCharacterCode[96 + i], FontSize -> 150],
ImageSizeAction -> "ResizeToFit",
ImageSize -> {Scaled[1], Automatic}(* rather then {Scaled[1], Scaled[1]}*),
Alignment -> {Center, Center}], {i, 1, 25}], 5], Dividers -> All,
ItemSize -> {Scaled[.2], Scaled[.2]}]


Apperently the problem seems to be when the individual panes suddenly switch to be sized (incorrectly mind you) by their heights being scale[1] rather then the widths, even though they should be scaled by the smallest relative dimension. My best bet would be that whoever wrote the scaling algorithm assumed square content in square enclosures, though I am not certain.

-
Good observation of what could be going on. –  Jens Jun 11 '12 at 19:03
Thanks for this observation. I will keep this in mind in future applications. –  ogerard Jun 12 '12 at 5:21

Building on Mr. Wizards suggestion and Character edge finding This seems to work, but the curve conversion is a bit slow. One advantage is that the resizing of the letters is more smooth, since the normal resizeing of fonts will change the strokestyle depending on absolute size.

 stringGlyph[string_,font_] := First[First[ImportString[
ExportString[Style[string,FontSize->14,FontFamily->font],"PDF"],
"PDF","TextMode"->"Outlines"]]];

graphicsGlyph[string_,font_:"Courier New"] := Graphics[{EdgeForm[Black],FaceForm[Black],
stringGlyph[string,font]},
ImageSize->{Automatic,150}]

paneOptions = Sequence[ImageSizeAction -> "ResizeToFit", ImageMargins -> 0,
ImageSize -> {Scaled[1], Scaled[1]}, Alignment -> {Bottom, Center}];
gridOptions = Sequence[Dividers -> All, ItemSize -> {Scaled[.1], Full}];

Grid[
Table[
Pane[graphicsGlyph@FromCharacterCode[96 + i + n*5], paneOptions]
,{n, 0, 4}, {i, 1, 5}]
,gridOptions]


Scratch that, It actually has the same problems with the Pane switching from Resizing to clipping when scaling down.

-
One approach is to convert the font glyphs to Polygon or FilledCurve objects. See this answer for one method. I cannot run that code with v7 but it should be useful.