HP OpenVMS Systems Documentation  | 
    
[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ]
この章では,アプリケーションでStructured Visual Navigation (SVN) ウィジェットを使用する方法について説明します。この章で使用する例は,DEC UNIX 上の/usr/examples/motifディレクトリおよびOpenVMS上のDECW$EXAMPLES ディレクトリにあるデモ用のSVNウィジェット実現例です。 このデモでは,SVNの各種リソースや関連ルーチンを数多く使用しています(SVN デモ用アプリケーションはWindows NTでは提供されません)。
SVNウィジェットはデータを階層構造で提示して,ユーザがこの構造内をナビゲートしたり, この構造から選択できるようにします。
SVNウィジェットを使用すると,SVNデモ用アプリケーションから引用した 図 9-1に示すように,情報の階層を構造的に提示することができます。 アプリケーションはSVNウィジェットにデータの構造について知らせて,SVN ウィジェットのコールバックに応答するだけです。 データを実際に表示するのはSVNウィジェットです。
もう1つの例として,DECwindows Mailアプリケーションがあります。これはSVN ウィジェットを使用して,フォルダの入っているドロアや,メッセージの入っているフォルダを作成します。 この階層を表示するときには, ドロア(情報階層の最高レベル)だけを表示することも,ドロアをオープンして, その中のすべてのフォルダを表示することも,またフォルダをオープンして, その中のすべてのメール・メッセージを表示することもできます。
アプリケーションは階層を作成して,データをSVNウィジェットに提供しなければなりません。 階層内の実データはSVNウィジェットに透過的です。
SVNを使用して階層構造の情報を3種類のフォーマット,つまりモードで表示することができます。
階層におけるSVNの各行,つまり項目は,ユーザが必要とする情報量に応じて, 構成要素と呼ばれる情報を最高30個まで表示できます。 構成要素にはテキスト,ピックスマップ,ウィジェットの3つのデータ・ タイプがあります。
プログラマが使用する構成要素としては次のものがあります。
項目の状態(開くまたは閉じる)を表す。たとえば,DECwindows Mailにおけるフォルダ・ アイコンは,クローズされているフォルダまたはオープンされているフォルダのいずれかを示すことができる。 この構成要素はDXmSvnSetComponentPixmap ルーチンを介して設定される。
DXmSvnAddEntriesルーチンで設定された,項目のサブレベル内での位置を与える。
項目を説明する短いテキスト行。このリソースはDXmSvnSetComponentText またはDXmSvnSetComponentWidgetルーチンを介して設定される。DXmSvnSetComponentText およびDXmSvnSetComponentWidget ルーチンのx引数と y引数を使用すると,説明の位置を調整できる。
ある項目を展開すると表示される項目の,数とタイプをリストする。 項目を展開すると,この数は表示される子の数とタイプを反映する。 DXmSvnGetComponentTagルーチンを使用すると,子のサマリ情報を取得できる。
構成要素のすべてがユーザに関係するわけではありません。たとえば,子のサマリは展開できない項目にとっては関係のない情報です。
SVNウィジェットには,必要に応じてアプリケーションが構成要素を挿入したり取り除くことができるルーチンがあります。 また,追加の支援ルーチンを使用すれば, 構成要素に関連するテキストを設定したり,構成要素を隠れている状態に設定したり, 構成要素の幅の設定および決定を行なったり, 構成要素の番号を決定することができます。
選択モードは,ユーザのアクションに応じて選択され反転表示される項目を指定します。DXmSvnKselectEntry 以外のモードの選択はコラム・ モードで最も有用です。1次作業ウィンドウからは完全な項目しか選択できませんが,2 次作業ウィンドウからは項目内の個々の構成要素を選択できます。
SVNウィジェットには,次の4つの選択モードがあります。
アプリケーションは,SVNウィジェットの支援ルーチンを使用して,ユーザが選んだ項目を選択できます。DXmSvnGetNumSelections ルーチンを呼び出して, 選択されている項目の数を判断したり,DXmSvnGetSelectionsルーチンを呼び出して, 選択された項目番号を返すことができます。さらに, 選択された項目を設定したり消去したりするルーチンや,選択を隠したり表示したりするルーチンもあります。
ユーザがツリー・ディスプレイ・モードを使用してデータ階層をナビゲートする場合, 階層内における項目の相対位置を見失う可能性があります。SVN ウィジェットにはナビゲーション・ウィンドウがあり,ユーザはこれを使用するとツリー・ ディスプレイ・モード内での相対位置を見つけることができます。 このナビゲーション・ウィンドウは,SVN ウィジェット内のプッシュ・ボタンによってアクティブ化されます。図 9-4 に,ナビゲーション・ウィンドウの例を示します。
DXmSvnNnavWindowTitleリソースを設定すると,このナビゲーション・ウィンドウのタイトルを指定することができます。
位置カーソルは現在の項目を囲んでいる実線の長方形です。SVNウィジェットを作成すると, 位置カーソルは省略時の設定により,ディスプレイの最初の項目の上に置かれます。 アプリケーションはDXmSvnNstartLocationCursor リソースを設定して,位置カーソルが最初にどの項目上に描かれるかを指定することができます。 このリソースは,SVN ウィジェットの作成時にのみ設定できます。
最初の項目に置かれた後,位置カーソルはかならず,前回選択された項目または切り換えた項目上に置かれます。 さらに,すべてのコールバックは, コールバック構造体で位置カーソルをもっている項目を報告します。
アプリケーションは,SVNウィジェットの支援ルーチンを使用すると,ユーザが選んだ項目を点線の長方形のボックスで囲むことによって, その項目を強調表示します。 強調表示されている項目の処理方法はアプリケーションが決定します。SVN ウィジェットは,強調表示されている項目対して特別な意味を割り当てません。
アプリケーションはDXmSvnGetNumHighlightedルーチンを呼び出して,強調表示する項目の数を決定したり,DXmSvnGetHighlighted ルーチンを呼び出して, 強調表示されている項目番号を返すことができます。
SVNウィジェットは各構成要素で読込み専用テキストと読込み/書込みテキストの両方をサポートします。
アプリケーションはDXmSvnSetComponentTextルーチンを呼び出すことによって, 読込み専用のコンパウンド・ストリング構成要素を設定し, DXmSvnGetComponentTextルーチンを呼び出すことによって,このコンパウンド・ ストリング構成要素のアドレスを取得できます。
読込み/書込みテキストの場合,アプリケーションはDXmSvnSetComponentWidget を呼び出すことにより,構成要素としてサブウィジェットを使用できます。
サブウィジェットの管理にはかなりのシステム資源が必要です。アプリケーションが読込み/ 書込みテキストをサポートする場合,ユーザが変更のために項目を選択する際に, アプリケーションはテキスト構成要素をサブウィジェット構成要素と動的に置き換えなければなりません。 たとえば, SVNデモ用アプリケーションはCSTextウィジェットをサブウィジェット構成要素として使用します。 デモ用アプリケーションでは,ユーザは読込み専用と読込み/ 書込みの各状態を切り換えることができます。
     if (Editable)
        if (node->stext == 0)
           {
             Widget primary_window;
             XtSetArg (args[0], DXmSvnNprimaryWindowWidget, &primary_window);
             XtGetValues (svnw, args, 1);
             XtSetArg (args[0], XmNvalue,    node->text);
             XtSetArg (args[1], XmNcolumns,  50        );
             XtSetArg (args[2], XmNrows,     1         );
             XtSetArg (args[3], XmNwordWrap, FALSE     );
             node->stext = DXmCreateCSText(primary_window, "TextWidget", args, 4);
           };
        if (Editable)
             DXmSvnSetComponentWidget (svnw, data->entry_number, 2,
                                       pixmap_width+4, 0, node->stext);
         else
             DXmSvnSetComponentText (svnw, data->entry_number, 2,
                                     pixmap_width+4, 0, node->text, fontlist);
SVNウィジェットを使用すれば,アプリケーションは項目の感知状態を変更することができます。DXmSvnSetEntrySensitivity ルーチンを使用すると, 項目を選択可能にすることも選択不可能にすることもできます。 DXmSvnGetEntrySensitivityルーチンは項目の感知状態を返します。
SVNウィジェットはSVNウィジェットを使用不可能にするルーチン(DXmSvnDisableDisplay) と使用可能にするルーチン(DXmSvnEnableDisplay) を備えています。これらのルーチンを使用することによって, ユーザが追加の変更を行わなくても,アプリケーションがSVN ウィジェットを変更してディスプレイを更新することができます。 たとえば,ユーザが項目を展開すると,DXmSvnDisableDisplayルーチンは, その展開が終了してアプリケーションがDXmSvnEnableDisplayルーチンを呼び出すまで, ユーザのアクションをそれ以上処理しないようにします。
アプリケーションはコールバックに応じて,SVNウィジェットを使用可能にしたり使用不可能にする必要はありません。SVN ウィジェットがコールバックを発行する前に自動的にウィジェットを使用不可能にし, 戻るとき自動的にそのウィジェットを使用可能にします。
SVNウィジェットがほかのウィジェットと異なるのは,アプリケーションが項目内の1 つ以上の構成要素を変更する必要があるとき,そのアプリケーションはDXmSvnInvalidateEntry ルーチンを呼び出して,SVNウィジェットに変更内容を反映させるという点です。
たとえば,アプリケーションがテキストを格納するためのサブウィジェット構成要素としてCSText ウィジェットを使用すると仮定します。この構成要素のテキストを変更するには, アプリケーションは次のことを実行します。
項目の構成要素はSVNウィジェット内部のものであり,XtSetArgおよびXtSetValues を呼び出して設定することはできません。ただし, DXmSvnNtreePerpendicularLinesなど,項目の構成要素に関係しないSVN のリソースは,XtSetArgおよびXtSetValuesを呼び出して設定することができます。
アプリケーションはまた,DXmSvnValidateAllルーチンを呼び出して,すべての項目に対する変更をSVN ウィジェットに反映させることもできます。
DXmSvnNuseScrollButtonsリソースはスクロール・バー上の外側の矢印を作成します。 外側の矢印は内側の矢印,つまりステップ矢印よりも大きな操作を実行します。 上向きのステップ矢印をクリックすると,ディスプレイは1 単位,つまりそのディスプレイの行数だけ上へ移動します。上向きの外側の矢印をクリックすると, ディスプレイはユーザが現在表示している階層のレベルの一番上まで移動します。DXmSvnNuseScrollButtons リソースの省略時の設定はTRUE です。
たとえば,200のメール・メッセージが入っているフォルダ内の20から40 までのメッセージが画面に表示されている場合,上向きの外側の矢印をクリックすると,1 から20までのメッセージが表示され,下向きの外側の矢印をクリックすると,180 から200までのメッセージが表示されます。
その階層がルートを1つしかもたない階層,つまりレベル・ゼロの項目を1 つだけもっている階層の場合,シフト・キーを押しながら外側の矢印上でMB1 をクリックすると,一番上または一番下までスクロールします。
階層がレベル・ゼロの項目を複数もっている場合,シフト・キーを押しながら外側の矢印上でMB1 をクリックすると,ディスプレイは各レベル・ゼロの階層の一番上または一番下までスクロールします。
DECwindows Mailのように,複数のドロア(すべてレベル0 )と複数のフォルダ( レベル1 )をもつアプリケーションでは,シフト・キーを押しながら外側の矢印上でMB1 をクリックすると,ドロアからドロア(レベル0 )へとスクロールします。MB1 をクリックすると,フォルダからフォルダへとスクロールします。
CTRL/上向き矢印およびCTRL/下向き矢印のキーボード・シーケンスは,修飾キーを使用しない場合の外側の矢印と同じ機能を実行します。
SVNウィジェットは,DXmSvnNliveScrollingリソースがTRUEに設定されているとき, アウトラインのスムースなスクロールと,コラム・ディスプレイ・ モードをサポートします。これは省略時の動作です。
ただし,DXmSvnNliveScrollingリソースをFALSEに設定すると,SVNウィジェットは インデックス・ウィンドウを実現します。インデックス・ ウィンドウはスクロール・バーにアタッチされている特別なウィンドウで, ユーザがマウス・ボタンを離したとき,ウィンドウに表示されているデータへのガイドを提供します。 アプリケーションは, DXmSvnSetEntryIndexWindowルーチンを呼び出して,項目がかならずインデックス・ ウィンドウに表示されるようにすることができます。
この節では,データ階層,SVNウィジェットの使用可能設定と使用不可能設定, 構成要素の処理,およびコールバックに関するトピックなど,SVN ウィジェットのプログラミング上の注意事項について説明します。
SVNウィジェットはアプリケーションが提供する階層構造を表示します。 階層内の実際の情報はSVNウィジェットに透過的であるため,アプリケーションが階層を作成して, テキストの各行をSVNウィジェットへ送らなければなりません。
したがって,アプリケーションは階層内のデータを追跡するメカニズムを実現する必要があります。 データは通常,最初の項目,子,兄弟として配列されます。 たとえば,SVNデモ用アプリケーションは,次のようなnode データ構造体を使用して階層を定義します。
         typedef struct node
             {
               int             level;
               int             number;
               XmString        text;
               struct node    *sibling;
               struct node    *children;
               Widget          stext;
               Boolean         opened;
             }_Node, *NodePtr;
_Nodeデータ構造体のフィールドについて,表 9-1 に説明します。
| フィールド | 説明 | 
|---|---|
| level | 子のレベル番号。 | 
| number | 子の数。 | 
| text | 項目に関連するテキスト(XmString) 。 | 
| sibling | この項目の最初の兄弟へのポインタ。 | 
| children | この項目の最初の子へのポインタ。 複数の子がある場合,その子らは最初の子の兄弟として追跡される。 | 
| stext | 項目に関連するCSText ウィジェット。 | 
| opened | 項目がオープンされているかどうか,つまり子が表示されているかどうかを示す論理値。 | 
_Nodeデータ構造体から階層におけるデータの関係を見ることができます。
例 9-1に示すコードは,SVNデモ用アプリケーションのデータ階層の一部を実現しています。B ,P1,P2などは,_Node データ構造体のタイプです。
   .
   .
   .
/*
**  Fill in the child pointers for the book, parts, and chapters
*/
    B.children   = &P1;
    P1.children  = &C11;
    P2.children  = &C21;
    P3.children  = &C31;
    P4.children  = &C41;
    P5.children  = &C51;
    P6.children  = &C61;
    P7.children  = NULL;
    C11.children  = NULL;
    C12.children  = &C121;
    C13.children  = &C131;
    C14.children  = &C141;
    C15.children  = NULL;
    C16.children  = &C161;
    C17.children  = NULL;
    C21.children  = &C211;
    C22.children  = &C221;
    C23.children  = &C231;
    C31.children  = &C311;
    C32.children  = &C321;
    C33.children  = &C331;
    C41.children  = &C411;
    C42.children  = &C421;
    C43.children  = &C431;
    C44.children  = NULL;
    C51.children  = NULL;
    C52.children  = &C521;
    C53.children  = &C531;
    C54.children  = NULL;
    C55.children  = &C551;
    C61.children  = NULL;
    C62.children  = &C621;
    C63.children  = NULL;
    C64.children  = NULL;
    C65.children  = NULL;
    C66.children  = NULL;
/*
**  Fill in the sibling pointers for the book
*/
    B.sibling     =  NULL;
/*
**  Fill in the sibling pointers for the parts
*/
    P1.sibling    =  &P2;
    P2.sibling    =  &P3;
    P3.sibling    =  &P4;
    P4.sibling    =  &P5;
    P5.sibling    =  &P6;
    P6.sibling    =  &P7;
    P7.sibling    =  NULL;
/*
**  Fill in the sibling pointers for the chapters
*/
    C11.sibling  = &C12;
    C12.sibling  = &C13;
    C13.sibling  = &C14;
    C14.sibling  = &C15;
    C15.sibling  = &C16;
    C16.sibling  = &C17;
    C17.sibling  = &P2;
    C21.sibling  = &C22;
    C22.sibling  = &C23;
    C23.sibling  = &P3;
    C31.sibling  = &C32;
    C32.sibling  = &C33;
    C33.sibling  = &P4;
    C41.sibling  = &C42;
    C42.sibling  = &C43;
    C43.sibling  = &C44;
    C44.sibling  = &P5;
    C51.sibling  = &C52;
    C52.sibling  = &C53;
    C53.sibling  = &C54;
    C54.sibling  = &C55;
    C55.sibling  = &P6;
    C61.sibling  = &C62;
    C62.sibling  = &C63;
    C63.sibling  = &C64;
    C64.sibling  = &C65;
    C65.sibling  = &C66;
    C66.sibling  = &P7;
   .
   .
   .
node->childrenフィールドは項目の最初の子へのポインタです。 P1の場合,C11からC17までの7つの子があります。最初の子には6つの兄弟があります。
C17のnode->siblingフィールドは,C21ではなくP2を指していることに注意してください。 これは,C17とC21の親が同じでないからです。 この構造はSVNデモ用アプリケーションが,コールバックで提供された entry_numberを,データ階層内の項目と同等とみなす方法を反映しています( 詳しい説明は第9.2.1.2 項を参照)。
データ配列は,アプリケーションが階層をPレベルまで戻らなくても,階層内の次の項目を見つけることができるようになっています。C21 の項目がオープンされてない場合,SVN デモのコードはC21のパスを下って,C2の最初の兄弟を見つけます。C2 の項目がオープンされている場合,C21の最後の子であるC212 は,その兄弟としてC22をもちます。
SVNウィジェットのインスタンスを作成した後は,それを階層のデータへ接続しなければなりません。 接続は,SVNウィジェットが実現されると呼び出されるDXmSvnNattachToSourceCallback コールバック・ルーチンで行われます。
アプリケーションのDXmSvnNattachToSourceCallbackコールバックは, 親/子/兄弟の階層のデータを設定し,DXmSvnAddEntriesルーチンを呼び出して, その階層における最初の項目(および項目の数)を指定します。
DXmSvnAddEntriesルーチンに必要な引数の1つは,その後ろに新しい項目を追加するための項目番号です。 最初の項目に対してはゼロです。このようにして,SVN ウィジェットは最初の項目を番号1として参照します。
アプリケーションはまた,アプリケーション固有のentry_tag引数を指定して, その項目に関連付けることもできます。
たとえば,SVNデモ用アプリケーションはDXmAddEntriesを次のように呼び出します。
         entry_tags[0] = (unsigned int) &B;
         DXmSvnAddEntries (svnw, 0, 1, 0, entry_tags, TRUE);
この呼び出しはレベルがゼロの項目を1つ(ゼロのあとから始まる)追加します。 データ階層における最初の項目のアドレスである_Nodeはタグとして渡され, ユーザがスライダをドラッグすると,その項目がスクロール・ インデックス・ウィンドウ(アクティブ化されている場合)に表示されます。
DXmSvnNattachToSourceCallbackコールバックは,項目の内容についての情報は提供しません。 その情報はGetEntryコールバックによって取得します。
アプリケーションはコールバックで提供されるentry_numberフィールドを, データ階層内の項目と同等とみなすことができなければなりません。
SVNウィジェットの番号付けは,1から始まる連番です。それ以降の項目に関連する番号は, それらの項目がオープンされ,子や兄弟をもっているかどうかによって異なります。 項目がオープンされて子をもっている場合, その子は項目番号に含まれています。そうでない場合は,兄弟だけが含まれています。
デモ用プログラムから引用した次の例を考えてみてください。コールバックの entry_numberフィールドは5の値をもっていると仮定します。
     entry_number
          1       OSF/Motif Style Guide V1.1
          2        1. User Interface Design Principles
          3        2. Input and Navigation Models
          4        3. Selection and Component Activation
          5        4. Application Design Principles
この例では,項目番号1はオープンされ,子をもっています。ただし,項目1 の子の"User Interface Design Principles"と,その子の兄弟はオープンされていません。 この場合,entry_numberの値が5ということは, ユーザが"Application Design Principles"をダブル・クリックしたことを意味しています。
その後,ユーザが項目1の子の"User Interface Design Principles"をダブル・ クリックし,それが子をもっている場合,項目番号は次のようになります。
     entry_number
          1       OSF/Motif Style Guide V1.1
          2        1. User Interface Design Principles
          3         1.1 Adopt the User's Perspective
          4         1.2 Give the User Control
          5         1.3 Use Real-World Metaphors
          6         1.4 Keep Interfaces Natural
          7         1.5 Keep Interfaces Consistent
          8         1.6 Communicate Application Actions to the User
          9         1.7 Avoid Common Design Pitfalls
         10        2. Input and Navigation Models
         11        3. Selection and Component Activation
         12        4. Application Design Principles
この場合,entry_numberの値が5ということは,ユーザが"Use Real-World Metaphors"をダブル・クリックしたことを意味しています。
SVNデモ用アプリケーションは次のコードを使用して,コード内で node_numberと呼ばれているentry_numberフィールドを,_Node データ構造体にマップします。コード内で参照している node_numberと,子があるかどうかを通知する node->numberフィールドを混同しないでください。
        .
        .
        .
     NodePtr LclGetNodePtr (node_number)
       int node_number;
     {
         int i;
         NodePtr current_node = &B;
         if (node_number != 1)
            for (i = 2;  i <= node_number;  i++)
                 if (current_node == NULL)
                      break;
                 else if (current_node->opened)
                        current_node = current_node->children;
                        else current_node = current_node->sibling;
         return current_node;
このコードは5番めの項目を探し出すためにループします。コールバックにおける entry_numberフィールドが5の値をもっていると仮定すると,このコードは親/ 兄弟の検査を4回(2から5まで)通ります。そしてcurrent_ nodeフィールドは,どの項目がオープンされているかにより,子または兄弟のいずれかのアドレスを含みます。
いったんデータがSVNウィジェットに接続されると,SVNウィジェットはDXmSvnNgetEntryCallback を呼び出して,構成要素の数や項目に関連付けるデータ階層からのテキストなど, 最初の項目に関連する情報を取得します。DXmSvnNgetEntryCallback は最初の項目だけでなく,その階層内のあらゆる項目に関する情報を取得するために呼び出されることに注意してください。
SVNデモ用アプリケーションの場合,DXmSvnNgetEntryCallbackコールバック・ ルーチンは次の機能を実行します。
アプリケーションは階層内のデータを,SVNウィジェット内の項目にリンクさせなければなりません。 これを行うために,アプリケーションのコールバック・ ルーチンは階層データの知識に基づいて,DXmSvnAddEntriesルーチンを呼び出します。
第9.2.1.1項で説明したように, SVNウィジェットは,階層における最上位の項目を項目番号1として認識しています。 ユーザがこの項目をダブル・クリックすると, DXmSvnNselectAndConfirmコールバックが生成されます。そのコールバックには項目の entry_numberが含まれており,この場合は1です(DXmSvnCallbackStruct コールバック・データ構造体については,第9.4節で説明します)。
そのコールバックはユーザがこの項目を展開(または収縮)したいことを示しています。
デモ用SVNアプリケーションの_Nodeデータ構造体には,兄弟( sibling),子(children),および要素の子が展開( opened)されているかどうかを追跡するフィールドがあります。DXmSvnNselectAndConfirm コールバック・ルーチンは,項目がまだオープンされてない場合それをオープンし, その要素がもっている子を追加するためにDXmSvnAddEntry ルーチンを呼び出します。
たとえば,ユーザが項目番号1をクリックすると,DXmSvnAddEntriesへの呼び出しが次のように変換されます。
         DXmSvnAddEntries (Svn, node_number, node->number, node->level, NULL, FALSE);
この呼び出しは項目番号1 (node_number)に4つの子(node->number)を追加します。 これら項目の実際のテキストは指定されていません。
次にSVNウィジェットは,第9.2.1.3項で説明したように, 表示されている各項目について,アプリケーションのDXmSvnNgetEntry コールバック・ルーチンを呼び出します。
SVNウィジェットのインスタンスを使用不可能すると,ユーザは選択した項目を変更できなくなり, アプリケーションがその下のデータ階層を変更できるようになります。 変更内容を期待通りに表示するには,アプリケーションはDXmSvnInvalidateEntry ルーチンを呼び出す前に,SVNウィジェットを使用不可能に しなければなりません。
次の例はSVNウィジェットを使用不可能にして,メニュー項目に関連付けられているラベル文字列を変更し, その後SVNウィジェットを使用可能にします。
     void MenuToggleEditable()
     {
     /*
     **  Local data declarations
     */
         XmString cs;
         Arg arguments[2];
     /*
     **  Disable the widget.  This would not be necessary if this routine was
     **  being called in response to an SVN callback.
     */
         DXmSvnDisableDisplay (Svn);
     /*
     **  Turn it on or off...
     */
         if (Editable)
              {
                 cs = XmStringCreate("Editable Text", XmSTRING_DEFAULT_CHARSET);
              }
         else {
                 cs = XmStringCreate("Non-editable Text", XmSTRING_DEFAULT_CHARSET);
              };
     /*
     **  Change the label
     */
         XtSetArg    (arguments[0], XmNlabelString, cs);
         XtSetValues (editableEntry, arguments, 1);
         XmStringFree (cs);
     /*
     **  Tell the source module to make the change
     */
         SourceToggleEditable();
     /*
     **  Re-enable the SVN Widget.
     */
         DXmSvnEnableDisplay (Svn);
     }
アプリケーションはDXmSvnNstartLocationCursorリソースを設定して,位置カーソルが最初にどの項目上で描かれるかを指定できます。 省略時の設定では, 位置カーソルは項目1から始まります。
このリソースはSVNウィジェットの作成時にのみ設定できます。それ以外のときは, アプリケーションはこの位置カーソルの位置を変更できません。 このリソースに関してXtSetValuesが実行されている場合,その値は無視されます。
アプリケーションは項目を無効にして,SVNウィジェットに項目を強制更新させることができます。 第9.1.9項で説明したように, アプリケーションはSVN DXmSvnInvalidateEntry ルーチンを呼び出して,項目を更新することができます。するとDXmSvnInvalidateEntry ルーチンは,DXmSvnNgetEntryCallbackコールバック・ ルーチンを呼び出して,新規の情報を取得します。
このため,DXmSvnInvalidateEntryルーチンを使用すると,アプリケーションは必要に応じてDXmSvnNgetEntryCallback を生成することができます。
次に例を示します。
     /*
     **  Traverse tree and unmanage all editable fields and invalidate
     **  the entries.
     */
         while (node_number <= SourceNumEntries)
            {
              node = LclGetNodePtr (1);
              if (node->stext)
                 XtUnmanageChild(node->stext);
              DXmSvnInvalidateEntry(Svn, node_number);
              node_number++;
            };
各項目について,関連するCSTextウィジェットがあるかどうかを調べます。 関連するCSTextウィジェットがある場合,そのウィジェットの管理を解除し,DXmSvnInvalidateEntry を呼び出して,DXmSvnNgetEntryCallback コールバックを起動します。
アプリケーションがツリー・モードにいる場合,アプリケーションは次の定数のいずれか1 つを指定して,DXmSvnNtreeStyleリソースを設定できます。
次の例はツリー・スタイルをDXmSvnKtopTreeに設定します。
         cs = XmStringCreate("Top Tree Navigation", XmSTRING_DEFAULT_CHARSET);
         XtSetArg    (arguments[0], DXmSvnNnavWindowTitle, cs);
         XtSetArg    (arguments[1], DXmSvnNtreeStyle, DXmSvnKtopTree);
         XtSetValues (Svn, arguments, 2);
         XtFree (cs);
アプリケーションは次の定数のいずれか1つを指定して, DXmSvnNdisplayModeリソースを設定できます。
次の例はディスプレイ・モードをDXmSvnKdisplayTreeに設定します。
     XtSetArg (arguments[0], DXmSvnNdisplayMode, DXmSvnKdisplayTree);
     XtSetValues (Svn, arguments, 1);
SVNウィジェットが項目を自動的に配置するため,通常,アプリケーションはそれに関与する必要がありません。 ただし,DXmSvnKuserDefinedTree のツリー・スタイルを指定する場合,SVNウィジェットはプログラマが指定するx およびy座標を使用して,項目を配置します。
アプリケーションはDXmSvnSetEntryPositionおよびDXmSvnGetEntryPosition のツールキットのルーチンを呼び出して,項目についてx とy座標を設定および取得することができます。
次の例は親の項目のxおよびy座標を取得し,すべての子のxとy座標について,30 という直接コーディングされた値を追加します。FALSEは,SVNウィジェットが位置情報を内部的に解釈することを示す論理値です。
     /*
     **  For each child, call SetEntry if the child has children.  Also set the
     **  positions in case we are in UserDefined Tree Style.
     */
         DXmSvnGetEntryPosition(Svn, node_number, FALSE, &x, &y);
         for (i = 1;  i <= node->number;  i++)
             {
               if (child_node->children != 0)
                  DXmSvnSetEntry (Svn, node_number+i, 0, 0, 2, 1, 0, FALSE);
               child_node = child_node->sibling;
               x += 30;
               y += 30;
               DXmSvnSetEntryPosition(Svn, node_number+i, FALSE, x, y);
DXmSvnPositionDisplayルーチンを使用すると,現在表示されている項目の数に関係なく, 指定した項目をディスプレイの上,中央, 下のいずれかに配置することができます。位置を指定するには, DXmSvnPositionDisplayルーチンに,SVNウィジェットのID,配置したい項目の項目番号, および次の定数のいずれか1つを与えます。
次のコード例では,tag引数が位置定数の1つを指定していることに注意してください。
     void MenuPosition (unused_w, tag)
       Widget unused_w;
       int tag;
     {
     /*
     **  Local variables
     */
         int selections [1];
     /*
     **  Only can position one entry at a time, so just get it
     */
         DXmSvnDisableDisplay(Svn);
         if ((tag != DXmSvnKpositionNextPage) && (tag != DXmSvnKpositionPreviousPage))
             DXmSvnGetSelections (Svn, selections, NULL, NULL, 1);
         DXmSvnPositionDisplay(Svn, selections[0], tag);
         DXmSvnEnableDisplay(Svn);
このルーチンへの呼び出しはコールバックの結果ではないため,SVNウィジェットを使用不可能にします。 位置がDXmSvnKpositionNextPageおよびDXmSvnKpositionPreviousPage に等しくない場合は,どの項目が現在選択されているかを調べてください。 そして,指定した位置定数に従って,それらの項目のうちの最初の項目を配置します。 その後,SVNウィジェットを使用可能にします。
SVNウィジェットの選択ルーチンを使用すると,アプリケーションは次のことが実行できます。
たとえば,次のコードは現在の選択を取得します。
     void SvnExtended (w)
       Widget w;
     {
     /*
     **  Local data declarations
     */
         int number_selected;
         int selections [50];
         int Entry_tags [50];
         int i;
     /*
     **  Ask how many were selected.
     */
         number_selected = DXmSvnGetNumSelections (w);
     /*
     **  Get those that are selected
     */
         DXmSvnGetSelections (w, selections, NULL, Entry_tags, number_selected);
この例はselections引数で現在の選択の項目番号を取得します。現在の選択数(number_selected) は,DXmSvnGetNumSelectionsルーチンによって返されます。
SVNウィジェットで複数の選択をサポートしたいときは, SvnNmultipleSelectionsリソースをTRUEに設定しなければなりません。
SVNウィジェットの各種操作ルーチンを使用すると,アプリケーションは次のことが実行できます。
次の例は項目の追加方法を示しています。
         entry_tags[0] = (unsigned int) &B;
         DXmSvnAddEntries (svnw, 0, 1, 0, entry_tags, TRUE);
ユーザがSVNデモ用アプリケーション内のある項目をダブル・クリックすると,DXmSvnNselectAndConfirm コールバック・ルーチンは,その項目がまだオープンされてない場合それをオープンし,DXmSvnAddEntry ルーチンを呼び出してその要素がもっている子を追加します。
この呼び出しはレベルがゼロの項目を1つ(ゼロのあとから始まる)追加します。 データ階層における最初の項目のアドレスである_Nodeがタグとして渡され, ユーザがスライダをドラッグすると,項目がスクロール・インデックス・ ウィンドウ(アクティブ化されている場合)に表示されます。
次の例は項目の削除方法を示しています。
         DXmSvnDeleteEntries (Svn, node_number, node->number);
after引数(この場合node_number)は,その後ろの項目を削除する項目番号です。 count 引数(この場合node->number)は,削除する項目の数です。node_number が1の値をもち,node->numberが3の値をもつと仮定すると, この例では項目2,3,4が削除されます。
項目の子を削除したい場合は,after引数で親の項目番号を,count引数でその子の数を渡します。
次の例では,項目はアプリケーション固有のtag引数の値に応じて,選択可能または選択不可能に設定されます。 このコードへの呼び出しはコールバックの結果ではないため, この例はSVNウィジェットを使用不可能に設定したのち, 使用可能に設定しています。
        .
        .
        .
     /*
     **  Disable Svn while making changes
     */
         DXmSvnDisableDisplay(Svn);
         if (tag == 0)
             while (DXmSvnGetNumSelections(Svn) > 0)
                 {
                 DXmSvnGetSelections (Svn, selections, NULL, NULL, 1);
                 DXmSvnSetEntrySensitivity(Svn, selections[0], FALSE);
                 DXmSvnClearSelection(Svn, selections[0]);
                 }
         if (tag == 1)
            for (i = 1; i <= SourceNumEntries; i++)
                 DXmSvnSetEntrySensitivity(Svn, i, TRUE);
        .
        .
        .
     /*
     **  Changes done so reenable
     */
         DXmSvnEnableDisplay(Svn);
     }
コラム・モードを使用すると,アプリケーションはSVNウィジェットのディスプレイを,1 次作業ウィンドウと2次作業ウィンドウの2つのコラムに分割できます。DXmSvnNstartColumnComponent は1次作業ウィンドウ内の最後の構成要素の番号, つまり2次作業ウィンドウに配置する構成要素の1つ前の構成要素の番号を指定します。
たとえば,次のコードは番号が4以上の構成要素を2次作業ウィンドウに置くように指定します。
        .
        .
        .
         XtSetArg (arguments[0], DXmSvnNstartColumnComponent, 3);
         XtSetArg (arguments[1], DXmSvnNcolumnLines, TRUE);
         XtSetValues (Svn, arguments, 2);
1次作業ウィンドウからは完全な項目だけを選択でき,2次作業ウィンドウでは項目内の個々の構成要素を選択できます。DXmSvnInsertComponent およびDXmSvnRemoveComponent の各ルーチンを呼び出すと,項目に構成要素を追加したり, 項目から構成要素を削除することができます。
アプリケーションがアウトライン・モードである間は,DXmSvnFlushEntry ルーチンを呼び出して,項目を画面に表示することができます。 DXmSvnFlushEntryへ渡す項目番号が,最後に表示された項目の項目番号よりも1 つ大きく,かつその項目が入るだけのスペースがある場合,その項目は見えている項目のセットに追加されます。 その項目が入るだけの空のスペースがない場合には,DXmSvnFlushEntry はその項目をスクロールします。
第9.1.1項で説明したように, 階層内の各項目は, ユーザが必要とする情報量に応じて,最高30個までの情報の 構成要素を表示できます。構成要素にはテキスト,ピックスマップ( アイコン),ウィジェットの3つのデータ・タイプがあります。
プログラマが使用する構成要素は次のとおりです。
SVNウィジェットの各種操作ルーチンを使用すると,アプリケーションは次のことが実行できます。
次の例は,アイコンとして使用するピックスマップを作成および設定する方法を示しています。
        .
        .
        .
     /*
     **  Create the pixmap.
     */
         parent_pixmap = XCreatePixmapFromBitmapData (
             display,                                /* (IN) display */
             XDefaultRootWindow(display),            /* (IN) drawable */
             parent_pixmap_bits,                     /* (IN) bitmap data */
             pixmap_width,                           /* (IN) width */
             pixmap_height,                          /* (IN) height */
             foreground_pixel,                       /* (IN) foreground pixel */
             background_pixel,                       /* (IN) background pixel */
             DefaultDepthOfScreen (screen));         /* (IN) pixmap depth */
         child_pixmap = XCreatePixmapFromBitmapData (
             display,                                /* (IN) display */
             XDefaultRootWindow(display),            /* (IN) drawable */
             child_pixmap_bits,                      /* (IN) bitmap data */
             pixmap_width,                           /* (IN) width */
             pixmap_height,                          /* (IN) height */
             foreground_pixel,                       /* (IN) foreground pixel */
             background_pixel,                       /* (IN) background pixel */
             DefaultDepthOfScreen (screen));         /* (IN) pixmap depth */
        .
        .
        .
         DXmSvnDisableDisplay(Svn);
         if (node->number == 0)
             DXmSvnSetComponentPixmap (svnw, data->entry_number, 1, 0, 0,
                                    child_pixmap,  pixmap_width, pixmap_height);
         else DXmSvnSetComponentPixmap (svnw, data->entry_number, 1, 0, 0,
                                    parent_pixmap, pixmap_width, pixmap_height);
        .
        .
        .
         DXmSvnEnableDisplay(Svn);
この例は親の項目に1つ,子のない項目に1つの,計2つの別々のピックスマップを作成します。 その後node->numberフィールドを使用して, 選択された項目が子をもつかどうかを判断し,それに従ってアイコン構成要素を設定します。 このコードへの呼び出しはコールバックの結果ではないため, この例はSVNウィジェットを使用不可能にしたのち,使用可能にします。
アプリケーションのユーザは,長い項目リストの中で特定の項目を目立たせるために, その項目を強調表示したい場合があります。強調表示のもう1 つの使用方法としては,ユーザが選択内容を確認できるように,ユーザの選択内容を強調表示することがあります。 たとえば,ユーザがある項目でMB3 を押してポップアップ・メニューを要求すると,DECwindows Mailはその項目を強調表示します。
SVNウィジェットでは,アプリケーションは点線の長方形のボックスで1つ以上の項目を囲むことによって, それらを強調表示することができます。 アプリケーションが強調表示されている項目の処理方法を決定します。 SVNウィジェットは強調表示されている項目に特別な意味を割り当てることはありません。
SVNウィジェットには,アプリケーションが次のことを実行できるルーチンがあります。
次の例はすべての項目を強調表示します。
     /*
     **  This routine is the callback for the Highlight All button
     */
     void MenuHighlightAll()
     {
         DXmSvnDisableDisplay(Svn);
         DXmSvnHighlightAll(Svn);
         DXmSvnEnableDisplay(Svn);
     }
このコードへの呼び出しはコールバックの結果ではないため,この例はSVN ウィジェットを使用不可能にしたのち,使用可能にします。
アプリケーションが強調表示を使用する場合には, DXmSvnNexpectHighlightingリソースをTRUEに設定して, 強調表示の長方形が入る余裕を残します。
SVNウィジェットには,アプリケーションがSVNウィンドウに現在表示されている項目の数を取得して, それらの項目に関連する項目番号,タグの値,y 座標を取得できるルーチンがあります。
次の例では,DXmSvnGetDisplayedは表示されている項目の項目番号を,disp_nums 引数で指定された整数の配列に返し,tag引数の値は使用せず,y 座標をdisp_ys引数に返します。disp_count引数はDXmSvnGetNumDisplayed ルーチンによって返される数です。
        .
        .
        .
     /*
     **  Local data declarations
     */
         int disp_count;
         int disp_nums [75];
         int disp_ys   [75];
         int i;
     /*
     **  Ask how many are being displayed.  If none are being displayed, then
     **  leave.
     */
         disp_count = DXmSvnGetNumDisplayed (w);
         if (disp_count == 0)
             return;
     /*
     **  Max out at 75 hardcoded
     */
         if (disp_count > 75) disp_count = 75;
     /*
     **  Get those that are displayed.  The null field is for a tag array.
     */
         DXmSvnGetDisplayed (w, disp_nums, NULL, disp_ys, disp_count);
SVNウィジェットには項目ドラッグ・メカニズムがあります。このメカニズムを使用すると, ユーザはある項目でMB2をクリックして,その項目を新しい位置にドラッグしたのちMB2 を離すことによって,その項目を移動できます。
SVNウィジェットでは,アプリケーション固有のドラッグ・メカニズムも実現できます。 アプリケーションはDXmSvnSetApplDraggingルーチンを呼び出して,SVN とアプリケーション固有のドラッグ・モードを切り換えることができます。
DXmSvnNselectionsDraggedCallbackコールバック・ルーチンがNULLでなく, アプリケーション固有のドラッグが設定されてない場合,MB2を使用して項目をドラッグすると, コールバックが生成されます。SVNウィジェットがドラッグ機能を実現し, アプリケーションはこのコールバックを使用して, ドラッグ関連の機能を実行することができます。
アプリケーションがDXmSvnSetApplDraggingルーチンを呼び出して,アプリケーション固有のドラッグ・ モードを設定する場合,ユーザがMB2を押すと,DXmSvnNdraggingCallback が生成されます。アプリケーションのドラッグが終了すると,DXmSvnNdraggingEndCallback が生成されます。アプリケーション固有のドラッグを使用する場合には, プログラマがそのコールバック・ ルーチンを与えなければなりません。
第9.2.16項で説明したように,SVN ウィジェットではアプリケーション固有の項目ドラッグ・ メカニズムを実現できます。 このドラッグ・メカニズムの一部として,アプリケーションは,項目を移動するとそれに追随する「ゴースト」イメージの図形, サイズ,および相対的な原点x とyを定義できます。
ゴーストの各種リソースは次のとおりです。
次の例はゴースト・イメージのxおよびyオフセットを取得し,現在の選択, つまり現在移動している項目を取得して,新しい項目位置を設定します。 コールバックのdata->xおよび data->yフィールドは, ゴーストの原点を示します。つまり,data->xおよび data->yフィールドは項目自身の位置でなく,ゴーストの位置を示します。
         /*
         **  If not user defined tree, then return
         */
         XtSetArg    (arguments[0], DXmSvnNghostX, &offset_x);
         XtSetArg    (arguments[1], DXmSvnNghostY, &offset_y);
         XtSetArg    (arguments[2], DXmSvnNtreeStyle, &tree_style);
         XtGetValues (Svn, arguments, 3);
         if (tree_style == DXmSvnKuserDefinedTree)
             {
             /*
             **  Move the Entry to the new position
             */
             DXmSvnGetSelections (Svn, selection, NULL, entry_tags, num_selections);
             DXmSvnSetEntryPosition (Svn, selection[0], TRUE,
                data->x-offset_x, data->y-offset_y);
             return;
             }
SVNウィジェットでは,アプリケーションは各項目レベルについて省略時のフォント・ リストを設定したり,すべての項目レベルの省略時の設定として,1 つのフォント・リストを使用することができます。フォント・リストのリソースには, 次のものがあります。
SVNデモ用アプリケーションは次のように,階層内の各項目に子のレベル番号( データ構造体における最初のフィールド)を割り当てます。
         static _Node B  = { 1, 7};
         static _Node P1 = { 2, 7};
         static _Node P2 = { 2, 3};
         static _Node P3 = { 2, 3};
         static _Node P4 = { 2, 4};
        .
        .
        .
したがって,DXmSvnNfontListLevel2リソースを設定すると,レベル2 の項目(P1,P2,P3,P4の子)はすべて,指定されたフォント・リストを使用します。
次の例はDXmSvnNfontListLevel2および DXmSvnNfontListLevel3の各リソースを設定します。
         XmFontList fontlist;
         Arg        arglist[10];
         int        ac;
        .
        .
        .
         fontlist = XmFontListCreate (XLoadQueryFont (XtDisplay(toplevel),
                    "-ADOBE-ITC Avant Garde Gothic-Book-R-Normal--14-100-*-*-P-80-*"),
                     XmSTRING_DEFAULT_CHARSET);
         ac = 0;
         XtSetArg    (arglist[ac], DXmSvnNfontListLevel2, fontlist);ac++;
         XtSetArg    (arglist[ac], DXmSvnNfontListLevel3, fontlist);ac++;
         XtSetValues (svn_widget, arglist, ac);
項目全体のフォント・リストとは独立して,構成要素のフォント・ リストを設定できることに注意してください。たとえば, DXmSvnSetComponentTextルーチンを使用してコンパウンド・ストリングを指定する場合,fontlist 引数を使用して構成要素のフォント・リストを指定できます。
この節では,ツリー・モード固有のリソースについて説明します。
SVNウィジェットには,ディスプレイ・モードがDXmSvnDisplayTreeのとき, アプリケーションがツリーの位置を取得して復元することができるルーチンがあります。 これらのルーチンは,SVNウィジェットが内部的に認識しているx およびy座標に基づいてディスプレイの正確な位置を判断し, その位置をあとで使用できるように格納する方法を提供します。アプリケーションが保存されている位置を復元する場合,SVN ウィジェットはその位置が保存されたときと同じ状態( 同じサイズおよび項目数)でなければなりません。
ツリー・ディスプレイ・モードの項目は,項目間の境界をはっきりさせる輪郭で囲まれています。 DXmSvnNtreeArcWidthリソースを使用すると, この輪郭の円弧幅を指定できます。
たとえば,SVNデモ用アプリケーションはDXmSvnNtreeArcWidthリソースを設定して, ユーザが楕円形(arc_width = 15)と長方形( arc_width = 0)の項目を切り換えることができるようにします。
  【1】if (arc_width == 0)
            {
               arc_width = 15;
               XtSetArg    (arguments[0], DXmSvnNtreeArcWidth, arc_width);
               XtSetValues (Svn, arguments, 1);
               cs = XmStringCreate("Rectangular Entries", XmSTRING_DEFAULT_CHARSET);
            }
  【2】else {
               arc_width = 0;
               XtSetArg    (arguments[0], DXmSvnNtreeArcWidth, arc_width);
               XtSetValues (Svn, arguments, 1);
               cs = XmStringCreate("Oval Entries", XmSTRING_DEFAULT_CHARSET);
            };
DXmSvnNtreeCenteredComponentsリソースを使用すると,項目内のすべての構成要素を垂直方向にセンタリングすることができます。SVN ウィジェットは, センタリングされた構成要素を収容できるように,項目のサイズを自動的に変更します。
たとえば,SVNデモ用アプリケーションは DXmSvnNtreeCenteredComponentsリソースを設定して,ユーザがセンタリングされた構成要素とノーマルの構成要素を切り換えることができるようにします。
  【1】if (centered_components)
        {
          centered_components = FALSE;
          XtSetArg    (arguments[0], DXmSvnNtreeCenteredComponents, centered_components);
          XtSetValues (Svn, arguments, 1);
          cs = XmStringCreate("Components Centered", XmSTRING_DEFAULT_CHARSET);
        }
  【2】else {
          centered_components = TRUE;
          XtSetArg    (arguments[0], DXmSvnNtreeCenteredComponents, centered_components);
          XtSetValues (Svn, arguments, 1);
          cs = XmStringCreate("Normal Components", XmSTRING_DEFAULT_CHARSET);
        };
DXmSvnNtreeEntryOutlinesリソースを使用すると,ツリー・モードの項目を囲んでいる輪郭の有効および無効を切り換えることができます。
たとえば, SVNデモ用アプリケーションはDXmSvnNtreeEntryOutlinesリソースを設定して, ユーザが輪郭を有効にしたり無効にしたりできるようにします。
      【1】if (outlines)
                {
                   outlines = FALSE;
                   XtSetArg    (arguments[0], DXmSvnNtreeEntryOutlines, outlines);
                   XtSetValues (Svn, arguments, 1);
                   cs = XmStringCreate("Add Outlines", XmSTRING_DEFAULT_CHARSET);
                }
      【2】else {
                   outlines = TRUE;
                   XtSetArg    (arguments[0], DXmSvnNtreeEntryOutlines, outlines);
                   XtSetValues (Svn, arguments, 1);
                   cs = XmStringCreate("Remove Outlines", XmSTRING_DEFAULT_CHARSET);
                };
DXmSvnNtreeEntryShadowsリソースを使用すると,ツリー・モードの項目を囲んでいる輪郭にシャドウを追加することができます。
たとえば,SVNデモ用アプリケーションは DXmSvnNtreeEntryShadowsリソースを設定して,ユーザがシャドウを有効にしたり無効にしたりできるようにします。
  【1】if (shadows)
           {
               shadows = FALSE;
               XtSetArg    (arguments[0], DXmSvnNtreeEntryShadows, shadows);
               XtSetValues (Svn, arguments, 1);
               cs = XmStringCreate("Add Shadows", XmSTRING_DEFAULT_CHARSET);
            }
  【2】else {
               shadows = TRUE;
               XtSetArg    (arguments[0], DXmSvnNtreeEntryShadows, shadows);
               XtSetValues (Svn, arguments, 1);
               cs = XmStringCreate("Remove Shadows", XmSTRING_DEFAULT_CHARSET);
            };
DXmSvnNtreePerpendicularLinesリソースを設定すると,ツリー・ モードの項目について,垂直接続線と対角接続線を切り換えることができます。
たとえば,SVNデモ用アプリケーションは DXmSvnNtreePerpendicularLinesを設定して,ユーザが垂直接続線と対角接続線を切り換えることができるようにします。
  【1】if (perpendicular_lines)
        {
          perpendicular_lines = FALSE;
          XtSetArg    (arguments[0], DXmSvnNtreePerpendicularLines, perpendicular_lines);
          XtSetValues (Svn, arguments, 1);
          cs = XmStringCreate("Perpendicular Lines", XmSTRING_DEFAULT_CHARSET);
        }
  【2】else {
          perpendicular_lines = TRUE;
          XtSetArg    (arguments[0], DXmSvnNtreePerpendicularLines, perpendicular_lines);
          XtSetValues (Svn, arguments, 1);
          cs = XmStringCreate("Diagonal Lines", XmSTRING_DEFAULT_CHARSET);
        };
SVNウィジェットは,アプリケーションがそのウィジェットの作成中に設定したコールバック・ ルーチンを通して,アプリケーションと通信します。SVN ウィジェットがこれらのコールバック・ルーチンを使用するのは, ユーザによるアクションの結果として,階層データへの接続または階層データからの切離しを行っているときや, そのウィジェットがある項目に関連するディスプレイ情報を必要とするときなどです。
DXmSvnCallbackStructデータ構造体のフォーマットを,例 9-2 に示します。
typedef struct
{
    int           reason;
    int           entry_number;
    int           component_number;
    int           first_selection;
    int           x;
    int           y;
    unsigned int  entry_tag;
    Time          time;
    int           entry_level;
    int           loc_cursor_entry_number;
    int           transfer_mode;
    int           dragged_entry_number;
    XEvent        *event;
} DXmSvnCallbackStruct;
コールバック・ルーチンをSVNウィジェットのコールバックと関連付けるには, コールバック・ルーチン・リストをSVNウィジェットのコールバック・ リソースの1つに渡します。コールバックのリストと,それらを引き起こす条件については, 『日本語DECwindows Motif for OpenVMS 拡張機能説明書』(日本語),『DECwindows Extensions to Motif』(英語)を参照してください。
DXmSvnNhelpRequestedCallbackコールバックを使用すると,ユーザがヘルプを要求するときに呼び出すルーチンを指定できます。
SVNウィジェットはヘルプを生成するために2つのメカニズムをサポートしています。1 つはヘルプ・キーを押す方法であり,もう1つはスクロール・ バー,「ナビゲーション」プッシュ・ボタン,ナビゲーション・ウィンドウのいずれかの上でコンテキスト依存ヘルプを要求する方法です。SVN ウィジェットはヘルプが要求された方法に応じて,DXmSvnCallbackStruct データ構造体の2 つのフィールドのいずれか1つを設定します。
DXmSvnCallbackStructデータ構造体のloc_cursor_entry_ numberフィールドには,現在選択されている項目の項目番号も返されます。
アプリケーションのヘルプ・コールバック・ルーチンはこれら2つのフィールドをチェックして, ユーザが要求したヘルプのタイプを判断しなければなりません。
例 9-3はまず,entry_numberフィールドを調べて, コンテキスト依存ヘルプが要求されたかどうかを確認します。 entry_numberに負の数が入っていない場合は,loc_ cursor_entry_numberフィールドを調べて,それがNULLでないことを確認したのち,SVN の項目に関する概要のヘルプを提供します。
DECwindowsヘルプ・システムの各種ルーチンの使用方法については,第5章を参照してください。
static void svn_help_proc (svnw, unused_tag, data)
      Widget               svnw;
      int                  unused_tag;
      DXmSvnCallbackStruct *data;
{
      int                  help_num = NULL;
      int                  sens_num = NULL;
      help_num = data->loc_cursor_entry_number;
      sens_num = data->entry_number;
       if (sens_num < 0) {
            if (sens_num == DXmSvnKhelpScroll)
                 DXmHelpSystemDisplay(help_context, svn_help,
                        "topic", "scroll", help_error, "Help System Error");
              else if (sens_num == DXmSvnKhelpNavButton )
                   DXmHelpSystemDisplay(help_context, svn_help, "topic",
                           "navigate", help_error, "Help System Error");
                       else
                           DXmHelpSystemDisplay(help_context, svn_help,
                                                "topic", "overview",
                                                help_error,
                                                "Help System Error");
            return;
       };
         if (help_num != NULL) {
                    DXmHelpSystemDisplay(help_context, svn_help, "topic",
                            "overview",  help_error, "Help System Error");
        };
}
ユーザがSVNウィジェットの存在期間中に実行できるアクションは限られています。 ユーザによるアクションの結果として生成されるコールバックについて, 表 9-2に説明します。
| アクション | コールバック | 説明 | 
|---|---|---|
| MB1クリック | DXmSvnNentrySelectedCallback DXmSvnNentryUnselectedCallback DXmSvnNtransitionsDoneCallback | 1つの項目を選択する。SVN ウィジェットは以前に選択されたすべての項目を, 選択されていないものとして設定した後,この項目を選択されたものとして設定する。 選択された項目は反転表示される。 | 
| MB1ダブル・クリック | DXmSvnNselectAndConfirmCallback | ユーザが1つの項目をダブル・ クリックした。このコールバックはユーザがその項目を展開( または収縮)したいことを示す。DXmSvnNselectAndConfirmコールバック・ ルーチンは,その項目がまだオープンされてない場合それをオープンし,DXmSvnAddEntry ルーチンを呼び出して,その要素がもっている子を追加する。 | 
| MB1/ドラッグ/クリック | DXmSvnNentrySelectedCallback DXmSvnNtransitionsDoneCallback | 項目上を通過するとその項目が選択されて, 押したポイントから現在のポイントまでのすべての項目が各ポイントで選択される。 選択された項目は,MB1を押すと選択が解除される。 | 
| シフト/MB1/項目のクリック | DXmSvnNentrySelectedCallback DXmSvnNtransitionsDoneCallback | 前回選択された項目(MB1 クリックによる)からMB1シフト・クリックが実行される現在の項目までのすべての項目が, 選択された項目となる。 | 
| MB1/Ctrl/クリック | DXmSvnNentrySelectedCallback DXmSvnNentryUnselectedCallback DXmSvnNtransitionsDoneCallback | 現在の項目の選択状態が切り換えられる。 位置カーソルはその項目へ移動する。 | 
| MB1/Ctrl/ドラッグ | DXmSvnNentrySelectedCallback DXmSvnNentryUnselectedCallback DXmSvnNtransitionsDoneCallback | 項目上を通過するとき項目選択状態が切り換えられて, 押したポイントから現在のポイントまでのすべての項目が切り換えられる。 | 
| MB2/クリック | DXmSvnNentryTransfer | DXmSvnNentryTransferコールバックが,転送モード"Unknown"を指定して生成される。 | 
| MB2/Ctrl/クリック | DXmSvnNentryTransfer | MB2 クリックと同様であるが,項目の転送はアプリケーションが実現する複写処理でなければならない。 コールバック・データ構造体の transfer_modeフィールドに,DXmSvnKtransferCopyの値が返される。 | 
| MB2/Alt/クリック | DXmSvnNentryTransfer | MB2クリックと同様であるが, 項目の転送はアプリケーションが実現する移動処理でなければならない。 コールバック・データ構造体のtransfer_modeフィールドに, DXmSvnKtransferMoveの値が返される。 | 
| MB2 /ドラッグ | DXmSvnNselectionsDragged | 選択された項目で押すと,選択された項目がすべてドラッグされる。 未選択の項目で押すと,その項目だけがドラッグされる。項目のゴーストが作成され, 解放ポイントまでマウスでドラッグされる。DXmSvnNselectionsDragged コールバックがアプリケーションへ返される。 コールバック構造体で"Unknown"の転送モードが指定される。 | 
| MB2/Ctrl/ドラッグ | DXmSvnNselectionsDragged | MB2ドラッグと同様であるが,1 つまたは複数の項目の転送は,アプリケーションが実現する複写処理でなければならない。 コールバック・データ構造体の transfer_modeフィールドに,DXmSvnKtransferCopy の値が返される。 | 
| MB2/Alt/ドラッグ | DXmSvnNselectionsDragged | MB2 クリックと同様であるが,項目の転送はアプリケーションが実現する移動処理でなければならない。 コールバック・データ構造体の transfer_modeフィールドに,DXmSvnKtransferMoveの値が返される。 | 
| MB3/クリック | DXmSvnNpopupMenuCallback | アプリケーションへのポップアップ・ メニューのコールバック。アプリケーションはポップアップ・ メニューの実現のためだけにこのボタンを使用する。 | 
表 9-3で説明するいずれの方法を使用しても,SVN ウィジェットのインスタンスを作成できます。
| UILオブジェクト・タイプ | DXmSvnオブジェクト・ タイプ識別子を使用して,UILモジュールでSVNウィジェットを作成する。 | 
| ツールキット・ルーチン | DXmCreateSvnルーチンを使用して,SVNウィジェットを作成する。 | 
SVNウィジェットが作成されると,アプリケーションはツールキットのルーチン呼び出しを通してウィジェットと通信します。 これらのルーチンは表示されている構造の有効範囲を変更したり, 選択について問い合わせたり, それらの選択を操作することができます。選択を操作するルーチンとしては, 選択の消去,全項目の選択,選択した項目のリストの取得などがあります。
アプリケーションは少なくとも次のSVNコールバックを実現しなければなりません 。
この節では,DECW$EXAMPLESディレクトリ内にあるSVNデモ用アプリケーションが最低限実現していることについて説明します。 この例は,DXmSvnオブジェクト・ タイプ識別子を使用することにより,UILモジュールでSVNウィジェットを作成します(SVN デモ・アプリケーションは,Windows NT用のeXcursion では提供されません)。
アプリケーションにSVNウィジェットを追加するとき,出発点としてこの例を使用することができます。 他のSVNの機能については,SVNデモ用アプリケーションを参照してください。
例の構成は次のようになっています。
   .
   .
   .
module form
    version = 'v1.0'
    names = case_sensitive
procedure
        svn_attach_proc    ();
        svn_confirm_proc   ();
        svn_get_entry_proc ();
        exit_proc         (string);
value
        k_exit_accelerator              : "Ctrl<>z:";
        k_exit_accelerator_text         : "Ctrl/Z";
!Build menu for exit button
object
    S_MAIN_WINDOW : XmMainWindow {
        arguments {
            XmNx = 0;
            XmNy = 0;
            XmNwidth = 800;
            XmNheight = 800;
         };
        controls {                      ! S_MAIN_WINDOW has two children.
            XmMenuBar       s_menu_bar;
            DXmSvn          main_svn;
            };
        };
object
    s_menu_bar : XmMenuBar {
        arguments {
            XmNorientation      = XmHORIZONTAL;
            };
        controls {
            XmCascadeButton     file_menu_entry;
            };
        };
object
    file_menu_entry : XmCascadeButton {
        arguments {
            XmNlabelString      = "File";
            XmNmnemonic         = keysym("F");
            };
        controls {
            XmPulldownMenu      file_menu;
            };
        };
! The file pulldown menu with the push buttons it controls.
object
    file_menu : XmPulldownMenu {
        controls {
            XmPushButton        exit_button;
            };
        };
object
    exit_button : XmPushButton {
        arguments {
            XmNlabelString      = "Exit" ;
            XmNaccelerator      = k_exit_accelerator;
            XmNacceleratorText  = k_exit_accelerator_text;
            XmNmnemonic         = keysym("E");
            };
        callbacks {
            XmNactivateCallback = procedure exit_proc('normal demo exit');
            };
        };
!The SVN widget object
【1】
object main_svn : DXmSvn
            {
            arguments
                {
                XmNwidth = 826;
                XmNheight = 237;
                };
            callbacks
                {
                 DXmSvnNattachToSourceCallback = procedure svn_attach_proc();
                 DXmSvnNselectAndConfirmCallback =  procedure svn_confirm_proc();
                 DXmSvnNgetEntryCallback = procedure svn_get_entry_proc();
                };
           };
end module;
   .
   .
   .
   .
   .
   .
#include <stdio>
#include <Mrm/MrmAppl.h>
【1】
#include <DXm/dxmsvn.h>
Widget toplevel, main_widget, svn_widget;
/******************************************************/
/*  Local declarations needed for SVN definitions  */
/******************************************************/
/*
**  My local hierarchy storage structure
*/
    typedef struct node
        {
          int             level;      /* level number of children    */
          int             number;     /* number of children          */
          XmString        text;       /* entry text                  */
          struct node    *sibling;    /* pointer to sibling or NULL  */
          struct node    *children;   /* pointer to children or NULL */
          Widget          stext;      /* stext widget for this entry */
          Boolean         opened;     /* children are showing        */
        }_Node, *NodePtr;
/*
**  Declarations used in building the pixmap
*/
#define pixmap_width 13
#define pixmap_height 13
【2】
static char parent_pixmap_bits[] = {
   0x40, 0x00, 0xe0, 0x00, 0xf0, 0x01, 0x08, 0x02, 0xf4, 0x05, 0x16, 0x0d,
   0x57, 0x1d, 0x16, 0x0d, 0xf4, 0x05, 0x08, 0x02, 0xf0, 0x01, 0xe0, 0x00,
   0x40, 0x00};
static char child_pixmap_bits[] = {
   0x40, 0x00, 0xa0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x04, 0x04, 0x02, 0x08,
   0x41, 0x10, 0x02, 0x08, 0x04, 0x04, 0x08, 0x02, 0x10, 0x01, 0xa0, 0x00,
   0x40, 0x00};
/*
**  Pixmap structures
*/
    static Pixmap parent_pixmap = NULL;
    static Pixmap child_pixmap = NULL;
/*
**  Local data defining all of the nodes of the book.  We will initialize
**  the first three fields of the structures, namely level, number, and
**  text.  All of the remaining fields will be initialized in the local
**  initialization routines.
*/
【3】static _Node B  = { 1, 7};
    static _Node P1 = { 2, 7};
    static _Node P2 = { 2, 3};
    static _Node P3 = { 2, 3};
    static _Node P4 = { 2, 4};
    static _Node P5 = { 2, 5};
    static _Node P6 = { 2, 6};
    static _Node P7 = { 2, 0};
    static _Node C11  = { 3, 0};
    static _Node C12  = { 3, 2};
    static _Node C13  = { 3, 3};
    static _Node C14  = { 3, 2};
    static _Node C15  = { 3, 0};
    static _Node C16  = { 3, 3};
    static _Node C17  = { 3, 0};
    static _Node C21  = { 3, 2};
    static _Node C22  = { 3, 3};
    static _Node C23 = { 3, 4};
    static _Node C31 = { 3, 9};
    static _Node C32  = { 3, 4};
    static _Node C33 = { 3, 7};
    static _Node C41 = { 3, 2};
    static _Node C42 = { 3, 4};
    static _Node C43 = { 3, 3};
    static _Node C44 = { 3, 0};
    static _Node C51 = { 3, 0};
    static _Node C52 = { 3, 3};
    static _Node C53 = { 3, 7};
    static _Node C54 = { 3, 0};
    static _Node C55 = { 3, 3};
    static _Node C61 = { 3, 0};
    static _Node C62 = { 3, 9};
    static _Node C63 = { 3, 0};
    static _Node C64 = { 3, 0};
    static _Node C65 = { 3, 0};
    static _Node C66 = { 3, 0};
    static _Node C70 = { 3, 0};
    static _Node C121 = { 4, 0};
    static _Node C122 = { 4, 0};
    static _Node C131 = { 4, 0};
    static _Node C132 = { 4, 0};
    static _Node C133 = { 4, 0};
    static _Node C141 = { 4, 0};
    static _Node C142 = { 4, 0};
    static _Node C161 = { 4, 0};
    static _Node C162 = { 4, 0};
    static _Node C163 = { 4, 0};
    static _Node C211 = { 4, 0};
    static _Node C212 = { 4, 0};
    static _Node C221 = { 4, 0};
    static _Node C222 = { 4, 0};
    static _Node C223 = { 4, 0};
    static _Node C231 = { 4, 0};
    static _Node C232 = { 4, 0};
    static _Node C233 = { 4, 0};
    static _Node C234 = { 4, 0};
    static _Node C311 = { 4, 0};
    static _Node C312 = { 4, 0};
    static _Node C313 = { 4, 0};
    static _Node C314 = { 4, 0};
    static _Node C315 = { 4, 0};
    static _Node C316 = { 4, 0};
    static _Node C317 = { 4, 0};
    static _Node C318 = { 4, 0};
    static _Node C319 = { 4, 0};
    static _Node C321 = { 4, 0};
    static _Node C322 = { 4, 0};
    static _Node C323 = { 4, 0};
    static _Node C324 = { 4, 0};
    static _Node C331 = { 4, 0};
    static _Node C332 = { 4, 0};
    static _Node C333 = { 4, 0};
    static _Node C334 = { 4, 0};
    static _Node C335 = { 4, 0,};
    static _Node C336 = { 4, 0};
    static _Node C337 = { 4, 0};
    static _Node C411 = { 4, 0};
    static _Node C412 = { 4, 0};
    static _Node C421 = { 4, 0};
    static _Node C422 = { 4, 0};
    static _Node C423 = { 4, 0};
    static _Node C424 = { 4, 0};
    static _Node C431 = { 4, 0};
    static _Node C432 = { 4, 0};
    static _Node C433 = { 4, 0};
    static _Node C521 = { 4, 0};
    static _Node C522 = { 4, 0};
    static _Node C523 = { 4, 0};
    static _Node C531 = { 4, 0};
    static _Node C532 = { 4, 0};
    static _Node C533 = { 4, 0};
    static _Node C534 = { 4, 0};
    static _Node C535 = { 4, 0};
    static _Node C536 = { 4, 0};
    static _Node C537 = { 4, 0};
    static _Node C551 = { 4, 0};
    static _Node C552 = { 4, 0};
    static _Node C553 = { 4, 0};
    static _Node C621 = { 4, 0};
    static _Node C622 = { 4, 0};
    static _Node C623 = { 4, 0};
    static _Node C624 = { 4, 0};
    static _Node C625 = { 4, 0};
    static _Node C626 = { 4, 0};
    static _Node C627 = { 4, 0};
    static _Node C628 = { 4, 0};
    static _Node C629 = { 4, 0};
/*
 * Forward declarations
 */
static void create_svn();
static void svn_attach_proc();
static void svn_confirm_proc();
static void svn_get_entry_proc();
static void exit_proc();
static void LclInitializeList();
Boolean SourceIsNodeParent();
static void SourceToggleNode();
static void SourceOpenNode();
static void SourceCloseNode();
NodePtr LclGetNodePtr();
static void LclCloseNode();
static void LclSetUpPixmap();
【4】
int SourceNumComps = 2;
int SourceNumEntries;
static MrmHierarchy s_MrmHierarchy;
static MrmType *dummy_class;
【5】
static char *db_filename_vec[] =
  {"create_svn.uid"
  };
/* The names and addresses of things that Mrm.has to bind.  The names do
 * not have to be in alphabetical order.  */
static MrmRegisterArg reglist[] = {
    {"svn_attach_proc", (caddr_t) svn_attach_proc},
    {"svn_confirm_proc", (caddr_t) svn_confirm_proc},
    {"exit_proc", (caddr_t) exit_proc},
    {"svn_get_entry_proc", (caddr_t) svn_get_entry_proc}
};
static int reglist_num = (sizeof reglist / sizeof reglist [0]);
int main(argc, argv)
    unsigned int argc;
    char **argv;
{
    XtAppContext app_context;
    MrmInitialize();
    DXmInitialize();
    toplevel = XtAppInitialize(&app_context, "svn example", NULL, 0, &argc,
                             argv, NULL, NULL, 0);
   /* Open the UID files (the output of the UIL compiler) in the hierarchy*/
    if (MrmOpenHierarchy(1,
      db_filename_vec,
      NULL,
      &s_MrmHierarchy)
      !=MrmSUCCESS)
          printf("can't open hierarchy");
    MrmRegisterNames(reglist, reglist_num);
【6】if (MrmFetchWidget(s_MrmHierarchy, "main_svn", toplevel,
      &svn_widget, &dummy_class) != MrmSUCCESS)
        printf("can't fetch Svn widget");
     XtManageChild(svn_widget);
     XtRealizeWidget(toplevel);
     XtAppMainLoop(app_context);
}
   .
   .
   .
/*
 * The user pushed the exit button, so the application exits.
 */
static void exit_proc(w, tag, reason)
    Widget  w;
    char  *tag;
    XmAnyCallbackStruct *reason;
{
    if (tag != NULL)
        printf("Exit - %s\n", tag);
    exit(1);
}
   .
   .
   .
/* Svn Attach Callback */
【1】
static void svn_attach_proc(svnw)
Widget svnw;
{
/*
**  Local data declarations
*/
    unsigned int entry_tags [1];
/*
**  Announce the routine on the debugging terminal
*/
    printf ("AttachToSource handler\n");
/*
**  Initialize the book data structure
*/
    LclInitializeList ();
/*
**  Make room for the books entries.  I will pass the tag array here since I
**  know that I have exactly one entry and its easy to figure out the tag.
*/
    entry_tags[0] = (unsigned int) &B;
    DXmSvnAddEntries (svnw, 0, 1, 0, entry_tags, TRUE);
/*
**  Reflect this addition in the global count.
*/
    SourceNumEntries = 1;
}
/*
**  SelectAndConfirm callback routine.  This routine is called when one and
**  only one Entry is selected.  The Entry number selected is provided in the
**  callback structure.
*/
【2】
static void svn_confirm_proc(w, unused_tag, data)
  Widget w;
  int unused_tag;
  DXmSvnCallbackStruct *data;
{
/*
**  Announce the routine on the debugging terminal
*/
    printf ("SelectAndConfirm handler\n");
/*
**  Determine if the Entry can be expanded.  If so, then tell the source module
**  to deal with it.
*/
    if (SourceIsNodeParent (data->entry_number, data->entry_tag) == TRUE)
       {
         SourceToggleNode (data->entry_number, data->entry_tag);
         DXmSvnClearSelection (w, data->entry_number);
       };
}
/*
**  This routine is called when the widget wants the Source module to set
**  the information associated with a particular entry.
*/
【3】
static void svn_get_entry_proc(svnw, unused_tag, data)
  Widget svnw;
  int unused_tag;
  DXmSvnCallbackStruct *data;
{
/*
**  Local data declarations
*/
    int     i;
    NodePtr node;
    Arg     args[10];
    XmFontList fontlist;
    fontlist = XmFontListCreate (XLoadQueryFont (XtDisplay(toplevel),
                      "*helvetica-medium-r-*-14-*"), XmSTRING_DEFAULT_CHARSET);
/*
**  Announce the routine on the debugging terminal
*/
     printf ("GetEntry handler - entry_number = %d, entry_tag = %d\n",
             data->entry_number, data->entry_tag);
/*
**  Get at the node (if needed)
*/
    if (data->entry_tag == 0)
         node = LclGetNodePtr (data->entry_number);
    else node = (NodePtr) data->entry_tag;
/*
**  Set up the pixmaps
*/
    LclSetUpPixmap (svnw);
/*
**  Set the entry information that both children and parent nodes
**  have in common.
*/
    DXmSvnSetEntryNumComponents (svnw, data->entry_number, SourceNumComps);
    DXmSvnSetEntryTag (svnw, data->entry_number, node);
/*
 *  The first component is different in parent/child nodes and always present.
 *  If there are no children, use the child pixmap.  Otherwise use the parent
 *   pixmap.
 */
    if (node->number == 0)
       DXmSvnSetComponentPixmap (svnw, data->entry_number, 1, 0, 0,
                                 child_pixmap,  pixmap_width, pixmap_height);
    else DXmSvnSetComponentPixmap (svnw, data->entry_number, 1, 0, 0,
                                   parent_pixmap, pixmap_width, pixmap_height);
 【4】DXmSvnSetComponentText (svnw, data->entry_number, 2, pixmap_width+4,
                            0, node->text, fontlist);
}
/*
**  Global routine that opens a closed node or closes an open node.
*/
void SourceToggleNode (node_number, entry_tag)
  int node_number;
  unsigned int entry_tag;
{
/*
**  Local data declarations
*/
    NodePtr node;
/*
**  Get at the node (if needed)
*/
    if (entry_tag == 0)
         node = LclGetNodePtr (node_number);
    else node = (NodePtr) entry_tag;
/*
**  If it is opened, then close it.  Otherwise open it.
*/
    if (node->opened == TRUE)
         SourceCloseNode (node_number, entry_tag);
    else SourceOpenNode  (node_number, entry_tag);
}
/*
**  Global routine that tells the caller if the given node has child nodes.
*/
Boolean SourceIsNodeParent (node_number, entry_tag)
  int node_number;
  unsigned int entry_tag;
{
/*
**  Local data declarations
*/
    NodePtr node;
/*
**  Get at the node (if needed)
*/
    if (entry_tag == 0)
         node = LclGetNodePtr (node_number);
    else node = (NodePtr) entry_tag;
/*
**  Return TRUE or FALSE
*/
    if (node->children == 0)
         return FALSE;
    else return TRUE;
}
/*
**  Global routine that opens a node, given the node number
*/
static void SourceOpenNode(node_number, entry_tag)
  int node_number;
  unsigned int entry_tag;
{
/*
**  Local data declarations
*/
    NodePtr node;
    NodePtr child_node;
    int i, x, y;
/*
**  Get at the node (if needed)
*/
    if (entry_tag == 0)
         node = LclGetNodePtr (node_number);
    else node = (NodePtr) entry_tag;
/*
**  If it is already opened, then return.
*/
    if (node->opened == TRUE)
       return;
/*
**  If it has no children, then return.
*/
    if (node->number == 0)
       return;
/*
**  Mark the node as being opened
*/
    node->opened = TRUE;
/*
 *  Add the entries.  This code does not yet use the entry_tags array.
 */
    DXmSvnAddEntries (svn_widget, node_number, node->number,
                        node->level, NULL, FALSE);
/*
 *  Get to the first child of this node
 */
    child_node = node->children;
/*
 *  For each child, call SetEntry if the child has children.  Also set their
 *  positions in case we are in we have a UserDefined Tree Style.
 */
    DXmSvnGetEntryPosition(svn_widget, node_number, FALSE, &x, &y);
    for (i = 1;  i <= node->number;  i++)
        {
          if (child_node->children != 0)
             DXmSvnSetEntry (svn_widget, node_number+i, 0, 0, 2, 1, 0, FALSE);
          child_node = child_node->sibling;
          x += 30;
          y += 30;
          DXmSvnSetEntryPosition(svn_widget, node_number+i, FALSE, x, y);
        };
/*
**  Reflect this addition in the global count.
*/
    SourceNumEntries = SourceNumEntries + node->number;
}
/*
**  Global routine that closes a node, given the node number
*/
void SourceCloseNode (node_number, entry_tag)
  int node_number;
  unsigned int entry_tag;
{
/*
**  Local data declarations
*/
    NodePtr node;
/*
**  Get at the node (if needed)
*/
    if (entry_tag == 0)
         node = LclGetNodePtr (node_number);
    else node = (NodePtr) entry_tag;
/*
**  Call the local recursive close routine.
*/
    LclCloseNode(node, node_number);
}
/*
**  Recursively close all nodes given a current node pointer
**  and a current node number.
*/
void LclCloseNode(node, node_number)
  NodePtr node;
  int node_number;
{
/*
**  Local data declarations
*/
    int i;
    NodePtr child_node;
/*
**  If the current node is not opened, then return
*/
    if (node->opened == FALSE)
       return;
    /*
**  Get to the first child of this node
*/
    child_node = node->children;
/*
**  For each child, call CloseNode on each child
*/
    for (i=1;  i<=node->number;  i++)
        {
          LclCloseNode (child_node, node_number);
          child_node = child_node->sibling;
        };
/*
**  Tell SVN to remove its children
*/
    DXmSvnDeleteEntries (svn_widget, node_number, node->number);
/*
**  Mark the node closed
*/
    node->opened = FALSE;
    if (node->stext != NULL) XtUnmanageChild(node->stext);
/*
**  Reflect this removal in the global count.
*/
    SourceNumEntries = SourceNumEntries - node->number;
}
/*
**  Routine that maps a node_number into a node structure pointer.
*/
NodePtr LclGetNodePtr (node_number)
  int node_number;
{
/*
**  Local routine data
*/
    int i;
    NodePtr current_node = &B;
/*
**  Loop through until it's found.  If we hit the end of the list, then
**  we'll return a null pointer.
*/
    if (node_number != 1)
       for (i = 2;  i <= node_number;  i++)
            if (current_node == NULL)
                 break;
            else if (current_node->opened)
                     current_node = current_node->children;
                     else current_node = current_node->sibling;
/*
**  Return the node address
*/
    return current_node;
}
   .
   .
   .
SVNデモ用アプリケーションの場合,DXmSvnNgetEntryCallbackコールバック・ ルーチンは次の機能を実行します。
   .
   .
   .
void LclInitializeList ()
{
      B.text = XmStringCreate("OSF/Motif Style Guide V1.1", XmSTRING_DEFAULT_CHARSET);
      P1.text = XmStringCreate("1. User Interface Design Principles", XmSTRING_DEFAULT_CHARSET);
      P2.text = XmStringCreate("2. Input and Navigation Models", XmSTRING_DEFAULT_CHARSET);
      P3.text = XmStringCreate("3. Selection and Component Activation", XmSTRING_DEFAULT_CHARSET);
      P4.text = XmStringCreate("4. Application Design Principles", XmSTRING_DEFAULT_CHARSET);
      P5.text = XmStringCreate("5. Window Manager Design Principles", XmSTRING_DEFAULT_CHARSET);
      P6.text = XmStringCreate("6. Designing for International Markets", XmSTRING_DEFAULT_CHARSET);
      P7.text = XmStringCreate("7. Controls, Groups, and Models Reference Pages", XmSTRING_DEFAULT_CHARSET);
      C11 .text = XmStringCreate("1.1  Adopt the User's Perspective", XmSTRING_DEFAULT_CHARSET);
      C12 .text = XmStringCreate("1.2  Give the User Control", XmSTRING_DEFAULT_CHARSET);
      C13 .text = XmStringCreate("1.3  User Real-World Metaphors", XmSTRING_DEFAULT_CHARSET);
      C14 .text = XmStringCreate("1.4  Keep Interfaces Natural", XmSTRING_DEFAULT_CHARSET);
      C15 .text = XmStringCreate("1.5. Keep Interfaces Consistent", XmSTRING_DEFAULT_CHARSET);
      C16 .text = XmStringCreate("1.6  Communicate Application Actions to the User", XmSTRING_DEFAULT_CHARSET);
      C17 .text = XmStringCreate("1.7  Avoid Common Design Pitfalls", XmSTRING_DEFAULT_CHARSET);
      C21 .text = XmStringCreate("2.1 The Keyboard Focus Model", XmSTRING_DEFAULT_CHARSET);
      C22 .text = XmStringCreate("2.2 The Input Device Model", XmSTRING_DEFAULT_CHARSET);
      C23.text = XmStringCreate("2.3 The Navigation Model", XmSTRING_DEFAULT_CHARSET);
      C31.text = XmStringCreate("3.1 Selection Models", XmSTRING_DEFAULT_CHARSET);
      C32.text = XmStringCreate("3.2 Selection Actions", XmSTRING_DEFAULT_CHARSET);
      C33.text = XmStringCreate("3.3 Component Activation", XmSTRING_DEFAULT_CHARSET);
      C41.text = XmStringCreate("4.1 Choosing Components", XmSTRING_DEFAULT_CHARSET);
      C42.text = XmStringCreate("4.2 Layout", XmSTRING_DEFAULT_CHARSET);
      C43.text = XmStringCreate("4.3 Interaction", XmSTRING_DEFAULT_CHARSET);
      C44.text = XmStringCreate("4.4 Component Design", XmSTRING_DEFAULT_CHARSET);
      C51.text = XmStringCreate("5.1 Configurability", XmSTRING_DEFAULT_CHARSET);
      C52.text = XmStringCreate("5.2 Window Support", XmSTRING_DEFAULT_CHARSET);
      C53.text = XmStringCreate("5.3 Window Decorations", XmSTRING_DEFAULT_CHARSET);
      C54.text = XmStringCreate("5.4 Window Navigation", XmSTRING_DEFAULT_CHARSET);
      C55.text = XmStringCreate("5.5 Icons", XmSTRING_DEFAULT_CHARSET);
      C61.text = XmStringCreate("6.1 Collating Sequences", XmSTRING_DEFAULT_CHARSET);
   .
   .
   .
/*
**  Fill in the child pointers for the book, parts, and chapters
*/
    B.children   = &P1;
    P1.children  = &C11;
    P2.children  = &C21;
    P3.children  = &C31;
    P4.children  = &C41;
    P5.children  = &C51;
    P6.children  = &C61;
    P7.children  = NULL;
    C11.children  = NULL;
    C12.children  = &C121;
    C13.children  = &C131;
    C14.children  = &C141;
    C15.children  = NULL;
    C16.children  = &C161;
    C17.children  = NULL;
    C21.children  = &C211;
    C22.children  = &C221;
    C23.children  = &C231;
    C31.children  = &C311;
    C32.children  = &C321;
    C33.children  = &C331;
    C41.children  = &C411;
    C42.children  = &C421;
    C43.children  = &C431;
    C44.children  = NULL;
    C51.children  = NULL;
    C52.children  = &C521;
    C53.children  = &C531;
    C54.children  = NULL;
    C55.children  = &C551;
    C61.children  = NULL;
    C62.children  = &C621;
    C63.children  = NULL;
    C64.children  = NULL;
    C65.children  = NULL;
    C66.children  = NULL;
/*
**  Fill in the sibling pointers for the book
*/
    B.sibling     =  NULL;
/*
**  Fill in the sibling pointers for the parts
*/
    P1.sibling    =  &P2;
    P2.sibling    =  &P3;
    P3.sibling    =  &P4;
    P4.sibling    =  &P5;
    P5.sibling    =  &P6;
    P6.sibling    =  &P7;
    P7.sibling    =  NULL;
/*
**  Fill in the sibling pointers for the chapters
*/
    C11.sibling  = &C12;
    C12.sibling  = &C13;
    C13.sibling  = &C14;
    C14.sibling  = &C15;
    C15.sibling  = &C16;
    C16.sibling  = &C17;
    C17.sibling  = &P2;
    C21.sibling  = &C22;
    C22.sibling  = &C23;
    C23.sibling  = &P3;
    C31.sibling  = &C32;
    C32.sibling  = &C33;
    C33.sibling  = &P4;
    C41.sibling  = &C42;
    C42.sibling  = &C43;
    C43.sibling  = &C44;
    C44.sibling  = &P5;
    C51.sibling  = &C52;
    C52.sibling  = &C53;
    C53.sibling  = &C54;
    C54.sibling  = &C55;
    C55.sibling  = &P6;
    C61.sibling  = &C62;
    C62.sibling  = &C63;
    C63.sibling  = &C64;
    C64.sibling  = &C65;
    C65.sibling  = &C66;
    C66.sibling  = &P7;
/*
**  Fill in the sibling pointers for the sections of chapter 1
*/
    C121.sibling  =  &C122;
    C122.sibling  =  &C13;
    C131.sibling  =  &C132;
    C132.sibling  =  &C133;
    C133.sibling  =  &C14;
    C141.sibling  =  &C142;
    C142.sibling  =  &C15;
    C161.sibling  =  &C162;
    C162.sibling  =  &C163;
    C163.sibling  =  &C17;
/*
**  Fill in the sibling pointers for the sections of chapter 2
*/
    C211.sibling  =  &C212;
    C212.sibling  =  &C22;
    C221.sibling  =  &C222;
    C222.sibling  =  &C223;
    C223.sibling  =  &C23;
    C231.sibling  =  &C232;
    C232.sibling  =  &C233;
    C233.sibling  =  &C234;
    C234.sibling  =  &P3;
   .
   .
   .
}
   .
   .
   .
void LclSetUpPixmap (svnw)
  Widget svnw;
{
/*
**  Local data declarations
*/
    Screen  *screen  = XtScreen(toplevel);
    Display *display = DisplayOfScreen (screen);
    Pixel background_pixel;
    Pixel foreground_pixel;
    Arg args [2];
/*
**  If we've already done this, then return.
*/
    if (parent_pixmap != NULL) return;
/*
**  Get the foreground/background colors of Svn
*/
    XtSetArg    (args[0], XmNforeground, &foreground_pixel);
    XtSetArg    (args[1], XmNbackground, &background_pixel);
    XtGetValues (svnw, args, 2);
/*
**  Create the pixmap.
*/
    parent_pixmap = XCreatePixmapFromBitmapData (
         display,                               /* (IN) display */
         XDefaultRootWindow(display),           /* (IN) drawable */
         parent_pixmap_bits,                    /* (IN) bitmap data */
         pixmap_width,                          /* (IN) width */
         pixmap_height,                         /* (IN) height */
         foreground_pixel,                      /* (IN) foreground pixel */
         background_pixel,                      /* (IN) background pixel */
         DefaultDepthOfScreen(screen));         /* (IN) pixmap depth */
    child_pixmap = XCreatePixmapFromBitmapData (
         display,                              /* (IN) display */
         XDefaultRootWindow(display),          /* (IN) drawable */
         child_pixmap_bits,                    /* (IN) bitmap data */
         pixmap_width,                         /* (IN) width */
         pixmap_height,                        /* (IN) height */
         foreground_pixel,                     /* (IN) foreground pixel */
         background_pixel,                     /* (IN) background pixel */
         DefaultDepthOfScreen(screen));        /* (IN) pixmap depth */
}
   .
   .
   .