1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-20 07:23:51 +00:00

Drop MyGUI 3.4 requirement. Manage layer and widget focus manually.

This commit is contained in:
Mads Buvik Sandvei 2020-11-27 21:47:20 +01:00
parent 02c7e8ed2a
commit 259330ab14
10 changed files with 164 additions and 104 deletions

View file

@ -109,7 +109,7 @@ void MWBase::Environment::setVrMode(bool vrMode)
mVrMode = vrMode;
}
bool MWBase::Environment::getVrMode(void)
bool MWBase::Environment::getVrMode(void) const
{
return mVrMode;
}

View file

@ -79,7 +79,7 @@ namespace MWBase
void limitFrameRate(double dt) const;
void setVrMode(bool vrMode);
bool getVrMode(void);
bool getVrMode(void) const;
World *getWorld() const;

View file

@ -11,6 +11,9 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp"
#include "../mwvr/vrenvironment.hpp"
#include "../mwvr/vrgui.hpp"
namespace MWGui
{
@ -91,6 +94,9 @@ void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget)
w.second = nullptr;
if (widget == mCurrentFocus)
mCurrentFocus = nullptr;
if (MWBase::Environment::get().getVrMode())
MWVR::Environment::get().getGUIManager()->notifyWidgetUnlinked(widget);
}
void styleFocusedButton(MyGUI::Widget* w)
@ -169,6 +175,9 @@ void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *d
void KeyboardNavigation::setModalWindow(MyGUI::Widget *window)
{
mModalWindow = window;
if (MWBase::Environment::get().getVrMode())
MWVR::Environment::get().getGUIManager()->notifyModalWindow(window);
}
void KeyboardNavigation::setEnabled(bool enabled)

View file

@ -83,25 +83,6 @@ namespace MWGui
window->setCaptionWithReplacing(title);
}
void Layout::setLayerPick(bool pick)
{
#if MYGUI_VERSION >= MYGUI_DEFINE_VERSION(3,4,0)
MyGUI::ILayer* layer = mMainWidget->getLayer();
// MyGUI exposes pick on the implementations of ILayer only, but not ILayer itself.
auto* oLayer = layer->castType<MyGUI::OverlappedLayer>(false);
auto* sLayer = layer->castType<MyGUI::SharedLayer>(false);
if (oLayer)
oLayer->setPick(pick);
if (sLayer)
sLayer->setPick(pick);
#else
#ifdef USE_OPENXR
#error "MyGUI version 3.4.0 or greater required to build for VR"
#endif
throw std::logic_error("Not implemented");
#endif
}
MyGUI::Widget* Layout::getWidget(const std::string &_name)
{
for (MyGUI::Widget* widget : mListWindowRoot)

View file

@ -64,9 +64,6 @@ namespace MWGui
// NOTE: this assume that mMainWidget is of type Window.
void setTitle(const std::string& title);
/// \note Affects the layer, not just the widget.
void setLayerPick(bool pick);
MyGUI::Widget* mMainWidget;
protected:

View file

@ -25,6 +25,9 @@
#include "itemmodel.hpp"
#include "../mwvr/vrenvironment.hpp"
#include "../mwvr/vrgui.hpp"
namespace MWGui
{
std::string ToolTips::sSchoolNames[] = {"#{sSchoolAlteration}", "#{sSchoolConjuration}", "#{sSchoolDestruction}", "#{sSchoolIllusion}", "#{sSchoolMysticism}", "#{sSchoolRestoration}"};
@ -156,7 +159,11 @@ namespace MWGui
if (mRemainingDelay > 0)
return;
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget();
MyGUI::Widget* focus = nullptr;
if (MWBase::Environment::get().getVrMode())
focus = MWVR::Environment::get().getGUIManager()->focusWidget();
else
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget();
if (focus == 0)
return;

View file

@ -1781,7 +1781,7 @@ namespace MWGui
#ifdef USE_OPENXR
auto* vrGuiManager = MWVR::Environment::get().getGUIManager();
vrGuiManager->insertLayer(mVideoBackground->getLayer()->getName());
vrGuiManager->insertLayer(mVideoBackground->getLayer());
#endif
bool cursorWasVisible = mCursorVisible;
@ -1834,7 +1834,7 @@ namespace MWGui
updateVisible();
#ifdef USE_OPENXR
vrGuiManager->removeLayer(mVideoBackground->getLayer()->getName());
vrGuiManager->removeLayer(mVideoBackground->getLayer());
#endif
mVideoBackground->setVisible(false);
mVideoEnabled = false;

View file

@ -67,6 +67,9 @@ namespace MWInput
void MouseManager::mouseMoved(const SDLUtil::MouseMotionEvent &arg)
{
if (MWBase::Environment::get().getVrMode())
return;
mBindingsManager->mouseMoved(arg);
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
@ -236,6 +239,8 @@ namespace MWInput
void MouseManager::injectMouseMove(float xMove, float yMove, float mouseWheelMove)
{
if (MWBase::Environment::get().getVrMode())
return;
mGuiCursorX += xMove;
mGuiCursorY += yMove;
mMouseWheel += mouseWheelMove;

View file

@ -40,6 +40,7 @@
#include <MyGUI_InputManager.h>
#include <MyGUI_WidgetManager.h>
#include <MyGUI_Window.h>
#include <MyGUI_Button.h>
namespace osg
{
@ -146,11 +147,12 @@ namespace MWVR
VRGUILayer::VRGUILayer(
osg::ref_ptr<osg::Group> geometryRoot,
osg::ref_ptr<osg::Group> cameraRoot,
std::string layerName,
MyGUI::ILayer* layer,
LayerConfig config,
VRGUIManager* parent)
: mConfig(config)
, mLayerName(layerName)
, mLayerName(layer->getName())
, mMyGUILayer(layer)
, mGeometryRoot(geometryRoot)
, mCameraRoot(cameraRoot)
{
@ -468,7 +470,8 @@ namespace MWVR
osg::Vec2(1,1),
sizingMode,
TrackingMode::Menu,
extraLayers
extraLayers,
false
};
}
LayerConfig gDefaultConfig = createDefaultConfig(1);
@ -493,7 +496,8 @@ namespace MWVR
osg::Vec2(1,1),
SizingMode::Auto,
TrackingMode::HudLeftHand,
""
"",
true
};
static const float sSideBySideRadius = 1.f;
@ -512,7 +516,8 @@ namespace MWVR
osg::Vec2(0.70f, 0.70f),
SizingMode::Fixed,
gDefaultConfig.trackingMode,
""
"",
false
};
};
@ -536,7 +541,8 @@ namespace MWVR
gDefaultConfig.myGUIViewSize,
SizingMode::Auto,
TrackingMode::HudLeftHand,
""
"",
false
};
LayerConfig gPopupConfig = LayerConfig
@ -552,7 +558,8 @@ namespace MWVR
gDefaultConfig.myGUIViewSize,
SizingMode::Auto,
TrackingMode::HudRightHand,
""
"",
false
};
@ -601,9 +608,10 @@ namespace MWVR
mSideBySideLayers[i]->setAngle(low + static_cast<float>(i) * sSideBySideAzimuthInterval);
}
void VRGUIManager::insertLayer(const std::string& name)
void VRGUIManager::insertLayer(MyGUI::ILayer* layer)
{
LayerConfig config = gDefaultConfig;
const auto& name = layer->getName();
auto configIt = gLayerConfigs.find(name);
if (configIt != gLayerConfigs.end())
{
@ -614,25 +622,25 @@ namespace MWVR
Log(Debug::Warning) << "Layer " << name << " has no configuration, using default";
}
auto layer = std::shared_ptr<VRGUILayer>(new VRGUILayer(
auto vrlayer = std::shared_ptr<VRGUILayer>(new VRGUILayer(
mGUIGeometriesRoot,
mGUICamerasRoot,
name,
layer,
config,
this
));
mLayers[name] = layer;
mLayers[name] = vrlayer;
layer->mGeometry->setUserData(new VRGUILayerUserData(mLayers[name]));
vrlayer->mGeometry->setUserData(new VRGUILayerUserData(mLayers[name]));
if (config.sideBySide)
{
mSideBySideLayers.push_back(layer);
mSideBySideLayers.push_back(vrlayer);
updateSideBySideLayers();
}
if (config.trackingMode == TrackingMode::Menu)
layer->updateTracking(mHeadPose);
vrlayer->updateTracking(mHeadPose);
}
void VRGUIManager::insertWidget(MWGui::Layout* widget)
@ -643,32 +651,24 @@ namespace MWVR
auto it = mLayers.find(name);
if (it == mLayers.end())
{
insertLayer(name);
insertLayer(layer);
it = mLayers.find(name);
if (it == mLayers.end())
{
Log(Debug::Error) << "Failed to insert layer " << name;
return;
}
}
it->second->insertWidget(widget);
if (it->second.get() != mFocusLayer)
widget->setLayerPick(false);
}
void VRGUIManager::removeLayer(const std::string& name)
void VRGUIManager::removeLayer(MyGUI::ILayer* layer)
{
auto it = mLayers.find(name);
auto it = mLayers.find(layer->getName());
if (it == mLayers.end())
return;
auto layer = it->second;
auto vrlayer = it->second;
for (auto it2 = mSideBySideLayers.begin(); it2 < mSideBySideLayers.end(); it2++)
{
if (*it2 == layer)
if (*it2 == vrlayer)
{
mSideBySideLayers.erase(it2);
updateSideBySideLayers();
@ -684,9 +684,8 @@ namespace MWVR
void VRGUIManager::removeWidget(MWGui::Layout* widget)
{
auto* layer = widget->mMainWidget->getLayer();
auto name = layer->getName();
auto it = mLayers.find(name);
auto it = mLayers.find(layer->getName());
if (it == mLayers.end())
{
//Log(Debug::Warning) << "Tried to remove widget from nonexistent layer " << name;
@ -696,7 +695,7 @@ namespace MWVR
it->second->removeWidget(widget);
if (it->second->widgetCount() == 0)
{
removeLayer(name);
removeLayer(layer);
}
}
@ -705,14 +704,12 @@ namespace MWVR
auto* layer = widget->mMainWidget->getLayer();
auto name = layer->getName();
Log(Debug::Verbose) << "setVisible (" << name << "): " << visible;
if (layerBlacklist.find(name) != layerBlacklist.end())
{
Log(Debug::Verbose) << "Blacklisted";
// Never pick an invisible layer
widget->setLayerPick(false);
Log(Debug::Verbose) << "setVisible (" << name << "): ignored";
return;
}
Log(Debug::Verbose) << "setVisible (" << name << "): " << visible;
if (visible)
insertWidget(widget);
@ -807,46 +804,111 @@ namespace MWVR
if (layer == mFocusLayer)
return;
if (mFocusLayer)
{
mFocusLayer->mWidgets.front()->setLayerPick(false);
}
setFocusWidget(nullptr);
mFocusLayer = layer;
if (mFocusLayer)
{
Log(Debug::Verbose) << "Set focus layer to " << mFocusLayer->mWidgets.front()->mMainWidget->getLayer()->getName();
mFocusLayer->mWidgets.front()->setLayerPick(true);
}
else
{
Log(Debug::Verbose) << "Set focus layer to null";
}
}
void VRGUIManager::setFocusWidget(MyGUI::Widget* widget)
{
// TODO: This relies on MyGUI internal functions and may break on any future version.
if (widget == mFocusWidget)
return;
if (mFocusWidget)
// TODO: This relies on MyGUI internal functions and may break on any future version.
if (validateFocusWidget())
mFocusWidget->_riseMouseLostFocus(widget);
if (widget)
widget->_riseMouseSetFocus(mFocusWidget);
mFocusWidget = widget;
}
bool VRGUIManager::injectMouseClick(bool onPress)
// MyGUI may delete the focusWidget.
// Call this and check the result before dereferencing mFocusWidget
bool VRGUIManager::validateFocusWidget()
{
// TODO: This relies on MyGUI internal functions and may break on any future version.
if (mFocusWidget)
{
if(onPress)
mFocusWidget->_riseMouseButtonClick();
auto* cursorWidget = widgetFromGuiCursor(mGuiCursor.x(), mGuiCursor.y());
// If the focus widget is no longer seen at the coordinate it was last seen
// it may have been deleted by mygui.
// In theory, notifyWidgetUnlinked() should catch all cases but doesn't.
if (cursorWidget != mFocusWidget)
{
mFocusWidget = nullptr;
return false;
}
return true;
}
return false;
}
bool VRGUIManager::focusIsModalWindow()
{
if (mFocusLayer)
for (auto* window : mFocusLayer->mWidgets)
if (mModalWindow == window->mMainWidget)
return true;
return false;
}
MyGUI::Widget* VRGUIManager::widgetFromGuiCursor(int x, int y)
{
if (mFocusLayer)
{
if (
mFocusLayer->mConfig.ignoreModality
|| !mModalWindow
|| focusIsModalWindow()
)
return static_cast<MyGUI::Widget*>(mFocusLayer->mMyGUILayer->getLayerItemByPoint(x, y));
}
return nullptr;
}
void VRGUIManager::updateGuiCursor(int x, int y)
{
setFocusWidget(widgetFromGuiCursor(x, y));
mGuiCursor.x() = x;
mGuiCursor.y() = y;
}
bool VRGUIManager::injectMouseClick(bool onPress)
{
// TODO: This relies on MyGUI internal functions and may break on any future version.
if (validateFocusWidget())
{
if (onPress)
{
mFocusWidget->_riseMouseButtonPressed(mGuiCursor.x(), mGuiCursor.y(), MyGUI::MouseButton::Left);
MyGUI::Button* b = mFocusWidget->castType<MyGUI::Button>(false);
if (b && b->getEnabled())
{
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
}
}
else
{
mFocusWidget->_riseMouseButtonReleased(mGuiCursor.x(), mGuiCursor.y(), MyGUI::MouseButton::Left);
mFocusWidget->_riseMouseButtonClick();
}
return true;
}
return false;
}
void VRGUIManager::notifyWidgetUnlinked(MyGUI::Widget* widget)
{
if (widget == mFocusWidget)
{
mFocusWidget = nullptr;
}
}
void VRGUIManager::notifyModalWindow(MyGUI::Widget* window)
{
mModalWindow = window;
}
void VRGUIManager::computeGuiCursor(osg::Vec3 hitPoint)
{
float x = 0;
@ -866,26 +928,8 @@ namespace MWVR
y = bottom - height * y;
}
mGuiCursor.x() = (int)x;
mGuiCursor.y() = (int)y;
MyGUI::InputManager::getInstance().injectMouseMove((int)x, (int)y, 0);
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
// The virtual keyboard must be interactive regardless of modals
// This could be generalized with another config entry, but i don't think any other
// widgets/layers need it so i'm hardcoding it for the VirtualKeyboard for now.
if (
mFocusLayer
&& mFocusLayer->mLayerName == "VirtualKeyboard"
&& MyGUI::InputManager::getInstance().isModalAny())
{
auto* widget = MyGUI::LayerManager::getInstance().getWidgetFromPoint((int)x, (int)y);
setFocusWidget(widget);
}
else
setFocusWidget(nullptr);
updateGuiCursor((int)x, (int)y);
}
}

View file

@ -1,5 +1,5 @@
#ifndef OPENXR_MENU_HPP
#define OPENXR_MENU_HPP
#ifndef VRGUI_HPP
#define VRGUI_HPP
#include <map>
#include <set>
@ -25,6 +25,7 @@ namespace MWGui
{
class Layout;
class WindowBase;
class ILayer;
}
struct XrCompositionLayerQuad;
@ -63,6 +64,7 @@ namespace MWVR
SizingMode sizingMode; //!< How to size the layer
TrackingMode trackingMode; //!< Tracking mode
std::string extraLayers; //!< Additional layers to draw (list separated by any non-alphabetic)
bool ignoreModality; //!< Layer input should be enabled even if another modal window is active
bool operator<(const LayerConfig& rhs) const { return priority < rhs.priority; }
};
@ -78,7 +80,7 @@ namespace MWVR
VRGUILayer(
osg::ref_ptr<osg::Group> geometryRoot,
osg::ref_ptr<osg::Group> cameraRoot,
std::string layerName,
MyGUI::ILayer* layer,
LayerConfig config,
VRGUIManager* parent);
~VRGUILayer();
@ -102,6 +104,7 @@ namespace MWVR
Pose mTrackedPose{};
LayerConfig mConfig;
std::string mLayerName;
MyGUI::ILayer* mMyGUILayer;
std::vector<MWGui::Layout*> mWidgets;
osg::ref_ptr<osg::Group> mGeometryRoot;
osg::ref_ptr<osg::Geometry> mGeometry{ new osg::Geometry };
@ -139,10 +142,10 @@ namespace MWVR
void setVisible(MWGui::Layout*, bool visible);
/// Insert the given layer quad if it isn't already
void insertLayer(const std::string& name);
void insertLayer(MyGUI::ILayer* layer);
/// Remove the given layer quad
void removeLayer(const std::string& name);
void removeLayer(MyGUI::ILayer* layer);
/// Update layer quads based on current camera
void updateTracking(void);
@ -162,6 +165,15 @@ namespace MWVR
/// Inject mouse click if applicable
bool injectMouseClick(bool onPress);
/// Notify VRGUIManager that a widget has been unlinked
void notifyWidgetUnlinked(MyGUI::Widget* widget);
/// Notify VRGUIManager that a window is modal
void notifyModalWindow(MyGUI::Widget* window);
/// Currently focus widget according to VR
MyGUI::Widget* focusWidget() { return mFocusWidget; }
private:
void computeGuiCursor(osg::Vec3 hitPoint);
void updateSideBySideLayers();
@ -169,6 +181,10 @@ namespace MWVR
void removeWidget(MWGui::Layout* widget);
void setFocusLayer(VRGUILayer* layer);
void setFocusWidget(MyGUI::Widget* widget);
bool validateFocusWidget();
bool focusIsModalWindow();
MyGUI::Widget* widgetFromGuiCursor(int x, int y);
void updateGuiCursor(int x, int y);
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
@ -183,6 +199,7 @@ namespace MWVR
osg::Vec2i mGuiCursor{};
VRGUILayer* mFocusLayer{ nullptr };
MyGUI::Widget* mFocusWidget{ nullptr };
MyGUI::Widget* mModalWindow{ nullptr };
osg::observer_ptr<osg::Camera> mCamera{ nullptr };
};
}