From 059b61805f64be01847bf1c29b1f9e04405a2db4 Mon Sep 17 00:00:00 2001 From: poikilos <7557867+poikilos@users.noreply.github.com> Date: Mon, 29 Mar 2021 13:54:27 -0400 Subject: [PATCH] Fix recent menu iteration and don't add the test file to recent... ...Improve output. Reduce GUI debugging output. Save the debug version in debug/ for the shell build. Don't overlap enum values for elements and commands. --- Engine.cpp | 19 ++++-- Engine.h | 4 +- UserInterface.cpp | 146 ++++++++++++++++++++++++++++++++++++---------- UserInterface.h | 12 +++- View.cpp | 5 +- build.sh | 10 +++- main.cpp | 2 +- 7 files changed, 151 insertions(+), 47 deletions(-) diff --git a/Engine.cpp b/Engine.cpp index 95f4e39..5260e80 100644 --- a/Engine.cpp +++ b/Engine.cpp @@ -452,12 +452,17 @@ vector3df Engine::camTarget() return m_CamTarget; } -bool Engine::loadMesh(const wstring& fileName) +bool Engine::loadMesh(const wstring& fileName, bool enableAddRecent) { bool ret = false; irr::scene::IAnimatedMesh* mesh = m_Scene->getMesh(fileName.c_str()); if (mesh != nullptr) { + // this->addRecent(Utility::toString(fileName)); + if (enableAddRecent) { + this->m_UserInterface->addRecentMenuItem(Utility::toString(fileName), true); + // ^ hasRecent throws "There was no menu for 1 in hasRecent" + } this->m_LoadedTexturePath = L""; this->m_LoadedMeshPath = fileName; // even if bad, set this // to allow F5 to reload @@ -601,7 +606,7 @@ bool Engine::reloadMesh() { bool ret = false; if (this->m_LoadedMeshPath.length() > 0) { - ret = loadMesh(this->m_LoadedMeshPath); + ret = loadMesh(this->m_LoadedMeshPath, false); } if (this->m_UserInterface != nullptr) this->m_UserInterface->OnSelectMesh(); @@ -706,14 +711,16 @@ std::wstring Engine::saveMesh(const io::path path, const std::string& nameOrBlan return ret; } -void Engine::reloadTexture() +bool Engine::reloadTexture() { + bool result = false; if (this->m_LoadedTexturePath.length() > 0) { if (wcslen(this->m_UserInterface->texturePathEditBox->getText()) == 0) - loadTexture(this->m_UserInterface->texturePathEditBox->getText()); + result = loadTexture(this->m_UserInterface->texturePathEditBox->getText()); else - loadTexture(this->m_LoadedTexturePath); + result = loadTexture(this->m_LoadedTexturePath); } + return result; } bool Engine::loadTexture(const wstring& fileName) @@ -904,7 +911,7 @@ void Engine::run() std::cerr << "* running tests..." << std::endl; this->m_EnableTestAndExit = false; std::cerr << "* loading test model..." << std::endl; - if (!this->loadMesh(L"dist/share/b3view/meshes/penguin-lowpoly-poikilos.b3d")) { + if (!this->loadMesh(L"dist/share/b3view/meshes/penguin-lowpoly-poikilos.b3d", false)) { throw "loading dist/share/b3view/meshes/penguin-lowpoly-poikilos.b3d failed."; } std::cerr << "* loading test model's next texture..." << std::endl; diff --git a/Engine.h b/Engine.h index 342a09c..16f54b1 100644 --- a/Engine.h +++ b/Engine.h @@ -81,11 +81,11 @@ public: irr::core::vector3df camTarget(); void run(); bool loadScene(const std::wstring& fileName); - bool loadMesh(const std::wstring& fileName); + bool loadMesh(const std::wstring& fileName, bool enableAddRecent); bool pushOption(const std::wstring& optionStr); bool reloadMesh(); std::wstring saveMesh(const irr::io::path path, const std::string& nameOrBlank, const std::string& extension); - void reloadTexture(); + bool reloadTexture(); bool loadTexture(const std::wstring& fileName); void setMeshDisplayMode(bool wireframe = false, bool lighting = false, bool textureInterpolation = true); bool isAnimating(); diff --git a/UserInterface.cpp b/UserInterface.cpp index f7e93ac..53aa6f1 100644 --- a/UserInterface.cpp +++ b/UserInterface.cpp @@ -40,15 +40,17 @@ void UserInterface::setupUserInterface() // Menu menu = m_Gui->addMenu(); - menu->addItem(L"File", UIE_FILEMENU, true, true); - menu->addItem(L"Playback", UIE_PLAYBACKMENU, true, true); - menu->addItem(L"View", UIE_VIEWMENU, true, true); + this->fileMenuIdx = menu->addItem(L"File", UIE_FILEMENU, true, true); + this->playbackMenuIdx = menu->addItem(L"Playback", UIE_PLAYBACKMENU, true, true); + this->viewMenuIdx = menu->addItem(L"View", UIE_VIEWMENU, true, true); // File Menu - fileMenu = menu->getSubMenu(0); + fileMenu = menu->getSubMenu(this->fileMenuIdx); fileMenu->addItem(L"Open", UIC_FILE_OPEN); this->fileRecentIdx = fileMenu->addItem(L"Open Recent", UIC_FILE_RECENT, true, true); std::vector recentPaths = this->m_Engine->recentPaths(); + fileMenu->addItem(L"Reload Model F5", UIC_FILE_RELOAD_MESH); + fileMenu->addItem(L"Reload Texture Shift F5", UIC_FILE_RELOAD_TEXTURE); fileMenu->addItem(L"Change Texture", UIC_FILE_OPEN_TEXTURE); fileMenu->addItem(L"Previous Texture Shift F3", UIC_FILE_PREVIOUS_TEXTURE); fileMenu->addItem(L"Next Texture F3", UIC_FILE_NEXT_TEXTURE); @@ -61,8 +63,13 @@ void UserInterface::setupUserInterface() // File, Open Recent submenu this->recentMenu = fileMenu->getSubMenu(this->fileRecentIdx); + std::cerr << "+this->recentMenu text:\"" << Utility::toString((wstring)this->recentMenu->getText()) << "\"" + << " idx:" << Utility::toString((int)this->fileRecentIdx) + << " id:" << Utility::toString((int)this->recentMenu->getID()) + << std::endl; - this->recentMenu->addItem(L"Clear Recent", UIC_FILE_RECENT_CLEAR); + this->fileRecentClearIdx = this->recentMenu->addItem(L"Clear Recent", UIC_FILE_RECENT_CLEAR); + std::cerr << "+this->fileRecentClearIdx: " << this->fileRecentClearIdx << std::endl; this->uic_file_recent_next = UserInterface::UIC_FILE_RECENT_FIRST; this->m_file_recent_first_idx = -1; this->m_file_recent_last_idx = -1; @@ -71,7 +78,7 @@ void UserInterface::setupUserInterface() this->addRecentMenuItems(recentPaths, false); // Playback Menu - playbackMenu = menu->getSubMenu(1); + playbackMenu = menu->getSubMenu(this->playbackMenuIdx); playbackMenu->addItem(L"Previous Frame Left", UIC_PLAYBACK_PREVIOUS, true, false, false, false); @@ -86,7 +93,7 @@ void UserInterface::setupUserInterface() false, false); // View Menu - viewMenu = menu->getSubMenu(2); + viewMenu = menu->getSubMenu(this->viewMenuIdx); viewWireframeIdx = viewMenu->addItem(L"Wireframe", UIC_VIEW_WIREFRAME, true, false, this->m_Engine->getEnableWireframe(), true); @@ -357,19 +364,21 @@ bool UserInterface::handleMenuItemPressed(const SEvent::SGUIEvent* ge) // && (ge->Caller->getID() <= m_file_recent_last_idx)) { // NOTE: ge->Caller->getID() is probably UIE_RECENTMENU now, but that is not to be used directly! cerr << "selected " << selected << std::endl; - if (std::find(this->recentIndices.begin(), this->recentIndices.end(), selected) != this->recentIndices.end()) { - // cerr << "parent callerID: " << callerID << endl; - // ^ commandID is the parent such as 1100 (or whatever UI_RECENTMENU is) + if (std::find(this->recentIndices.begin(), this->recentIndices.end(), commandID) != this->recentIndices.end()) { // ge->Caller->getText() // Don't do this. Caller is the parent! - // cerr << " commandID: " << commandID << std::endl; + cerr << "parent callerID: " << callerID << endl; + // ^ callerID is the parent such as 1100 (or whatever UI_RECENTMENU is) + cerr << " commandID: " << commandID << std::endl; + // ^ commandID is a menu id specified on creation + // such as starting from 1101 + // or from whatever UIC_FILE_RECENT_FIRST is--usually UI_RECENTMENU+1). // selectedItemID is a sequential number. - // commandID is a menu id specified on create such as starting from 1101 - // (or from whatever UIC_FILE_RECENT_FIRST is--usually UI_RECENTMENU+1) // std::wstring menuItemText = menu->getItemText(selected); - this->openRecent(selected); + this->openRecent(commandID, selected); } else { - cerr << "Unknown selected id: " << selected << " Text:" << Utility::toString(menu->getItemText(selected)) << endl; + cerr << "Unknown commandID: " << commandID << " Text:" << Utility::toString(menu->getItemText(selected)) << endl; + // ^ getItemText takes the index (NOT the commandID specified on creation) if (this->recentIndices.size() < 1) { cerr << "- recentIndices.size(): " << recentIndices.size() << endl; } @@ -421,6 +430,14 @@ bool UserInterface::handleMenuItemPressed(const SEvent::SGUIEvent* ge) exportMeshToHome("stl"); break; + case UIC_FILE_RELOAD_MESH: + m_Engine->reloadMesh(); + break; + + case UIC_FILE_RELOAD_TEXTURE: + m_Engine->reloadTexture(); + break; + case UIC_FILE_OPEN_TEXTURE: if (m_Engine->m_LoadedMesh != nullptr) { displayLoadTextureDialog(); @@ -871,9 +888,9 @@ void UserInterface::addRecentMenuItem(std::string path, bool addToEngine) if (!this->recent_initialized) { throw std::runtime_error("The UI is not ready in addRecentMenuItem."); } - std::cerr << "[addRecentMenuItem] " << path << "..." << std::flush; + std::cerr << "[addRecentMenuItem] " << path << "..." << std::endl; if (!this->hasRecent(path)) { - std::cerr << "adding since new..." << std::endl; + std::cerr << "* adding since new..." << std::endl; wstring path_ws = Utility::toWstring(path); if (this->uic_file_recent_next < UserInterface::UIC_FILE_RECENT_FIRST) { throw std::runtime_error("this->uic_file_recent_next is " @@ -884,11 +901,16 @@ void UserInterface::addRecentMenuItem(std::string path, bool addToEngine) // The first this->uic_file_recent_next is 1101 or whatever // UserInterface::UIC_FILE_RECENT_FIRST (usually UIC_FILE_RECENT+1) is. u32 newI = this->recentMenu->addItem(path_ws.c_str(), this->uic_file_recent_next); + std::cerr << "+this->recentMenu->addItem" + << " idx:" << newI + << " commandID:" << this->uic_file_recent_next + << std::endl; // IGUIContextMenu* menu = this->recentMenu->getSubMenu(newI); // NOTE: Caller would be the parent menu id on click! // newI is a sequential number starting at 1 which becomes the // selected item (See menu->getSelectedItem() in handleMenuItemPressed) - this->recentIndices.push_back(newI); + // this->recentIndices.push_back(newI); + this->recentIndices.push_back(this->uic_file_recent_next); this->uic_file_recent_next++; /* if (this->m_file_recent_first_idx < 0) { @@ -923,17 +945,69 @@ bool UserInterface::hasRecent(std::string path) if (!this->recent_initialized) { throw std::runtime_error("The UI is not ready in addRecent."); } - std::cerr << "* checking recent menu items for " << path << "..." << std::endl; + std::cerr << " [hasRecent]" << std::endl; + std::cerr << " * checking children..." << std::endl; + + // See http://irrlicht.sourceforge.net/docu/_i_g_u_i_element_8h_source.html#l00570 + // core::list< IGUIElement * > Children = this->getChildren(); + // ^ ‘class UserInterface’ has no member named ‘getChildren’ + // core::list< IGUIElement * > Children = this->recentMenu->getChildren(); + // ^ gets no results + // core::list< IGUIElement * > Children = this->menu->getChildren(); + // ^ only gets UIE_FILEMENU, UIE_PLAYBACKMENU, and UIE_VIEWMENU + + std::string thisItemStr = " "; + for (u32 i = 0; i < this->recentMenu->getItemCount(); i++) { + thisItemStr = Utility::toString((wstring)this->recentMenu->getItemText(i)); + // getItemText gets wchar_t* + // std::cerr << " * text:" << thisItemStr + // << std::endl; + if (thisItemStr == path) + return true; + } + return false; + // The commented section below is not valid since there are no children + // apparently, only items (inaccessible internals obtained by index). + /* + core::list< IGUIElement * > Children = this->recentMenu->getChildren(); + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + irr::gui::IGUIElement* child = *it; + std::cerr << " * text:" << Utility::toString((std::wstring)child->getText()) + << " parent:" << Utility::toString((std::wstring)child->getParent()->getText()) + << " id:" << Utility::toString(child->getID()) + << std::endl; + // - getText is a const wchar_t* + // - getParent is an IGUIElement* + // (*it)->Parent; + } + // ^ gets no results + std::cerr << " * checking recent menu items for " << path << "..." << std::endl; + for (std::vector::iterator uiIt = this->recentIndices.begin() ; uiIt != this->recentIndices.end(); ++uiIt) { - IGUIContextMenu* menu = this->recentMenu->getSubMenu(*uiIt); - if (menu != nullptr) { - std::cerr << " - " << *uiIt << ": " << Utility::toString(menu->getText()) << std::endl; - if (Utility::toString(menu->getText()) == path) { + // In the comments below, 1 is selected (idx) and 1101 is commandID. + // None of the commands work! An item is not an IGUI element apparently! + // IGUIContextMenu* child = this->recentMenu->getSubMenu(*uiIt); + // ^ null for 1 or 1101 + // irr::gui::IGUIElement* child = this->recentMenu->getElementFromId(*uiIt, true); + // ^ null for 1101 + // irr::gui::IGUIElement* child = this->menu->getElementFromId(*uiIt, true); + // ^ null for 1 or 1101 + // irr::gui::IGUIElement* child = this->recentMenu->getElementFromId(*uiIt, true); + // ^ null for 1 or 1101 + irr::gui::IGUIElement* child = this->getGUIEnvironment()->getRootGUIElement()->getElementFromId(1, true); + // ^ null for 1 or 1101 + // ^ cast to the specific IGUI... interface before use! + // ^ See + if (child != nullptr) { + std::cerr << " - " << *uiIt << " (1): " << Utility::toString(child->getText()) << std::endl; + if (Utility::toString(child->getText()) == path) { return true; } } else { - std::cerr << " - null at " << *uiIt << std::endl; + std::cerr << " - null at " << *uiIt << std::endl; std::string uiItMsg = std::to_string(*uiIt); // std::string uiItMsg = "recent_initialized) { @@ -970,6 +1045,7 @@ bool UserInterface::openRecent(s32 selectedItemID) // IGUIElement* submenu = this->menu->getSubMenu(commandID); // ^ There is no submenu for commandID (such as 1101) IGUIElement* submenu = this->menu->getSubMenu(selectedItemID); + // ^ requires the sequential selectedItemID (NOT commandID specified on create) if (submenu != nullptr) { std::wstring menuText = this->recentMenu->getItemText(selectedItemID); // std::string path = Utility::toString(submenu->getText()); @@ -978,7 +1054,7 @@ bool UserInterface::openRecent(s32 selectedItemID) cerr << "path: " << path << endl; cerr << "selectedItemID: " << selectedItemID << endl; cerr << "menuText: " << Utility::toString(menuText) << endl; - result = m_Engine->loadMesh(menuText); + result = m_Engine->loadMesh(menuText, true); // true to adjust recent menu order if (!result) { this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox( L"Load Mesh", L"The model is inaccessible or not in a compatible format."); @@ -1045,7 +1121,7 @@ bool UserInterface::OnEvent(const SEvent& event) result = m_Engine->loadScene(fileOpenDialog->getFileName()); } else { - result = m_Engine->loadMesh(fileOpenDialog->getFileName()); + result = m_Engine->loadMesh(fileOpenDialog->getFileName(), true); } if (result) { try { @@ -1181,7 +1257,7 @@ bool UserInterface::OnEvent(const SEvent& event) handled = false; break; case EGET_ELEMENT_HOVERED: - debug() << "hovered over " << callerID << "." << std::endl; + // debug() << "hovered over " << callerID << "." << std::endl; handled = false; break; case EGET_ELEMENT_LEFT: @@ -1205,6 +1281,10 @@ bool UserInterface::OnEvent(const SEvent& event) this->m_Engine->m_View->m_MouseUser = ""; handled = false; break; + case EGET_EDITBOX_MARKING_CHANGED: + this->m_Engine->m_View->m_MouseUser = "edit box"; + handled = false; + break; default: // EET_MOUSE_INPUT_EVENT EET_KEY_INPUT_EVENT EET_JOYSTICK_INPUT_EVENT cerr << "[UserInterface] (verbose message) event.GUIEvent.EventType " << ge->EventType << " (See EGET_* in irrlicht/IEventReciever.h) is not handled (event.EventType is EET_GUI_EVENT)." << std::endl; @@ -1221,7 +1301,11 @@ bool UserInterface::OnEvent(const SEvent& event) if (event.KeyInput.Key == irr::KEY_F5) { if (m_Engine->KeyIsDown[irr::KEY_LSHIFT] || m_Engine->KeyIsDown[irr::KEY_RSHIFT]) { - m_Engine->reloadTexture(); + bool result = m_Engine->reloadTexture(); + if (!result) { + this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox( + L"Reload Texture", L"The texture is inaccessible or not in a compatible format."); + } } else { if (m_Engine->m_LoadedMeshPath.length() > 0) { diff --git a/UserInterface.h b/UserInterface.h index 01ac6b2..b5c86da 100644 --- a/UserInterface.h +++ b/UserInterface.h @@ -11,7 +11,7 @@ class Engine; enum UserInterfaceElements { - UIE_FILEMENU = 1003, + UIE_FILEMENU = 1000, // This whole range (1100-1198) must stay free for generated submenus: UIE_RECENTMENU = 1100, @@ -44,7 +44,7 @@ enum UserInterfaceElements { }; enum UserInterfaceCommands { - UIC_FILE_OPEN = 1000, + UIC_FILE_OPEN = 1001, UIC_FILE_RECENT = 1100, // this whole range (1100-1198) must stay free for generated submenus UIC_FILE_RECENT_CLEAR = 1199, UIC_FILE_QUIT = 1002, @@ -56,6 +56,8 @@ enum UserInterfaceCommands { UIC_FILE_EXPORT_IRRMESH = 1008, UIC_FILE_EXPORT_OBJ = 1009, UIC_FILE_EXPORT_STL = 1010, + UIC_FILE_RELOAD_MESH = 1011, + UIC_FILE_RELOAD_TEXTURE = 1012, UIC_PLAYBACK_PREVIOUS = 2001, UIC_PLAYBACK_NEXT = 2002, UIC_PLAYBACK_SLOWER = 2003, @@ -114,6 +116,10 @@ public: irr::gui::IGUIStaticText* axisSizeStaticText; irr::gui::IGUIEditBox* axisSizeEditBox; irr::u32 fileRecentIdx; + irr::u32 fileRecentClearIdx; + irr::u32 playbackMenuIdx; + irr::u32 viewMenuIdx; + irr::u32 fileMenuIdx; std::vector recentIndices; irr::u32 viewTextureInterpolationIdx; irr::u32 viewWireframeIdx; @@ -135,7 +141,7 @@ public: void addRecentMenuItem(std::string path, bool addToEngine); void addRecentMenuItems(std::vector paths, bool addToEngine); bool hasRecent(std::string path); - bool openRecent(irr::s32 selectedItemID); + bool openRecent(irr::s32 commandID, irr::s32 selectedItemID); bool OnSelectMesh(); void setPlaybackText(irr::s32 id, const wchar_t* str); diff --git a/View.cpp b/View.cpp index 642ab96..8029d63 100644 --- a/View.cpp +++ b/View.cpp @@ -173,7 +173,10 @@ bool View::OnEvent(const SEvent& event) // Handle mouse event const SEvent::SMouseInput* mouseEvent = &(event.MouseInput); if (this->m_MouseUser != "") { - std::cerr << "[View] The mouse is being used by " << this->m_MouseUser << std::endl; + // std::cerr << "[View] The mouse is being used by " << this->m_MouseUser << std::endl; + // Do not allow dragging or scroll wheel movement (or anything else + // that may be implemented) to affect the view while the user is using + // a panel or dialog. return false; } if (mouseEvent->Event == EMIE_MMOUSE_PRESSED_DOWN) { diff --git a/build.sh b/build.sh index c9dc70a..5e509fb 100755 --- a/build.sh +++ b/build.sh @@ -22,20 +22,24 @@ done OPTION1="-O2" OPTION2= OPTION3= + +OUT_BIN=build/b3view + if [ "@$DEBUG" = "@true" ]; then OPTION1="-g" #OPTION2="-DQT_QML_DEBUG" OPTION3="-DDEBUG=true" - echo "* build:Debug" + OUT_BIN=build/debug/b3view + mkdir -p "build/debug" + echo "* build:Debug (`pwd`/$OUT_BIN)" else - echo "* build:Release" + echo "* build:Release (`pwd`/$OUT_BIN)" fi SYSTEM_INCDIR=$PREFIX/include #IRR_INCDIR= #IRR_LIBDIR= # FT2_INCDIR=$PREFIX/include/freetype2 FT2_INCDIR=$PREFIX/include/freetype2 -OUT_BIN=build/b3view #FT2_LIBDIR= OBJDIR="./build/tmp" diff --git a/main.cpp b/main.cpp index 3bb9251..663ad45 100644 --- a/main.cpp +++ b/main.cpp @@ -45,7 +45,7 @@ int main(int argc, char** argv) engine->pushOption(wstring(optionCS)); } else { - engine->loadMesh(wstring(optionCS)); + engine->loadMesh(wstring(optionCS), false); } free(optionCS); }