Sunday, May 28, 2006

 

Thinking About Proxy Points

When you work in the UI, a layout window has associated with it a transform reference point (familiarly know as its proxy point). Thus, when you select an object and manipulate it, that action can be performed using what is unambiguously the currently active proxy point.

But when an object is passed off to a function (or method) in a script for processing, how can that function know which is the appropriate proxy point to use? A quick look at these two captures of the Control palette:





should quickly convince you that the function cannot work out for itself which proxy point is active because both these were active at the same time for the same object. I happened to have it selected in two different windows and each window has its own proxy point.

So, the height and width methods I was discussing earlier today cannot of themselves know which proxy point to use when a value is passed telling them to set either the height or the width of an object. The only solution is to have another argument that carries the proxy point.

I'm thinking that this too should be an optional parameter. If it is missing, the function should work off the top left point, unless the item is directly inline to some text, in which case it needs to operate off the baseline of the containing character (which actually might not directly correspond to a proxy point at all).

And, as I write this, a nagging thought keeps surfacing: what if the item in question is a group? What then MacDuff?

 

Working with Heights and Widths

One of the frustrations of InDesign's object model is that you can't work directly with the height and width of most items (tables are an exception). PageItems, in all their flavors, come with geometricBounds (and visibleBounds, but I've seldom been moved to use that property).

Often, when working with geometry, you want to know the height or width of an object, so you'll often find yourself doing something like:
myBds = myPI.geometricBounds;
myHeight = myBds[2] - myBds[0];
where myPI is a reference to some PageItem.
Well, there's more than one problem here:
  1. The height of an object ought to take into consideration its rotation. Geometric bounds gives you the coordinates (top, left, bottom, right -- don't forget that bottom is lower on the page and therefore has a larger y value because of the way that InDesign's coordinate system works) of the bounding box, so the height returned here is the height consumed by the item's current position on the page and not its real height.
  2. It takes up two lines of code (more if we solve the rotation problem) when really all you wanted to do was:
    myHeight = myPI.height;

I confess that I don't know how to let you just write this very simple statement, but I can very easily get you a whole lot closer. Just add this method definition to your script:
Object.prototype.height = function() {
  var bds = this.geometricBounds;
  return bds[2] - bds[0];
}
and you can now get the height by simply writing:
myHeight = myPI.height();
While remembering to include the parentheses is a tad irksome, we can put to use the fact that this is a call to a method.
  1. If we want to solve the rotation problem, we can do so in the method, so the calling code's purpose remains clear and easy to read.
  2. We can extend the method to accept a parameter which would set rather than get the height.
Another confession: in all the work I've done, I don't think I've ever cared about the possibility that a page item is rotated when I've needed its height (or width). That's largely because in my own work, I've seldom used rotation and in those cases where I have, I have usually finished processing the items with my scripts before I do the rotation.

However, setting the height (or width) is something that has come up fairly often, and I've usually done that with code that clutters up my mainline scripts, making them harder to read when I need to come back to them.

It is perhaps worth a moment or two to discuss the merits of having a single height method (which returns the height if no argument is provided, but which sets the height if the first argument is a number). Perhaps having two methods: getHeight() and setHeight(ht) would be a better solution. I think this is a personal choice. In my case, I'd prefer to have just the single method. So, that's how I'll spend this Sunday morning of a holiday weekend, writing the methods height(ht) and width(wd) to return the appropriate values if the argument is missing, but to set them if present.

Wednesday, May 24, 2006

 

Let's Build a Make Fractions Script

Making fractions from already set text is at best a tedious process. An attempt was made by the OpenType fonts team to build the solution into the fonts themselves, but they quickly discovered that there is no universal solution to the problem. People type fractions in a wide variety of ways and there's no way that a font-based solution can satisfy everybody. For example, is 11/2 one and a half or eleven over two?

But a script has more freedom. For one thing, you only use it if you want to. For another, it could be configurable (e.g., it could offer an option whereby if the last three characters of a candidate fraction are one of these three: 1/2, 1/4, or 3/4, then the candidate would be treated as a fraction suffix to the number, so, in the above example with this option switched on, 11/2 would be one and a half, but with it switched off it would be eleven over two).

Perhaps more important because it is the more common case, what about fractions that are set as 1 1/2? Surely the script should get rid of that space when it converts the 1/2 to a fraction. Well, until earlier this year, I'd have said "certainly" but a project we're working on requires that the space be left there -- so, we need another option for this case.

The next problem that comes to mind is: how should the fractions, once identified, be constructed. There are a number of possibilities:

1. Switch on OpenType Fractions.
2. Use superscript and subscript character styles.
3. Use local formatting for superscript and subscript.

Perhaps the script has to be smart enough to choose among these. OpenType fractions are the best when they're available. The extent to which they're available is an issue though. Some of the Pro fonts support arbitrary fractions; others don't. Some used not to but now do, creating a scenario where text set using arbitrary fractions might work on some machines but not others -- that's a really big yuck, but one could also argue it is the price of progress. Right now, I don't know how to interrogate an OpenType font to find out what it does or does not support.

Another issue that springs to mind is the desire if using superscript and subscript to boost the weight of the font to compensate for the effects of scaling the characters to about 60% of their normal weight. A script that can't do this is a bit useless in my mind, but it raises the issue that different fonts use different names for their weights (or have different repertoires of available weights). I deal with this when setting by hand by having different fraction-creating character styles. The script, then, needs to be able to choose among fraction-creating character styles.

Maybe the script can help out by having a naming convention, but hey, projects have naming conventions for styles, so a script must surely be able to work with the user's styles. I have some vague ideas on how to solve this problem, but they're not cast strongly enough yet to present.

Another issue that springs to mind is what about "word fractions" such as numerator/denominator = result. Perhaps this is easily solved by yet another option.

Then there's the issue of mixed numbers and words. What does the script do with 129/133rds -- in particular, how should the "rds" be set?

Of course, the script has to be smart enough to realize that 5/6/06 is not a fraction, it's a date -- if you want that (or anything like it) to be a stacked fraction then you should be using a Math package of some kind. But what about 100/ or /100? Are they fractions?

Wow, the list of questions is long. I'd welcome any input on this.

Dave

This page is powered by Blogger. Isn't yours?