mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-12 02:40:00 +01:00
Unified & fixed implementation of Group of sources (formerly flatten)
Fixed MixingGroup keep&restore when making Session Group Sources. New global feature to Group all sources into one session source. Unused but potentially useful implementation of flatten of mixer session into one new session source.
This commit is contained in:
@@ -675,7 +675,7 @@ void ImGuiVisitor::visit (SessionGroupSource& s)
|
|||||||
|
|
||||||
ImGuiToolkit::Icon(s.icon().x, s.icon().y);
|
ImGuiToolkit::Icon(s.icon().x, s.icon().y);
|
||||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||||
ImGui::Text("Flat Sesion group");
|
ImGui::Text("Session group");
|
||||||
|
|
||||||
// info
|
// info
|
||||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
|
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
|
||||||
|
|||||||
@@ -120,12 +120,12 @@ void LayerView::draw()
|
|||||||
|
|
||||||
// special action of Mixing view
|
// special action of Mixing view
|
||||||
if (candidate_flatten_group){
|
if (candidate_flatten_group){
|
||||||
if (ImGui::Selectable( ICON_FA_DOWNLOAD " Flatten" )) {
|
if (ImGui::Selectable( ICON_FA_SIGN_IN_ALT " Group" )) {
|
||||||
Mixer::manager().flattenSelection();
|
Mixer::manager().groupSelection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImGui::TextDisabled( ICON_FA_DOWNLOAD " Flatten" );
|
ImGui::TextDisabled( ICON_FA_SIGN_IN_ALT " Group" );
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
#define MEDIA_PLAYER_DEBUG
|
#define MEDIA_PLAYER_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DISCOVER_TIMOUT 15
|
||||||
|
|
||||||
std::list<MediaPlayer*> MediaPlayer::registered_;
|
std::list<MediaPlayer*> MediaPlayer::registered_;
|
||||||
|
|
||||||
MediaPlayer::MediaPlayer()
|
MediaPlayer::MediaPlayer()
|
||||||
@@ -123,7 +125,7 @@ MediaInfo MediaPlayer::UriDiscoverer(const std::string &uri)
|
|||||||
#endif
|
#endif
|
||||||
MediaInfo video_stream_info;
|
MediaInfo video_stream_info;
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
GstDiscoverer *discoverer = gst_discoverer_new (15 * GST_SECOND, &err);
|
GstDiscoverer *discoverer = gst_discoverer_new (DISCOVER_TIMOUT * GST_SECOND, &err);
|
||||||
|
|
||||||
/* Instantiate the Discoverer */
|
/* Instantiate the Discoverer */
|
||||||
if (!discoverer) {
|
if (!discoverer) {
|
||||||
@@ -448,7 +450,8 @@ void MediaPlayer::close()
|
|||||||
if (!opened_) {
|
if (!opened_) {
|
||||||
// wait for loading to finish
|
// wait for loading to finish
|
||||||
if (discoverer_.valid())
|
if (discoverer_.valid())
|
||||||
discoverer_.wait();
|
if ( discoverer_.wait_for(std::chrono::seconds(DISCOVER_TIMOUT)) == std::future_status::timeout )
|
||||||
|
failed_ = true;
|
||||||
// nothing else to change
|
// nothing else to change
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
202
Mixer.cpp
202
Mixer.cpp
@@ -661,74 +661,157 @@ void Mixer::deleteSelection()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mixer::flattenSelection()
|
void Mixer::groupSelection()
|
||||||
{
|
{
|
||||||
|
// obvious cancel
|
||||||
if (selection().empty())
|
if (selection().empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// work on non-empty selection of sources
|
||||||
|
auto _selection = selection().getCopy();
|
||||||
|
|
||||||
|
// create session group where to transfer sources into
|
||||||
SessionGroupSource *sessiongroup = new SessionGroupSource;
|
SessionGroupSource *sessiongroup = new SessionGroupSource;
|
||||||
sessiongroup->setResolution( session_->frame()->resolution() );
|
sessiongroup->setResolution( session_->frame()->resolution() );
|
||||||
|
|
||||||
// prepare for new session group attributes
|
// prepare for new session group name
|
||||||
std::string name;
|
std::string name;
|
||||||
float d = selection().front()->depth();
|
// prepare for depth to place the group source
|
||||||
|
float d = _selection.front()->depth();
|
||||||
// empty the selection
|
|
||||||
while ( !selection().empty() ) {
|
|
||||||
|
|
||||||
Source *s = selection().front();
|
|
||||||
d = MIN(s->depth(), d);
|
|
||||||
|
|
||||||
// import source into group
|
|
||||||
if ( sessiongroup->import(s) ) {
|
|
||||||
name += s->initials();
|
|
||||||
// detach & remove element from selection()
|
|
||||||
detach (s);
|
|
||||||
// remove source from session
|
|
||||||
session_->removeSource(s);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
selection().pop_front();
|
|
||||||
|
|
||||||
|
// remember groups before emptying the session
|
||||||
|
std::list<SourceList> allgroups = session_->getMixingGroups();
|
||||||
|
std::list<SourceList> selectgroups;
|
||||||
|
for (auto git = allgroups.begin(); git != allgroups.end(); ++git){
|
||||||
|
selectgroups.push_back( intersect( *git, _selection));
|
||||||
}
|
}
|
||||||
|
|
||||||
// set depth at given location
|
// browse the selection
|
||||||
sessiongroup->group(View::LAYER)->translation_.z = d;
|
for (auto sit = _selection.begin(); sit != _selection.end(); ++sit) {
|
||||||
|
|
||||||
// set alpha to full opacity
|
// import source into group
|
||||||
sessiongroup->group(View::MIXING)->translation_.x = 0.f;
|
if ( sessiongroup->import(*sit) ) {
|
||||||
sessiongroup->group(View::MIXING)->translation_.y = 0.f;
|
// find lower depth in _selection
|
||||||
|
d = MIN( (*sit)->depth(), d);
|
||||||
|
// generate name from intials of all sources
|
||||||
|
name += (*sit)->initials();
|
||||||
|
// detach & remove element from selection()
|
||||||
|
detach (*sit);
|
||||||
|
// remove source from session
|
||||||
|
session_->removeSource(*sit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add source to Session
|
if (sessiongroup->session()->numSource() > 0) {
|
||||||
session_->addSource(sessiongroup);
|
// recreate groups in session group
|
||||||
|
for (auto git = selectgroups.begin(); git != selectgroups.end(); ++git)
|
||||||
|
sessiongroup->session()->link( *git );
|
||||||
|
|
||||||
// Attach source to Mixer
|
// set depth at given location
|
||||||
attach(sessiongroup);
|
sessiongroup->group(View::LAYER)->translation_.z = d;
|
||||||
|
|
||||||
// rename and avoid name duplicates
|
// set alpha to full opacity
|
||||||
renameSource(sessiongroup, name);
|
sessiongroup->group(View::MIXING)->translation_.x = 0.f;
|
||||||
|
sessiongroup->group(View::MIXING)->translation_.y = 0.f;
|
||||||
|
|
||||||
// store in action manager
|
// Add source to Session
|
||||||
std::ostringstream info;
|
session_->addSource(sessiongroup);
|
||||||
info << sessiongroup->name() << " inserted: " << sessiongroup->session()->numSource() << " sources flatten.";
|
|
||||||
Action::manager().store(info.str());
|
|
||||||
|
|
||||||
Log::Notify("Added source '%s' with %s", sessiongroup->name().c_str(), sessiongroup->info().c_str());
|
// Attach source to Mixer
|
||||||
|
attach(sessiongroup);
|
||||||
|
|
||||||
// give the hand to the user
|
// set name (avoid name duplicates)
|
||||||
Mixer::manager().setCurrentSource(sessiongroup);
|
renameSource(sessiongroup, name);
|
||||||
|
|
||||||
|
// store in action manager
|
||||||
|
std::ostringstream info;
|
||||||
|
info << sessiongroup->name() << " inserted: " << sessiongroup->session()->numSource() << " sources flatten.";
|
||||||
|
Action::manager().store(info.str());
|
||||||
|
|
||||||
|
Log::Notify("Added group source '%s' with %s", sessiongroup->name().c_str(), sessiongroup->info().c_str());
|
||||||
|
|
||||||
|
// give the hand to the user
|
||||||
|
Mixer::manager().setCurrentSource(sessiongroup);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delete sessiongroup;
|
||||||
|
Log::Info("Failed to group selection");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mixer::flatten()
|
void Mixer::groupAll()
|
||||||
{
|
{
|
||||||
//
|
// obvious cancel
|
||||||
|
if (session_->empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create session group where to transfer sources into
|
||||||
|
SessionGroupSource *sessiongroup = new SessionGroupSource;
|
||||||
|
sessiongroup->setResolution( session_->frame()->resolution() );
|
||||||
|
|
||||||
|
// remember groups before emptying the session
|
||||||
|
std::list<SourceList> allgroups = session_->getMixingGroups();
|
||||||
|
|
||||||
|
// empty the session (does not delete sources)
|
||||||
|
for ( Source *s = session_->popSource(); s != nullptr; s = session_->popSource()) {
|
||||||
|
if ( sessiongroup->import(s) )
|
||||||
|
detach(s);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessiongroup->session()->numSource() > 0) {
|
||||||
|
|
||||||
|
// recreate groups in session group
|
||||||
|
for (auto git = allgroups.begin(); git != allgroups.end(); ++git)
|
||||||
|
sessiongroup->session()->link( *git );
|
||||||
|
|
||||||
|
// set default depth in workspace for the session-group source
|
||||||
|
sessiongroup->group(View::LAYER)->translation_.z = LAYER_BACKGROUND + LAYER_STEP;
|
||||||
|
|
||||||
|
// set alpha to full opacity so that rendering is identical after swap
|
||||||
|
sessiongroup->group(View::MIXING)->translation_.x = 0.f;
|
||||||
|
sessiongroup->group(View::MIXING)->translation_.y = 0.f;
|
||||||
|
|
||||||
|
// Add the session-group source to Session
|
||||||
|
session_->addSource(sessiongroup);
|
||||||
|
|
||||||
|
// Attach the session-group source to Mixer
|
||||||
|
attach(sessiongroup);
|
||||||
|
|
||||||
|
// name the session-group source (avoid name duplicates)
|
||||||
|
renameSource(sessiongroup, SystemToolkit::base_filename(session_->filename()));
|
||||||
|
|
||||||
|
// store in action manager
|
||||||
|
std::ostringstream info;
|
||||||
|
info << sessiongroup->name() << " inserted: " << sessiongroup->session()->numSource() << " sources flatten.";
|
||||||
|
Action::manager().store(info.str());
|
||||||
|
|
||||||
|
Log::Notify("Added group source '%s' with %s", sessiongroup->name().c_str(), sessiongroup->info().c_str());
|
||||||
|
|
||||||
|
// give the hand to the user
|
||||||
|
Mixer::manager().setCurrentSource(sessiongroup);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delete sessiongroup;
|
||||||
|
Log::Info("Failed to group all sources.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mixer::flattenSession()
|
||||||
|
{
|
||||||
|
// new session group containing current session
|
||||||
SessionGroupSource *sessiongroup = new SessionGroupSource;
|
SessionGroupSource *sessiongroup = new SessionGroupSource;
|
||||||
sessiongroup->setSession(session_);
|
sessiongroup->setSession(session_);
|
||||||
|
|
||||||
// set alpha to full opacity
|
// set alpha to full opacity so that rendering is identical after swap
|
||||||
sessiongroup->group(View::MIXING)->translation_.x = 0.f;
|
sessiongroup->group(View::MIXING)->translation_.x = 0.f;
|
||||||
sessiongroup->group(View::MIXING)->translation_.y = 0.f;
|
sessiongroup->group(View::MIXING)->translation_.y = 0.f;
|
||||||
|
|
||||||
|
// set default depth in workspace
|
||||||
|
sessiongroup->group(View::LAYER)->translation_.z = LAYER_BACKGROUND + LAYER_STEP;
|
||||||
|
|
||||||
// propose a name to the session group
|
// propose a name to the session group
|
||||||
sessiongroup->setName( SystemToolkit::base_filename(session_->filename()));
|
sessiongroup->setName( SystemToolkit::base_filename(session_->filename()));
|
||||||
|
|
||||||
@@ -736,19 +819,24 @@ void Mixer::flatten()
|
|||||||
Session *futuresession = new Session;
|
Session *futuresession = new Session;
|
||||||
futuresession->addSource( sessiongroup );
|
futuresession->addSource( sessiongroup );
|
||||||
|
|
||||||
// set and swap to futuresession
|
// set identical filename to future session
|
||||||
|
futuresession->setFilename( session_->filename() );
|
||||||
|
|
||||||
|
// set and swap to futuresession (will be done at next update)
|
||||||
set(futuresession);
|
set(futuresession);
|
||||||
|
|
||||||
// detatch current session's nodes from views
|
// detatch current session_'s nodes from views
|
||||||
for (auto source_iter = session_->begin(); source_iter != session_->end(); source_iter++)
|
for (auto source_iter = session_->begin(); source_iter != session_->end(); source_iter++)
|
||||||
detach(*source_iter);
|
detach(*source_iter);
|
||||||
// detatch session's mixing group
|
|
||||||
|
// detatch session_'s mixing group
|
||||||
for (auto group_iter = session_->beginMixingGroup(); group_iter != session_->endMixingGroup(); group_iter++)
|
for (auto group_iter = session_->beginMixingGroup(); group_iter != session_->endMixingGroup(); group_iter++)
|
||||||
(*group_iter)->attachTo(nullptr);
|
(*group_iter)->attachTo(nullptr);
|
||||||
|
|
||||||
// prevent deletion of session_ (now embedded into session group)
|
// prevent deletion of session_ (now embedded into session group)
|
||||||
session_ = new Session;
|
session_ = new Session;
|
||||||
|
|
||||||
Log::Notify("Created source '%s' with %s", sessiongroup->name().c_str(), sessiongroup->info().c_str());
|
Log::Notify("Created group source '%s' with %s", sessiongroup->name().c_str(), sessiongroup->info().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mixer::renameSource(Source *s, const std::string &newname)
|
void Mixer::renameSource(Source *s, const std::string &newname)
|
||||||
@@ -1135,6 +1223,9 @@ void Mixer::merge(Session *session)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remember groups before emptying the session
|
||||||
|
std::list<SourceList> allgroups = session->getMixingGroups();
|
||||||
|
|
||||||
// import every sources
|
// import every sources
|
||||||
std::ostringstream info;
|
std::ostringstream info;
|
||||||
info << session->numSource() << " sources imported from:" << session->filename();
|
info << session->numSource() << " sources imported from:" << session->filename();
|
||||||
@@ -1149,12 +1240,9 @@ void Mixer::merge(Session *session)
|
|||||||
attach(s);
|
attach(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// import and attach session's mixing groups
|
// recreate groups in current session_
|
||||||
auto group_iter = session->beginMixingGroup();
|
for (auto git = allgroups.begin(); git != allgroups.end(); ++git)
|
||||||
while ( group_iter != session->endMixingGroup() ){
|
session_->link( *git, mixing_.scene.fg() );
|
||||||
session_->link((*group_iter)->getCopy(), mixing_.scene.fg());
|
|
||||||
group_iter = session->deleteMixingGroup(group_iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// needs to update !
|
// needs to update !
|
||||||
++View::need_deep_update_;
|
++View::need_deep_update_;
|
||||||
@@ -1206,6 +1294,9 @@ void Mixer::merge(SessionSource *source)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remember groups before emptying the session
|
||||||
|
std::list<SourceList> allgroups = session->getMixingGroups();
|
||||||
|
|
||||||
// import every sources
|
// import every sources
|
||||||
for ( Source *s = session->popSource(); s != nullptr; s = session->popSource()) {
|
for ( Source *s = session->popSource(); s != nullptr; s = session->popSource()) {
|
||||||
|
|
||||||
@@ -1236,12 +1327,9 @@ void Mixer::merge(SessionSource *source)
|
|||||||
attach(s);
|
attach(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// import and attach session's mixing groups
|
// recreate groups in current session_
|
||||||
auto group_iter = session->beginMixingGroup();
|
for (auto git = allgroups.begin(); git != allgroups.end(); ++git)
|
||||||
while ( group_iter != session->endMixingGroup() ){
|
session_->link( *git, mixing_.scene.fg() );
|
||||||
session_->link((*group_iter)->getCopy(), mixing_.scene.fg());
|
|
||||||
group_iter = session->deleteMixingGroup(group_iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// needs to update !
|
// needs to update !
|
||||||
++View::need_deep_update_;
|
++View::need_deep_update_;
|
||||||
|
|||||||
6
Mixer.h
6
Mixer.h
@@ -66,7 +66,10 @@ public:
|
|||||||
|
|
||||||
// operations on selection
|
// operations on selection
|
||||||
void deleteSelection ();
|
void deleteSelection ();
|
||||||
void flattenSelection ();
|
void groupSelection ();
|
||||||
|
void groupAll ();
|
||||||
|
|
||||||
|
void flattenSession();
|
||||||
|
|
||||||
// current source
|
// current source
|
||||||
Source *currentSource ();
|
Source *currentSource ();
|
||||||
@@ -113,7 +116,6 @@ public:
|
|||||||
void setResolution(glm::vec3 res);
|
void setResolution(glm::vec3 res);
|
||||||
bool busy () const { return busy_; }
|
bool busy () const { return busy_; }
|
||||||
|
|
||||||
void flatten();
|
|
||||||
|
|
||||||
// operations depending on transition mode
|
// operations depending on transition mode
|
||||||
void close (bool smooth = false);
|
void close (bool smooth = false);
|
||||||
|
|||||||
@@ -330,6 +330,9 @@ Source *Session::popSource()
|
|||||||
s = *its;
|
s = *its;
|
||||||
// remove Node from the rendering scene
|
// remove Node from the rendering scene
|
||||||
render_.scene.ws()->detach( s->group(View::RENDERING) );
|
render_.scene.ws()->detach( s->group(View::RENDERING) );
|
||||||
|
// inform group
|
||||||
|
if (s->mixingGroup() != nullptr)
|
||||||
|
s->mixingGroup()->detach(s);
|
||||||
// erase the source from the update list & get next element
|
// erase the source from the update list & get next element
|
||||||
sources_.erase(its);
|
sources_.erase(its);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -934,10 +934,6 @@ void UserInterface::showMenuFile()
|
|||||||
ImGui::SetNextItemWidth( ImGui::GetContentRegionAvail().x * 0.54f);
|
ImGui::SetNextItemWidth( ImGui::GetContentRegionAvail().x * 0.54f);
|
||||||
ImGui::Combo("Height", &Settings::application.render.res, FrameBuffer::resolution_name, IM_ARRAYSIZE(FrameBuffer::resolution_name) );
|
ImGui::Combo("Height", &Settings::application.render.res, FrameBuffer::resolution_name, IM_ARRAYSIZE(FrameBuffer::resolution_name) );
|
||||||
|
|
||||||
if (ImGui::MenuItem( ICON_FA_FILE_IMPORT " Embed in New file", nullptr, false, Mixer::manager().numSource() > 0)) {
|
|
||||||
Mixer::manager().flatten();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILE OPEN AND SAVE
|
// FILE OPEN AND SAVE
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
const std::string currentfilename = Mixer::manager().session()->filename();
|
const std::string currentfilename = Mixer::manager().session()->filename();
|
||||||
@@ -949,11 +945,6 @@ void UserInterface::showMenuFile()
|
|||||||
selectOpenFilename();
|
selectOpenFilename();
|
||||||
if (ImGui::MenuItem( MENU_REOPEN_FILE, SHORTCUT_REOPEN_FILE, false, currentfileopen))
|
if (ImGui::MenuItem( MENU_REOPEN_FILE, SHORTCUT_REOPEN_FILE, false, currentfileopen))
|
||||||
Mixer::manager().load( currentfilename );
|
Mixer::manager().load( currentfilename );
|
||||||
if (sessionimportdialog && ImGui::MenuItem( ICON_FA_FILE_EXPORT " Import sources" )) {
|
|
||||||
// launch file dialog to open a session file
|
|
||||||
sessionimportdialog->open();
|
|
||||||
navigator.hidePannel();
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem( MENU_SAVE_FILE, SHORTCUT_SAVE_FILE, false, currentfileopen)) {
|
if (ImGui::MenuItem( MENU_SAVE_FILE, SHORTCUT_SAVE_FILE, false, currentfileopen)) {
|
||||||
if (saveOrSaveAs())
|
if (saveOrSaveAs())
|
||||||
navigator.hidePannel();
|
navigator.hidePannel();
|
||||||
@@ -963,6 +954,21 @@ void UserInterface::showMenuFile()
|
|||||||
|
|
||||||
ImGui::MenuItem( MENU_SAVE_ON_EXIT, nullptr, &Settings::application.recentSessions.save_on_exit);
|
ImGui::MenuItem( MENU_SAVE_ON_EXIT, nullptr, &Settings::application.recentSessions.save_on_exit);
|
||||||
|
|
||||||
|
// IMPORT AND GROUP
|
||||||
|
ImGui::Separator();
|
||||||
|
if (sessionimportdialog && ImGui::MenuItem( ICON_FA_SIGN_OUT_ALT " Import sources" )) {
|
||||||
|
// launch file dialog to open a session file
|
||||||
|
sessionimportdialog->open();
|
||||||
|
// close pannel to select file
|
||||||
|
navigator.hidePannel();
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem( ICON_FA_SIGN_IN_ALT " Group all sources", nullptr, false, Mixer::manager().numSource() > 0)) {
|
||||||
|
// create a new group session with all sources
|
||||||
|
Mixer::manager().groupAll();
|
||||||
|
// switch pannel to show first source (created)
|
||||||
|
navigator.showPannelSource(0);
|
||||||
|
}
|
||||||
|
|
||||||
// HELP AND QUIT
|
// HELP AND QUIT
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::MenuItem( IMGUI_TITLE_HELP, SHORTCUT_HELP))
|
if (ImGui::MenuItem( IMGUI_TITLE_HELP, SHORTCUT_HELP))
|
||||||
|
|||||||
Reference in New Issue
Block a user