メニュー機能の実装

 

Step-1

さ〜て何から始めましょうかね。そうだ、メニューボタンをぺこぺこさせよう(笑。メニューボタンを押したときに、メニューが開くのと同時にぺこっと窪んだ状態になるアレです。とりあえずやってみよう。まずは、ボタンをへこませる関数と元に戻す関数の実装から。背景の初期化関数に似たような部分があるので、とくに難しいところはない。ちなみに、rapuOSではロゴを表示しているが、これを右下に1ドットずらすとちょっとリアルになるので、これもやっておこう。戻す場合は逆のことを行う。関数ができたので、今度は呼び出し部分を実装しよう。マウス/キーボードのタスクでは、マウスがクリックされると、マウスが指しているウィンドウを探し出す。これが見つかった場合にフラグを立てることで、みつからなかった場合、つまり背景を指している場合を判別する。あとはメニューボタンの範囲にマウスがあるかを判定するだけで良いので簡単だ。メニューボタンを戻す(メニューを閉じる)場合備えて、ぺこらせたこと(メニューが開いた状態)を示すフラグも立ててこう。キーが押下されたり、マウスをクリックした場合に、メニューボタンを戻す関数を呼び出す。ささ、実験です。ぺこり〜♪・・・あ、へこんだ(笑。

 

Step-1

ぺこっとな。はい、これ以上何も出ません(笑。

 


Step-2

メニューボタンのぺこぺこができたところで、メニュー表示もつけてしまおう。メニューの表示にはシート機能を使うのだが、他のウィンドウと区別する必要がある。ウィンドウの移動や×ボタン(表示はされていないけど)クリック時の処理を実行しないように制御するためである。いつも通りシートのフラグを使わせてもらうおう。コレ、とっても便利(嬉。あとはデザインを考えて、表示する関数を実装するだけだ。とりあえず4つのメニューを用意してみた(画像参照)。それらしく見せるために、実装していない機能まで盛り込んでみた(笑。ちなみに、タイトル部分の表示は、通常のウィンドウの表示と似ているのだが、微妙に違いがあるため、表示する関数を別に用意した。将来的にはボタンのないウィンドウが表示できるAPIの実装なんかも考えて、1つの関数にまとめられるといいな。まあ、ここではこれで、えい実行・・・。ぺこん、表示できました。

 

Step-2

メニューだぁ。ん?内容に偽りあり・・・(汗。

 


Step-3

さあ、連続して行きますよ〜。メニューの上でマウスを動かしたときに、マウス位置にあるメニューをハイライトする処理をつけよう。ハイライトされているメニューを判別するために、メニューを開いたときに立てるフラグ(Step-1参照)にちょっと細工して、メニューの場所を保管しておこう。メニューの場所はマウス位置から算出する。マウスが範囲外の場合は0にしておくことにする。以前の場所が0でない場合はハイライトを消し、新しい場所を算出して、0でない場合はハイライトする。ハイライトする関数は、ウィンドウタイトルをアクティブ/非アクティブにする関数を流用すれば簡単だ。うむ、思ったよりあっさりできた(笑。さてさて、実行しま〜す・・・。ぉぉぉ、ハイライトが切り替わるぅぅぅ。あ、まだなーんにも起動できません(笑。

 

Step-3

はりぼてメニューですが、それらしく見えるのが不思議です(笑。

 


Step-4

見た目がメニューらしくなってきたところで、中身の実装にいってみましょうかねぇ。う・・・重大なことにいまさら気づく。今までは、見た目だけ気をつけていればよかったので、表示する文字列なんかは実にテキトーに記述していた。しかし、アプリの起動やサブメニューの追加を考えると、いいかげんな管理では対応できない。ここをテキトーのまま突っ走ると、プログラムの方が複雑になり、ちょっとした変更でも大幅に修正が必要、なんてことにもなりかねない。よし、ちゃんとメニュー構造体を作ってちゃんと管理しよう。この構造体を配列で管理すると、無駄に大きくなりそうなので、各メニューをポインタでつなぐことにした。階層を意識する必要があるので、横方向と縦方向の2つのポインタを用意した。後はメニューに表示する名称と実行するコマンドを持っていれば十分だ。おっと、メニューがどの階層に位置しているかも保持しておこう。実行コマンドだが、実際に実行コマンドでないもの(consoleやsubmenu)については、「<>」で囲んで区別することにした。メニューの初期化と設定関数を追加して・・・これにて準備完了。

 

・・・と、メニューに関連する情報(シートや選択位置など)を管理しやすくするために、メニュー階層の構造体も用意することにした。これで階層が増えても安心だ。また、開いたメニューを階層ごとに保持することで、メニュー構造体を1から検索するよりも高速に動作する。Step-3で選択位置を保持していたフラグは、現在の階層を示す様に変更した。今度こそ準備完了・・・だといいな(笑。

 

準備も整ったところで、サブメニューの表示をやっちゃいますかね。まずはメニューをクリックしたときにそれぞれの処理を実行する関数を追加しよう。このステップでは、サブメニューをクリックしたときの処理を追加する。メニュー選択位置から呼び出すべき処理を検索して、「<submenu>」だったらメニューを開く関数を呼び出す。このときメニューボタンぺこぺこ処理は不要なので、階層が0以外の場合は実施しない様に変更した。また、サブメニューの表示位置を、選択されているメニューの場所に合わせたいので、サブメニューの場合は計算して求める様にした。最後にメニューを閉じるときの処理を、開いているすべてのメニューを閉じる様にして完了。さぁ〜実行しますよ、とりゃ!!・・・ふむふむ、ちょうどいい位置に表示されました。

 

Step-4

サブメニュー・・・う〜ん、いい響きだ(笑。

 


Step-5

長々と続けてきてしまいましたが、いよいよ最後の仕上げです。ちょっと寂しい気もしますが、開発が進まないので、あきらめて仕上げちゃうことにします(笑。さあ、コンソール起動とアプリの起動を追加しますよ〜。といっても、メニューをクリックしたときの関数(Step-4で追加したヤツね)に、実行コマンドが「<console>」の場合とそれ以外の処理を追加するだけなのだ。コンソールについては、Shift+F2キーを押下したときと同じ処理だし、それ以外の処理も、おなじみの「ncst」コマンドを利用すれば簡単だ。あっさり完成〜!! といいたいところだけど、ちょっとサブメニュー表示を修正しておこう。まず、サブメニューにタイトルがあるのはちょっとしつこい気もするので、タイトルを取っ払った。これに伴って表示位置などを修正した。また、右クリックで現在のメニューを閉じられる様に変更した。右クリックの処理は本文にはなかったので、新たに分岐を追加することになるが、左クリックのマネをすればOKだ。お〜し、起動&クリッククリック!! あははは、ポンポン起動するぞコレ(当たり前ですね。

 

Step-5

階層も変えてみました。調子にのって、たくさんアプリを起動してみました(笑。