VST GUIにおけるコンテキストメニューの実装
VST GUIにおいて右クリックでポップアップするコンテキストメニューを実装する方法を説明いたします。
なお、VST GUIの基本的な作成方法として下記をご理解いただいている前提で進めさせていただきます。
また、コンテキストメニューはCOptionMenuクラスを使用したり、valueChanged()関数でメニュー項目の選択処理などを行うため、「コンボボックスの実装」や「複数コントロールの同期」についても参考にしてください。
CViewクラスの作成
まず、マウスの右クリック操作を受け取るためのクラスをCViewクラスを継承して作成します。
このクラスは背景画像や背景色を設定しないため見た目上は何も表示されないビュー(UI)となります。
【guieditor.h】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class CMyView : public CView { protected: COptionMenu* contextMenu = nullptr; public: // 第1引数sizeは右クリックを受け付ける範囲 // 第2引数listenerは操作の処理を行うリスナー CMyView(const CRect& size, IControlListener* listener); ~CMyView(); CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) SMTG_OVERRIDE; CControl* getContextMenu(); }; |
【guieditor.cpp】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
CMyView::CMyView(const CRect& size, IControlListener* listener) : CView(size) { // コンテキストメニュー用のCOptionMenuクラスを作成する contextMenu = new COptionMenu(); // コンテキストメニューにのスタイルを設定する。 // kPopupStyleとすることで、ポップアップウィンドウのみとなる。 // (デフォルトのスタイルではコンボボックスのような形となる。) contextMenu->setStyle(COptionMenu::kPopupStyle); // コンテキストメニューにアイテム(選択肢)を追加する。 contextMenu->addEntry("menu 1"); contextMenu->addEntry("menu 2"); contextMenu->addEntry("menu 3"); contextMenu->addEntry("menu 4"); // コンテキストメニューが操作されたときのリスナーをセットする。 // VST GUIのクラスを設定することで、アイテムが選ばれたときにvalueChange()関数が呼ばれるようになる。 contextMenu->setListener(listener); // 他のコントロールに影響を与えないよう、透過状態にする。 setTransparency(true); } CMyView::~CMyView() { if (contextMenu != nullptr) contextMenu->forget(); } CMouseEventResult CMyView::onMouseDown(CPoint& where, const CButtonState& buttons) { // 右クリックが押されたかどうかを確認する if (buttons.isRightButton()) { // コンテキストメニューをポップアップする。 contextMenu->popup(getFrame(), where); // 右クリックの処理が正常終了したので、 // kMouseDownEventHandledButDontNeedMovedOrUpEventsを返す。 return kMouseDownEventHandledButDontNeedMovedOrUpEvents; } // 右クリック以外の処理については、実装していないので、 // kMouseEventNotImplementedを返す return kMouseEventNotImplemented; } CControl* CMyView::getContextMenu() { return contextMenu; } |
CMyViewクラスでは、コンストラクタでコンテキストメニュー用のCOptionMenuクラスを作成します。ただし、ここではCOptionMenuクラスの表示をさせません。
また、操作されたときに呼び出されるリスナーをセットしたり、他のコントロールに影響を与えないよう透過状態にしています。
デストラクタでは、コンテキストメニュー用のCOptionMenuクラスをforget()関数で解放しています。
onMouseDown()関数は、CViewクラスの関数をオーバーライドしたもので、コンテキストメニューをポップアップする処理をしています。
マウスのクリックが右クリックが押されたかどうかを確認し、右クリックの場合にCOptionMenuクラスのpopup()関数を呼び出して表示しています。
getContextMenu()関数は他のクラスなどがメンバー変数のcontextMenuを取得するための関数です。
後述するvalueChanged()関数などで使うために定義しています。
VST GUIへの組み込み
CMyViewクラスが実装できれば、実際にVST GUIに組み込みます。
VST GUIクラスのopen()関数内でCMyViewクラスを作成します。
CMyViewクラス作成時にCMyViewクラスのポインタはvalueChanged()関数などで使用するためあらかじめ定義したメンバー変数myViewに保存します。
【guieditor.h】
1 2 3 4 5 6 7 8 |
class MyVSTGUIEditor : public VSTGUIEditor, public IControlListener { protected: CMyView* myView = nullptr; public: ~~ 中略 ~~ } |
【guieditor.cpp】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
bool PLUGIN_API MyVSTGUIEditor::open(void* parent, const PlatformType& platformType) { // GUIウィンドウが開かれたときに、UIを作成する ~~ 中略 ~~ // --------------------------------------------- // ここから各コントロールの作成 // 第1引数は右クリックを受け付ける範囲になるのでframeと同じサイズを指定する // 第2引数はvalueChange()関数が呼ばれるリスナーなので、VST GUIクラス(つまりthis)を指定する myView = new CMyView(size, this); frame->addView(myView); ~~ 中略 ~~ // GUIウィンドウのオープンに成功した場合はtrueを返す return true; } |
作成時の注意点として、CMyViewクラスをフレームに追加する順番(frame->addView()を行う順番)に注意してください。
CMyViewクラスよりも後に追加されたコントロールについては、そのコントロール上で右クリックを行っても、コンテキストメニューは開きません。
逆にCMyViewクラスよりも前に追加されたコントロールでは、コンテキストメニューが開きますが、コントロール自体に個別のコンテキストメニューがある場合は2重でポップアップウィンドウが開く可能性があります。
コンテキストメニュー操作時の処理
つづいてコンテキストメニューが操作されたときの処理を追加します。
コンテキストメニューのアイテムが選択されるとvalueChanged()関数が呼び出されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
void MyVSTGUIEditor::valueChanged(CControl* pControl) { ~~ 中略 ~~ // 操作されたコントロールがCMyViewクラスのコンテキストメニューかどうかを確認 if (pControl == myView->getContextMenu()) { // コンテキストメニューだったので何番目のアイテムが選択されたか取得する。 // 今回のサンプルは4つアイテムを追加したので、「0.0、0.333…、0,666…、1.0」になる // 3倍して0~3の整数値にしている。 int selected = (int)(pControl->getValueNormalized() * 3); switch (selected) { case 0: // 「menu 1」が選ばれたときの処理 break; case 1: // 「menu 2」が選ばれたときの処理 break; case 2: // 「menu 3」が選ばれたときの処理 break; case 3: // 「menu 4」が選ばれたときの処理 break; } } } |
valueChanged()関数では操作されたコントロールがCMyViewクラスのコンテキストメニューかどうかを確認します。
コンテキストメニューだった場合、どのアイテムが選択されたかを取得し、アイテムに合わせて処理を実施します。
おわりに
以上でコンテキストメニューが実装できます。
上記以外にもVST3.6についての情報があります。下記をご参照ください。
また、質問やご指摘はコメント欄や掲示板、Twitterでいただけばとおもいます。
■掲示板
■Twitterアカウント:@vstcpp URL:https://twitter.com/vstcpp
こんにちは。いつも大変参考にさせていただいてます。
今自作しているプラグインで、メインUI上に必要に応じて別のウィンドウを描画(そのウィンドウ描画中はメインUIをグレーアウトさせる)したいのですが、そのような場合もコンテキストメニューの例のように新しくCViewを継承したクラスを作れば良いのでしょうか?
nattou29さん
お返事遅れました。
CViewクラスで覆ってしまうというのは一つの手だと思います。
Windowsだとウィンドウハンドルを取得してウィンドウ自体を操作不能にすることもできた気がします。
(すいません。ちょっとこのあたりの記憶は曖昧です。 )
VST GUIのopen()関数の引数parentがウィンドウハンドルだったと思います。
お返事ありがとうございます。
色々やっていたらCViewでsetAlphaValueなど使ってなんとか実現できそうです。
そうなのですね、ウィンドウハンドルについても調べてみようと思います
。 助言いただき感謝です。