日曜日, 11月 06, 2011

Cocoaでの縦書きの実現について

OS/X 10.7 (Lion)では、NSTextView でも日本語のような
縦書による入力が可能になった。
OS標準のテキストエディタでも縦書きができるように
なっている。じぶんではあまり縦書きの文書は書かないので
あるが、使ってみると、なかなかいい。テキストカーソルは
水平になり、変換候補も横方向に縦書きで表示されるので
とても面白い。

NSTextView でレイアウトを縦書きにするには

setLayoutOrientation: で
NSTextLayoutOrientationVertical を指定するだけでよいことが
わかった。これだけで、テキストエディタと同じように縦書きで
テキスト入力ができる。

では、NSTextViewを使わずに、NSViewに縦書きのテキストを表示する
にはどうすればいいのか?
以前調べたときCoreTextを使って実現する方法がわかったが、
結構面倒なことになってしまったが、10.7になって、もっと楽な
方法ができたようだ。
CoreTextを使わずにCocoaのテキスト関連クラスで実現できる。
 NSTextStorage
 NSTextContainer
 NSLayoutManager

このうちNSTextStorage はNSMutableAttributedStringを継承している。
つまり、テキストの書式などの属性はテキストと共にNSTextStorageに格納する。
ここで、属性として NSVerticalGlyphFormAttributeName を設定すればよいようだ。

NSTextStorage *textStorage; があるとして、

    [textStorage addAttribute:NSVerticalGlyphFormAttributeName 
                      value:[NSNumber numberWithBool:YES] range:NSMakeRange(0, [textStorage length])];


のように指定する。
これで、日本語の文字はは左に90度回転した状態で水平方向に並ぶようになる。


あとは、あなたも首を90度傾ければ、縦書き表示が実現する。

首がつかれるので、いやだ? 

冗談はさておき、最初私は、さらに90配置を変更してくれる設定があるのだろうと
探していたが、見つからなかった。
じゃあ、Drawする前に、コンテキストに90度の回転を加えれば、それらしくなる
のかなと思ったのであった。ようは首を傾けるかわりにモニターを傾けるようなものだ。
その際に、表示域の縦と横を入れ替えてTextContainerに指定すればつじつまがあいそうだ。
でも、なんかしょぼい気がするし、NSTextViewはどうやっているのか気になった。
そこでヘッダファイルの説明を読むと、90度回転して表示しているらしいとわかった。
なんだ、同じじゃん!

コンテキストを回転するには     CGContextRotateCTM で90度時計回りの回転を
指定する。私のアプリはもともと任意の角度での回転を施していたんで、回転に
90度を足すだけだった。
やってみると、非常にいいあんばいになった。
もともと水平方向の描画をコンテキストで90回転しているだけなので、
水平方向のテキストアライメント(右寄せとかセンタリングとか)がそのまま
垂直方向に働く。よって縦書きテキストが上寄せ、中央寄せ、下寄せというように。

しかし細かいところで、課題が残った。
例えば水平テキストにアンダーラインを引くと当然、それは文字の下に線が引かれる
ことになるが、垂直なテキストでの傍線は私の実現方法では左側になってしまう。
それは普通、右側に引くものか?という点が気になる。
たぶんそうだ。右利きで鉛筆で縦書きに傍線を引くとき、左側に引こうとすれば
文字が隠れてしまう。よって、右側に引くのが自然だ。
でも、縦書きの印刷物で傍線が引かれたものなんて余り見かけないような気がする。


Appleの人も右側だと考えているようだ。テキストエディタでも右側に
傍線が引かれるようになっている。
しかし、これを実現する方法は今のところわからない。


土曜日, 11月 05, 2011

NSScrollView内のNSViewの位置について

OS/X では、NSViewなどのコンテンツを表示するビューを
NSScrollView内に配置すると、そのNSViewは左下隅に貼り付く。
原点を左上隅にあわせるためには、そのNSViewのサブクラスにて
BOOL isFlipped をオーバーライドして {return YES} を
返すようにすればよい。

であるが、ウィンドウをリサイズして、NSScrollViewが小さくなったときに
表示されている内容が上にスクロールしてしまう。

(NSScrollViewは自動的にリサイズするようにしておいたとして。)

絵にするとこんな感じである。
ウィンドウをリサイズすることにつれてスクロールビューもちいさくなる。
そのとき、狭くなった分だけ、表示されている内容が上に上がってしまう。



普通のアプリケーションはそのような状態にはなっていないので、当然なんとかなるはずが
その方法がわからず、なやんだ。
Appleのサンプルプログラムのsketchの状態を調べているうちに
やっと違いが見つかった。

Interface Builder のSize Inspector でのAutosizingの設定が不足していた
ことが原因だった。
これは、コンテンツのNSViewの設定である。

不十分な設定

対策
これによって、問題が解決した。
簡単なことであったが、知らないばかりに悩んでしまった。

まあ、いつも思うことだが、複雑な解決策は何か遠回りをしているものだ。
何かを解決できずはまってしまう時は、間違った方向に難しく考えすぎている
可能性がある。また、その方向で、何とか実現できたとしても、
その方法が自分でも気に入らない時は、おそらく、まだベストではない。
もっとシンプルな方法が見つかるはずなのだ。