カードの平面を越えて

ハイパーカードはバージョン2からカードとは独立した外部ウインドウを扱うことができるようになった。これを用いると、カードだけでは不可能な高度な処理も実現できる。

カードの外にあるウインドウ

ハイパーカードはその名のとおりカードを基本単位として成り立っており、情報はカード上のボタンやフィールドというオブジェクトを使って表示するようになっている。このシンプルな構造は扱いやすい反面、ここに収まらない表現、たとえば大きさを自由に変えたり移動したりといったことは、かなりトリッキーな手段を持ち出さないと難しい。

外部ウインドウとは、このハイパーカードの階層構造の外側にもう一つの「層」を作り、そこにウインドウを表示することで従来の制約を克服できるようにする仕組みだ(*注1)。カードとは独立したウインドウを使っていろいろな機能を実現するのが今回取り上げるXCMDである。

Textoid

32,000文字(半角)までのテキストをスタイル付きで表示できるウインドウを作成する。フィールドと同じような働きだが、扱い易さ、機能ともに格段に強化されている。

Textoid <wname>[,<text>[,<wstyle>] [,<color>] [,<x,y[,z,t]>] [,<textwrap>] [,<fname>] [,<fsize>] [,<fstyle>] [,<falign>] ]

必須パラメータは最初のウインドウ名のみ。3番目以降はどんな順序で与えても構わない。

WName
開くウインドウの名前を指定する。
Text
文字列、フィールド名、あるいはTEXT/stylリソース名。フィールド名を引用符でくくって与えると、そのフィールド内のスタイルをそのまま使って表示する。また、スタック内にTEXT/stylリソースを保存しておけば、文字色も含めて細かくスタイルを指定したテキストを表示できる。
WStyle
画面1に示した11種類のウインドウスタイルを選択できる。最初の3つ以外はフローティング形式、つまり常にカードより手前に出ていて隠れることがない。省略すると、スタックにRinaldoid WDEFリソースがある場合はRinaldoidZoom、なければwindoidZoomが使われる。
Color
文字と背景の色を指定。RED,BLUEなどの文字で指定する方法と、RGBを数値で表して指定する方法とある(画面2)。
X,Y[,Z,T]
ウインドウの左上あるいは四隅を指定する。省略すると"0,10"の位置に画面2のサイズで表示。
textWrap
ウインドウの端で文字列を折り返すかどうかをTRUE/FALSEで指定。省略値はTRUE
FName
表示フォント。省略値はGenevaなので、日本語表示には指定が必要。
FSize
フォントのサイズ。省略値は9.
FStyle
フォントのスタイル。表示するテキスト全体のスタイルを設定するが、<text>でフィールドやリソースを指定しているとその設定が優先される。
FAlign
行揃えをleft,right,centerで指定する。省略値はleft

このウインドウでは、テキストの編集はもちろん、lockTextプロパティをTRUEにしてマウスイベントを扱うこともできる(他にも多彩なプロパティがあるが、本文では紹介しきれないので、スタックの説明を参照していただきたい)。

さらにウインドウはユーザーの操作に応じ、カードに向けてメッセージを送る。これらのメッセージはパラメータとしてwindowName, windowIDを伴う。

OpenTextoid
ウインドウがメモリ上で作成されたとき(画面に表示される前)に発行される。これを使って、ウインドウのプロパティを設定した上で表示させることができる。
CloseTextoid
ウインドウを閉じるときに発行される。編集したテキストをファイルに保存するなどの処理を行うことができる。
ActivateTextoid
ウインドウがクリックされてアクティブになったときに送られる(フローティング型以外)
DeActivateTextoid
上の逆で、アクティブだったウインドウが非アクティブになるときに発行される(同上)。これらはsuspendStack,resumeStackと似ている。
mouseDownInTextoid, mouseUpInTextoid, DblClickInTextoid
ロックされたウインドウ上でマウスをクリックしたときにそれぞれ送られる。windowName, windowIDに加え、clicked word, start and end char, font, size, style, colorがパラメータとして送られる(ただしパラメータは255文字以上は送れないので、255文字目以降は...と省略されてしまう*注2)。

カードやバックグラウンドのスクリプトにこれらのメッセージを処理するハンドラを置くと、単なる情報表示以上の効果的な使い方が可能だ。リスト1は、ウインドウを閉じるときにその内容をテキストファイルに保存するためのスクリプトである。7行目でtextプロパティを使ってウインドウの内容を取り出し、ファイルに書き込んでいるわけだ。

Listoid

このXCMDは、外部ウインドウにリストを表示してくれる(画面3)。前回取り上げたListSelectはダイアログとしてリストを表示し、スクリプトの途中で強制的に何かを選択するような場合に有効なものだったが、こちらはスクリプトの流れとは関係なく常にリストを表示しておき、必要なときだけ項目を選択するという使い方が可能だ。スクロール型のフィールドで「行を回り込ませない」設定にしたときと似ている。

Listoid <wname>[,<list>[,<wstyle>] [,<x,y[,z,t]>] [,<no|one|con|dis>] [,<selected line(s)>] [,<fontname[,size]>] [,<separator>] [,<prompt>] [,<color>] [,<alignment>] [,"DontAllowReorg"]]

Textoidの時と同じく、必須のパラメータは最初のウインドウ名のみで、3番目以降はどんな順序で与えても構わない。Textoidと異なるものを説明する。

List
改行かコンマで区切られたリスト
NO|ONE|CON|DIS
リストの選択形式を指定する。順番に、選択不可、1つだけ選択可、連続して選択可、不連続でも選択可。省略値はONE。
selected line(s)
あらかじめ選択されている行(項目)を指定する。複数の行を指定するときはコンマで区切る。省略値は1。選択させたくないときは0を与える。
fontName[,size]
表示フォントとサイズ。省略値は"Geneva,10"なので、日本語表示には必ず指定すること。Textoidとの違いに注意。
separator
改行、コンマ以外の文字をアイテム区切り文字にするときに半角英数字を1文字指定。
prompt
他で解釈されない文字列を与えると、プロンプトとしてリストの先頭に表示される。
"DontAllowReorg"
この文字列を引数として与えると、後で述べるoptionキーによるアイテムの移動を無効にする。省略した場合は移動可。

外部ウインドウはどれもHyperTalkからプロパティを設定することによって表現方法を変えたり情報をやりとりすることができる。また、ユーザーのアクションに対応するメッセージがカードに送られるという点も共通だ。Listoidのウインドウにも多様なプロパティがあるが、多くは引数として与える値と同じなので、ここでの説明は省略しておく。メッセージは次のようなものだ。

listoidSelect
アイテムをダブルクリックしたときに送られる。パラメータとしてそのアイテムとウインドウの名前、IDが伴う。パラメータは255文字以内の制限があり、それを越えると最後が"..."となってしまう(*注2)ので、この場合はプロパティSelectedTextで内容を調べる必要がある(リスト2)。
openListoid, closeListoid
ウインドウを開閉するときに送られる。
clickInListoid
リストでのmouseUpイベントに対応する。
clickInPrompt
プロンプト部分でのmouseDownイベントに対応する。 これらはlistoidSelectを除いてはいずれもWNmane, WIDという2つのパラメータを伴ってカードに送られる。

Listoidのウインドウ特有の機能としては、次のようなものがある。

まず、

send "string" to window <wname>

という命令を実行すると、"string"で始まるアイテムを探してハイライト(選択)してくれる。また、optionキーを押しながらアイテムをドラッグすると、リスト内での順番を入れ替えることができる(この機能は、前に述べたように引数として"DontAllowReorg"を与えると働かなくなる)。

Tabloid

もう一つ、Tabloidを紹介しておこう。これはスプレッドシートのような表をウインドウ内に表示してくれるXCMDである(画面4)。こういうものをフィールドで表現しようとして四苦八苦した人も多いだろう(*注3)。数表などを扱うときには重宝するに違いない。

Tabloid <wname>[,<list>[,<wstyle>[,<x,y[,z,t]>] [,<no|one|con|dis>] [,<cell(s)>] [,<textfont[,textsize]>] [,<textalign>] [,<frame>]]

Listoidとよく似ているので、同じパラメータの説明は省略し、Tabloid独自のもののみ解説する。

cell(s)
最初に選択しておくセルを指定する。書式は行番号+スペース+列番号の形のアイテムをコンマで区切って並べたもの。"2 3,5 1"のような形になる。省略すると"1 1"、つまり左上隅のセルが選択される。何も選択しないようにするには"0 0"を与えておく。
frame
セルを区切る点線を表示するかどうかをTRUE/FALSEで設定する。省略値はTRUE。ただしTabloid LDEFリソースがスタックになければこれは無効になる。

セルの大きさは全て同じで、最大のアイテムに合わされる。一部のアイテムや列だけが大きい場合にも調整できないのが残念ではある。他のウインドウと同様に、Tabloidのウインドウもプロパティを持ち、メッセージを発行する。メッセージは:

TabloidSelect
セルをダブルクリックした時に発行される。パラメータとしてセルの内容とウインドウの名前が続く。
openTabloid, closeTabloid
ウインドウの開閉に伴って発行される。パラメータはウインドウの名前(IDはない)

ウインドウのlockTextプロパティ(最初はTRUE)をFALSEにすると、セルを編集したりフレーム(セルの境目)をドラッグして大きさを変えたりすることができる。ロックされている状態でも、optionキーを押すと一時的に同じことが可能になる。

ハイパーテキストへの応用

EasyHyperText画面

最後にTextoidを使ったハイパーテキストの応用を見てみたい。画面5に今回のサンプルスタックを示した。リストから項目タイトルを選ぶとその内容をTextoidウインドウに表示するが、そのウインドウで適当な語句をクリックすると(*注4)、その語句がタイトルリストに含まれていたら該当する項目をダイアログ表示し、新しい情報を取り出すというものだ。該当する項目が1つなら直接ウインドウをその内容に切り替える。

リスト3がクリックに対応するカードのスクリプトである。情報はテキストファイルに各項目を区切り行(目印になる文字列の行)で区切って納め、あらかじめそのタイトル一覧と区切り行の位置はスタックに登録しておく。スクリプト中の"List"フィールドがタイトルのリスト、"Pos"フィールドが区切行番号を納めるものだ。mouseUpInTextoidメッセージのパラメータでクリックした単語(what)が取得できるので、これを項目リストの中から探し出し(4行目)、対応する区切り行の情報(14行目)を使ってファイルから目的の内容を取り出してウインドウに表示する(16行目)。変数の関係がやや複雑だが、前回と同様ここさえきちんと把握すればあとは難しくない。

この仕組みで面白いのは、もとのデータには仕掛けが一切不要であるという点だ。プレーンなテキストを項目ごとに区切って用意するだけで、ハイパーテキストの出来上がり。高度なハイパーリンクには無理があるにしても、内容によっては結構実用的な使い方ができるのではないだろうか。

*注1

メッセージボックスからvwと打ち込むことで表示できる「変数表示」や、同じくmwで開ける「メッセージ表示」が外部ウインドウの例である。これらはカードを移動しても常に参照することができる。

*注2

この...はピリオド3つではなく、一文字で"..."となる、0xC9の文字。日本語フォントなら半角の「ノ」に相当する。

*注3

複数のフィールドが同時にスクロールするような工夫をしたり、モノスペースフォントを使って一つのフィールド内にうまく縦の線がそろうようにアイテムを配列するなどの方法があるが、不十分なものしかできない。

*注4

フィールドでは、the clickChunk関数を使ってクリックした単語を調べる場合、日本語はパラグラフ単位でしか認識できないという問題があったが、Textoidでは、漢字、ひらがな、英数字などの文字種によってクリックした単位を識別できる。フィールドで同様の機能を実現するには「グループ」スタイルで単語を指定する必要がある。

リスト

リスト1

 1: on closeTextoid WName,WId
 2:   answer "ウインドウ「" & WName & "」の内容を保存しますか?" with "いいえ" or "はい"
 3:   if it is "いいえ" then exit closeTextoid
 4:   ask file "保存するファイルを指定してください"
 5:   if it is "" then exit closeTextoid
 6:   open file it
 7:   write the text of window WName to file it
 8:   close file it
 9: end closeTextoid

リスト2

 1: on ListoidSelect What,WName,WID
 2:   if last char of What is numToChar(201)
 3:   then put SelectedText of window WName into What
 4:   answer "選択されたのは「" & What & "」です"
 5: end ListoidSelect

リスト3

 1: on mouseUpInTextoid wname,wid,what
 2:   set cursor to watch
 3:   put cd fld "List" into aList -- 項目のリスト
 4:   put extractItems(fullFind(aList, what, FALSE, TRUE),2) into res
 5:   if res is NOT "" then
 6:     if number of lines of res>1 then
 7:       repeat with i=1 to number of lines of res
 8:         put line (line i of res) of aList & return after showList
 9:       end repeat
10:       get ListSelect("1#",showList)
11:       if it is "" then exit mouseUpInTextoid
12:       get line it of res
13:     else get res
14:     put line it to (it+1) of cd fld "Pos" into pos
15:     put ReadMyFile() into data -- データファイルから情報を読み込む
16:     set text of window id wid to line ((line 1 of pos)+1) to ((line 2 of pos)-1) of data
17:   end if
18: end mouseUpInTextoid

(MacUser Japan, October 1996)