<   2007年 09月 ( 2 )   > この月の画像一覧

メニュートリガー

a0011820_040189.jpg

図の一番上に示したのは BeOS を日本語で使っているとときどき見かける
「ファイル(F) 」というメニューです。ここで注目してほしいのは最後になんかゴミのような点があるところ。実はこの点、メニュー項目をキーで選択する際のトリガーである F の下に引かれるべき下線が別のところに出ているんです。

その下に示した 2 つのメニューは、BeOS R5 と Haiku で次のように作成した 4 つのメニュー項目を表示させてみたものです。

menuItem = new BMenuItem("Haiku BEOS beos rebirth", new BMessage('MNU1'));
menuItem->SetTrigger('B');
popupMenu->AddItem(menuItem);

menuItem = new BMenuItem("Haiku BEOS beos rebirth", new BMessage('MNU2'));
menuItem->SetTrigger('e');
popupMenu->AddItem(menuItem);

menuItem = new BMenuItem("はいく BEOS beos rebirth", new BMessage('MNU3'));
menuItem->SetTrigger('O');
popupMenu->AddItem(menuItem);

menuItem = new BMenuItem("はいく BEOS beos rebirth", new BMessage('MNU4'));
menuItem->SetTrigger('s');
popupMenu->AddItem(menuItem);

まずは BeOS R5 の方で上の 2 つのメニュー項目に注目。トリガーに大文字を指定しても小文字を指定しても、その区別なく、その文字が前から見つかったところに下線が引かれます。ところが、大文字で指定した方は実はキーでは操作できません。いや、もしかしたらキーに大文字が割り当てられている Keymap で試せば操作できるのかもしれませんが、そこまでは試していません。通常は小文字が割り当てられていると思うので、基本的にトリガーは小文字で指定すると考えていいでしょう。

次に BeOS R5 の残り 2 つのメニュー項目に注目。こっちは O と s を設定してあるのにとんでもないところに下線が引かれてます。どうもこれ、UTF-8 のバイト数で割り出したインデックスを文字数として計算しているようなのです。
UTF-8では「はいく BEOS beos rebirth」は「E3 81 AF E3 81 84 E3 81 8F 20 42 45 4F 53 20 62 65 6F 73 20 72 65 62 69 72 74 68」というコード列になります。「は」が「E3 81 AF」という 3 バイトで表されるわけです。
このコード列から「O」(4F あるいは 6F)を探すと前から 13 バイト目に見つかります。これは文字数で言えば前から 7 文字目になるのですが、実際に下線が引かれているのは 13 文字目ですね。マルチバイト圏のことが考慮されていないバグでしょう。

さて、このバグ、Haiku では治っているのかな~?と思って実験してみたのが図の一番下のもの。
Haiku の方でも注目して欲しいのが上の 2 つ。BeOS R5 と異なり、トリガーに指定した文字の大文字・小文字を区別して下線が引かれています。これは微妙に困ります。例えば「File」とメニューに「f」のトリガーを与える場合を考えてください。BeOS R5 では小文字を指定しないと実質動かないのですが、Haiku で小文字を指定すると(「f」はラベルに見つからないので)トリガーの下線が引かれません。BeOS R5 と Haiku の両方でうまく行くようなプログラムは作れないのです。ちなみに、Haiku、このバージョンではキーによるトリガー操作は大文字も小文字も効きませんでした。

それはそうと、残り 2 つのメニュー項目が今回の実験のメインです。結論から言うと、BeOS R5 と全く同じ不具合を持ってます。そんなところは再現しなくていいんだってば。

Haiku の BMenuItem のソースを見てみた感じでは、strchr で得たインデックスを BFont::GetEscapements() に渡しているのが悪いみたい。GetEscapements() の第 2 引数はバイト数じゃなくて文字数ですからね。
あと、ソースレベルでしか確認してませんが、BMenuItem::SetTrigger() を呼んだあとで BMenuItem::SetLabel() でラベルを変えてもトリガーの下線位置が更新されないように見えます。これもおかしいんじゃないのかな?

ある程度予想はしていたことですが Haiku も細かいところで完成度がまだまだのようです。

(2007-09-29 13:47追記
みなさんの励ましと Google 言語ツールのおかげで、なんとか Haiku プロジェクトへバグ報告しました。
http://dev.haiku-os.org/ticket/1506
)
[PR]
by hironytic | 2007-09-21 00:46 | 情報

[CoveredCalc] ダイアログコンポーネントの共通化 - 断念

ここ 1、2 ヶ月の間、CoveredCalc のダイアログ中の UI 部品を Windows と BeOS で共通化できないかと画策していました。例えばテキスト入力フィールドであれば、Windows なら Edit Control、BeOS なら BTextView が OS で用意されています。当然ながら Edit Control と BTextView ではそれをプログラムから操作する方法が全く異なります。そういうわけでダイアログを作るときは大まかにまとめられる処理だけ共通化して、部品を操作する部分は Windows と BeOS の 2 つ実装していました。これがまあ面倒なわけで、ダイアログの追加を避けて通ろうとしてしまう自分がいたわけです。
でも、必要な操作に関する共通のインタフェースがあればいいんじゃない? 操作する部分は共通のインタフェースを通じて簡潔にまとめられるんじゃない?という単純な思いつきから始めたわけですが‥‥。

この度、共通化作業を断念しました。技術的に無理なわけではありません。というか明らかに可能です。そういうことをやっているプロダクトは世の中にたくさんあります。
今回、断念に至った理由はいくつかあります。

  • 共通化作業がなかなか終わりそうにない。
  • Windows と BeOS の思想に合わせにくい。例えば Windows ではモーダルダイアログが一般的なのに対し BeOS ではモードレスダイアログであるとか、他にも BeOS ではダイアログ(というかウィンドウ)単位でスレッド(チーム)が違うとか。
  • OS 間の違いを基本的に意識しない共通インタフェースを通じて操作を行う部分が、思ったより複雑でちっとも簡潔じゃなくなってきた。
  • 共通インタフェースの実装がかなり複雑。

特に後ろ 2 つが大きな理由です。
共通インタフェースは現在使っている部品だけしか実装するつもりがありませんが、将来、機能拡張のために違う UI 部品を使いたくなったときに共通インタフェースから作らなければなりません。これは面倒だ。モチベーションが維持できない。機能拡張するのをやめてしまいそうだ(笑)その上、共通の部分まで複雑なんじゃ全く意味がない。

結局、ロクな設計をせずにちょこちょこ思いつきでやっていたのがよくなかったんですが、無意味に時間を使っちゃいましたね。
いろいろ勉強にはなった気もしますが。
[PR]
by hironytic | 2007-09-19 22:35 | 開発状況