Vertical Text in Java

If you're developing your application using Java on the Macintosh,
you may have noticed that Apple's Human Interface Guidelines specify
vertical text in side tabs, but Java only supports horizontal
text.

To address this, I wrote the VTextIcon class, which manages
vertical text with support for localization. VTextIcon does so using
only the Swing and Graphics2D APIs, so you should be able to use the
VTextIcon class on any Java2 platform, and in any JComponent which
supports Icons.

This article will help you learn how to display vertical text in a Swing
component such as a JTabbedPane. It is written for intermediate-level programmers.

You provide a Component so that VTextIcon knows which Font to use
when calculating the string dimensions for getIconWidth
and getIconHeight. It also invalidates the Component's
layout when the dimensions change, either because you used
setLabel to change the label or because the Component's
font changed.

The verifyRotation method determines the best
rotation based on the rotation style from rotateHint and
the characters in the label. If your label doesn't
support the style in rotateHint,
verifyRotation will return the default.

VTextIcon supports three rotation styles:

ROTATE_NONE
ROTATE_LEFT
ROTATE_RIGHT

Along with:

ROTATE_DEFAULT

Note that not all styles are available for all scripts. Roman, for
instance, can be drawn in any style, but Chinese, Japanese, and
Korean (CJK) cannot be rotated, and Arabic, Hebrew and Syriac should
be rotated.

While Unicode doesn't define the behavior for vertical text --
considering it a "formatting style” --- it does describe common
approaches:

When setting text using the Arabic script in vertical
lines, it is more common to employ a horizontal baseline that is
rotated by 90º counterclockwise so that the characters are
ordered from top to bottom. Latin text and numbers may be rotated
90º clockwise so that the characters are also ordered from
top to bottom.

So the default for Roman is ROTATE_RIGHT and for
Arabic ROTATE_LEFT, though they can be rotated in either
direction.

If Roman text isn't rotated, it should be centered

Japanese for "Japanese"It would be difficult to read if it was rotated

Here is the Arabic word for beach (shatt), showing the
individual letters and the entire word. Arabic letters take
on different forms depending on their position in the
word.

calcDimensions determines the width and height, and
also checks for special Japanese characters, as described in the next
section. recalcDimensions is used after the VTextIcon has been
created; it calls calcDimensions, then checks whether the
size has changed, and if so invalidates the Component's layout.

Japanese and Small Kana

In addition to the ideographs ("kanji"), Japanese has two
syllabaries, known as "kana." Most syllables are represented by a
single kana, but some are represented by two. In these cases the
second kana is drawn slightly smaller than the normal characters,
though it takes up the same amount of space. When drawn horizontally,
the small kana should be in the bottom-left quadrant of the space,
but when drawn vertically it goes in the top-right. Additionally,
vertical punctuation is shifted to the far top-right corner. Since
the VTextIcon can't tell Java that the kana is being drawn
vertically, it has to shift the glyph into the correct location in
paintIcon.

Vertical and horizontal small kana

Mixed-Language Strings

Because the rotated text is drawn using Graphics2D.rotate, it's
rendered by Java as if it were horizontal. This may cause undesired
effects in mixed-language strings. Unicode has this to say on mixed
Arabic and Latin:

The bidirectional algorithm also comes into effect when
some characters are ordered from bottom to top. For example, this
happens with a mixture of Arabic and Latin glyphs when all the
glyphs are rotated uniformly 90º clockwise. (The choice of
whether text is to be presented horizontally or vertically, or
whether text is to be rotated, is not specified by the Unicode
Standard, and is left up to higher-level protocols.)

It's common for mixed CJK/Roman to rotate the Roman string, but
VTextIcon does not support mixed rotation styles. The implementation
of mixed-language strings is left as the proverbial exercise for the
reader.

CompositeIcon

Since you're using your JComponent's Icon for text, does this mean
you can't have a graphical Icon? No. That's what CompositeIcon does
for you -- it takes two Icons (of any kind) and draws them with
a specified position relative to each other and orientation within
the allotted space.

/**
CompositeIcon is an Icon implementation which draws two icons
with a specified relative position:
LEFT, RIGHT, TOP, BOTTOM
specify how icon1 is drawn relative to icon2
CENTER
icon1 is drawn first, icon2 is drawn over it
and with horizontal and vertical orientations
within the allotted space
It's useful with VTextIcon when you want an icon with your text:
if icon1 is the graphic icon and icon2 is the VTextIcon,
you get a similar effect to a JLabel
with a graphic icon and text
*/

Creating a JTabbedPane With a VTextIcon

To create tabs with vertical text, first create a JTabbedPane with
LEFT or RIGHT tabs:

JTabbedPane panel = new JTabbedPane(LEFT);

Then create a VTextIcon for that panel. We'll use the default
orientation here:

VTextIcon textIcon = new VTextIcon(panel, "Mac OS X");

The test application uses one of the FileView icons, but any icon
will do: