Last active
September 23, 2016 22:57
-
-
Save usagi/aaa92de1a93e8a6c15b16763258d9ff0 to your computer and use it in GitHub Desktop.
ImGui を使い"コンテキストメニュー"をもう少し"高度"にステートフルなオールインワン実装する例を紹介したい ref: http://qiita.com/usagi/items/671bc7c573a600819ac3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
std::string label = "hoge"; | |
std::string id = "xyz"; | |
ImVec2 size; | |
auto clicked = | |
ImGui::Button | |
( ( id.empty() ? label : label + "###" + id ).c_str() // param-1 label & id | |
, size | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct button | |
{ | |
std::string label; | |
std::string id; | |
std::function< auto () -> void > on_click; // †1 | |
ImVec2 size; | |
auto operator()() const | |
{ | |
if | |
( ImGui::Button | |
( ( id.empty() ? label : label + "###" + id ).c_str() | |
, size | |
) | |
) | |
on_click(); | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if ( ImGui::BeginXXX( ... ) ) | |
{ | |
... | |
ImGui::EndXXX( ... ); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
auto operator()() const | |
{ | |
// 第1階層のメニュー定義のルートノードを開始 | |
if ( ImGui::BeginMenu( ROOT, ... ) ) | |
{ | |
// 第1階層に末端のメニューノード A を定義 | |
if ( ImGui::MenuItem( ROOT-A, ... ) ) | |
on_click( ROOT-A, ... ); | |
// 第1階層から第2階層へネストを展開する中間のメニューノード B を定義 | |
if ( ImGui::BeginMenu( ROOT-B ... )) | |
{ | |
// 第2階層に末端のメニューノード ROOT-B-X を定義 | |
if ( ImGui::MenuItem( ROOT-B-X, ... ) ) | |
on_click( ROOT-B-X, ... ); | |
// 第1階層から第2階層へネストしたメニュー定義 ROOT-B を終了 | |
ImGui::EndMenu( ... ); | |
} | |
// 第1階層のメニュー定義のルートノードを終了 | |
ImGui::EndMenu( ... ); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct statefull_menu_type | |
{ | |
// ctor: https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L28 | |
statefull_menu_type( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L37 | |
auto operator()( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L149 | |
auto show( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L65 | |
auto clear( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L78 | |
auto remove( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L83 | |
auto add( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L102 | |
auto modify( ... ); | |
private: | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L155 | |
auto _split( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L162 | |
auto _generate_random_number( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L182 | |
auto _remove( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L225 | |
auto _add( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L259 | |
auto _recursive_menu_render( ... ); | |
// https://github.com/usagi/usagi/blob/e11b5ee19ef8c79ba9a5387407c1a4fc17bb9d8f/include/usagi/imgui/statefull_menu_type.hxx#L170 | |
struct recursive_mapper_type; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using usagi::imgui::statefull_menu_type; | |
// テストコードの例として簡単のため static にオブジェクトを定義する。 | |
// 実際にはクラスのメンバー変数にする事が多いだろう。 | |
static statefull_menu_type o; | |
static statefull_menu_type n; | |
static statefull_menu_type q; | |
// テストコードの例として簡単のためメニュー定義が空ならば初期化するよう定義する。 | |
// 実際にはクラスの initialize タイミングで行う事が多いだろう。 | |
if ( q.empty() ) | |
// メニューの階層構造は ImGui らしい便利さを優先したい事が多いだろうから、 | |
// テキストから簡単に階層構造を定義できるようにしてみた。 | |
// また、コンテキストメニューは末端のノードがクリックされた際に何らかのイベントを処理したい用途が通常なので、 | |
// イベントはラムダ式で放り込めるようにしてみた。 | |
// ImGui では callback 系に `std::function` を採用できない事情があるためステートレスでなければならないが、 | |
// 今回はラッパークラスを定義して任意の C++ ファンクターを扱えるので便利も善い。 | |
q.add | |
( decltype( q )::value_type{ "aaa/bbb/ccc" , [&]{ q.clear(); std::cerr << 0; } } | |
, decltype( q )::value_type{ "aaa/bbb/ddd" , []{ std::cerr << 1; } } | |
, decltype( q )::value_type{ "aaa/xxx/yyy/zzz" , []{ std::cerr << 2; } } | |
, decltype( q )::value_type{ "aaa/xxx/yyy/www" , []{ std::cerr << 3; } } | |
, decltype( q )::value_type{ "ppp/xxx/sss/ttt" , []{ std::cerr << 4; } } | |
, decltype( q )::value_type{ "ppp/xxx/sss/uuu/vvv", []{ std::cerr << 5; } } | |
, decltype( q )::value_type{ "qqq/xxx/sss/ttt" , [&]{ q.remove( "qqq/xxx/sss/ttt" ); std::cerr << 6; } } | |
, decltype( q )::value_type{ "qqq/xxx/sss/uuu/vvv", [&]{ q.remove( "qqq/xxx/sss/uuu/vvv" ); std::cerr << 7; } } | |
); | |
if ( n.empty() ) | |
n.add | |
( decltype( n )::value_type{ "nnn/1/2/3", [&]{ std::cerr << "n3 "; } } | |
, decltype( n )::value_type{ "nnn/4/5/6", [&]{ std::cerr << "n6 "; } } | |
, decltype( n )::value_type{ "nnn/7/8/9", [&]{ std::cerr << "n9 "; } } | |
); | |
if ( o.empty() ) | |
o.add | |
( decltype( o )::value_type{ "ooo/1/2/3", [&]{ std::cerr << "o3 "; } } | |
, decltype( o )::value_type{ "ooo/4/5/6", [&]{ std::cerr << "o6 "; } } | |
, decltype( o )::value_type{ "ooo/7/8/9", [&]{ std::cerr << "o9 "; } } | |
); | |
// 蛇足的な注意となるが、ここでもボタンの ID は重複してはならない。 | |
if ( ImGui::Button( "open context menu 1" ) ) | |
// 実際にはクラスの update 処理中などに何らかのトリガーに応じて呼ぶことになるだろう。 | |
q.show(); | |
if ( ImGui::Button( "open context menu 2" ) ) | |
n.show(); | |
if ( ImGui::Button( "open context menu 3" ) ) | |
o.show(); | |
// 実際にはクラスの render 処理中に定義する事になるだろ。 | |
q(); | |
n(); | |
o(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment