Tell me more ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I thought a simple Mathematica kerning machine (for adjusting the space between characters) would be interesting, but I'm having trouble with the locators. (There are a number of other questions related to this, and I've read the answers, but as yet without finding a solution, or understanding them that well.)

 Manipulate[
  LocatorPane[Dynamic[points],
   text = "Wolfram";
   fonts = FE`Evaluate[FEPrivate`GetPopupList["MenuListFonts"]];
   Column[{
     Button["Export", Export["/tmp/t.png", g]],
     g = Graphics[{
          MapIndexed[
          Text[Style[#1, FontSize -> fontsize, FontFamily -> font], 
            points[[First[#2]]]] &, Characters[text]]}, ImageSize -> 500]
     }]],
  {points, {Table[{ x, 0}, {x, 1, Length[Characters[text]]}]}, 
    ControlType -> None},
  {fontsize , Table[x, {x, 96, 256, 12}]} ,
  {font, fonts}
 ]

(The font menu gets populated once you use it.)

kerning machine

I want to be able to slide the letters right or left (but not up or down), but at the moment they don't move like they're supposed to.

The solution

Thanks to the fine answers, I've got something useful working. There are some kludges and hacks too, and some problems still to be ironed out (string length needs to be dynamic, 'canvas' needs resizing, and so on), but this is excellent for now.

With[{fonts = FE`Evaluate[FEPrivate`GetPopupList["MenuListFonts"]]},
 DynamicModule[{kernedText, points},
  points = Table[{x, 0}, {x, 1, Length[Characters[text]] + 10}];
  Column[{
    (* input *)
    InputField[Dynamic[text], String],
    (* main panel *)
    Panel@LocatorPane[
      Dynamic[
       points, (points = ReplacePart[#, {{_, 2} -> 0}]) &], 
      Dynamic[kernedText = 
        Graphics[{MapIndexed[
           Text[Style[#1, FontSize -> fontsize, FontFamily -> font], 
             points[[First[#2]]]] &, Characters[text]]}, 
         PlotRangePadding -> 0, 
         PlotRange -> {{0, 1 + Length[Characters[text]]}, Automatic}, 
         Background -> None, ImageSize -> 800]], Appearance -> None],
    (* controls *)
    Row[
     {
      PopupMenu[Dynamic[fontsize], Table[x, {x, 72, 416, 12}]],
      PopupMenu[Dynamic[font], fonts],
      Button["Export", 
       Export[FileNameJoin[{$HomeDirectory, "Desktop", 
          "KernedText.png"}], kernedText], 
       ImageSize -> {Full, Automatic}]
      }]
    }, Left]]]

final

I realised that the locator dots didn't need to be showing - just click on the characters. The result can be compared to the unkerned version:

Text[Style[text, 192, FontFamily -> "Palatino"]]

unkerned

For me, this area of Mathematica (Manipulate/Dynamic) is gradually becoming less confusing (but only gradually).

share|improve this question

2 Answers

up vote 5 down vote accepted

This is just an addendum to jVincent's answer. In order to constrain the letters/locators to a horizontal line, you need to use the second argument of Dynamic. The following modified version of jVincent's answer adds the needed constraint:

With[{text = "Wolfram", fontsize = 96, font = "Georgia"},
   DynamicModule[{chars, kernedText, points},
      chars = Length[Characters[text]];
      points = Table[{x, 0}, {x, 1, chars}]; 
      Column[{Panel@
         LocatorPane[
            Dynamic[points, (points = ReplacePart[#, {{_, 2} -> 0}]) &], 
            Dynamic[kernedText = 
               Graphics[
                  {
                  MapIndexed[
                     Text[Style[#1, FontSize -> fontsize,
                        FontFamily -> font], points[[First[#2]]]]&,
                     Characters[text]]
                  }, 
                  PlotRange -> {{0, 1 + chars}, Automatic},
                  ImageSize -> 450]]],
         Button["Export", 
            Export[FileNameJoin[
               {
               $HomeDirectory, "Desktop", "KernedText.png"
               }],
            kernedText],
            ImageSize -> {Full, Automatic}]},
         Right]]]

Edit

I've cleaned up my code and incorporated kguler's fix. The resulting kerned letters look pretty and export nicely.

kerned text

share|improve this answer
You can use PlotRange->{{0,10},Automatic} to fix the issue with the right-most locator. (+1) – kguler Nov 18 '12 at 22:55
Thanks. Playing with it now. – cormullion Nov 19 '12 at 11:01

First off, Dynamic[exp]] redraws whenever anything that appears in expression changes. Think of Manipulate as being just a Dynamic[code] with some nice shortcuts to build controllers that can change things that appear in code. In your case, you have a Dynamic[LocatorPane[(* some expression depending on points*)]]. So whenever someone changes points a new locatorpane will be created and displayed right where the old one was, so you won't notice... except that the active controller loses focus, so you stop dragging the controller. Here is a very short demonstration of the problem:

points = {{0, 0}};
Dynamic@LocatorPane[Dynamic[points], Graphics[Point /@ points, PlotRange -> 2]]

While just moving the Dynamic will cause only the graphic to be updated and solve the issue:

LocatorPane[Dynamic[points], Dynamic@Graphics[Point /@ points, PlotRange -> 2]]

So how to get around this problem In your case. I would suggest not using LocatorPane inside manipulate, and either fully using only manipulate, or going completely without it. Here is a possible solution without using Manipulate:

text = "Wolfram";
fontsize = 96;
font = "BankGothic";

 DynamicModule[{points = Table[{x, 0}, {x, 1, Length[Characters[text]]}]},
  LocatorPane[Dynamic[points],
   Column[{
     Button["Export", Export["/tmp/t.png", g]], 
     Dynamic[g = Graphics[{MapIndexed[
     Text[Style[#1, FontSize -> fontsize], points[[First[#2]]]] &,
      Characters[text]]}, ImageSize -> 500]]}]]
  ]
share|improve this answer
Thanks, a good solution. So you don't use LocatorPane in Manipulate, because it doesn't need to create new panes all the time... – cormullion Nov 19 '12 at 10:58
@cormullion Correct, when it creates a new locator pane, the old locators stop working, so what you where moving stops moving and it redraws.You could possibly also make it all work by using ControlType->Locator inside the Manipulate and displaying a Graphics. – jVincent Nov 19 '12 at 11:21

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.