diff --git a/code/nel/include/nel/gui/event_descriptor.h b/code/nel/include/nel/gui/event_descriptor.h index 276979fdd..95bdad212 100644 --- a/code/nel/include/nel/gui/event_descriptor.h +++ b/code/nel/include/nel/gui/event_descriptor.h @@ -63,7 +63,7 @@ public: keystring, // a string has been sent. The string is a ucstring unknown, // uninitialized event }; - CEventDescriptorKey() : _KeyEvent(unknown) + CEventDescriptorKey() : _KeyEvent(unknown), _CtrlState(false), _ShiftState(false), _AltState(false), _Char(0) { _EventType = key; } @@ -105,6 +105,31 @@ public: { return _AltState; } + + // return true if key was pressed or held down at a time of this event + bool isShiftDown() + { + return (_KeyEvent == CEventDescriptorKey::keydown && (_Key == NLMISC::KeySHIFT || _ShiftState)) + || (_KeyEvent == CEventDescriptorKey::keyup && (_Key != NLMISC::KeySHIFT && _ShiftState)) + || (_KeyEvent == CEventDescriptorKey::keychar && _ShiftState); + } + + // return true if key was pressed or held down at a time of this event + bool isCtrlDown() + { + return (_KeyEvent == CEventDescriptorKey::keydown && (_Key == NLMISC::KeyCONTROL || _CtrlState)) + || (_KeyEvent == CEventDescriptorKey::keyup && (_Key != NLMISC::KeyCONTROL && _CtrlState)) + || (_KeyEvent == CEventDescriptorKey::keychar && _CtrlState); + } + + // return true if key was pressed or held down at a time of this event + bool isAltDown() + { + return (_KeyEvent == CEventDescriptorKey::keydown && (_Key == NLMISC::KeyMENU || _AltState)) + || (_KeyEvent == CEventDescriptorKey::keyup && (_Key != NLMISC::KeyMENU && _AltState)) + || (_KeyEvent == CEventDescriptorKey::keychar && _AltState); + } + // init from a CEventKey obj void init(const NLMISC::CEventKey &ev); diff --git a/code/nel/include/nel/gui/widget_manager.h b/code/nel/include/nel/gui/widget_manager.h index 773c3198b..fced74024 100644 --- a/code/nel/include/nel/gui/widget_manager.h +++ b/code/nel/include/nel/gui/widget_manager.h @@ -269,6 +269,14 @@ namespace NLGUI CViewPointerBase* getPointer(){ return _Pointer; } void setPointer( CViewPointerBase *pointer ){ _Pointer = pointer; } + // If > 0, snap window to others closer than distance + void setWindowSnapDistance(uint32 d) { _WindowSnapDistance = d; } + uint32 getWindowSnapDistance() const { return _WindowSnapDistance; } + + // If true, only snap when shift is held down + void setWindowSnapInvert(bool b) { _WindowSnapInvert = b; } + bool getWindowSnapInvert() const { return _WindowSnapInvert; } + /** * get the window under a spot * \param : X coord of the spot @@ -310,6 +318,9 @@ namespace NLGUI void drawOverExtendViewText(); + // Snap to closest visible window border if snapping is enabled + void snapIfClose(CInterfaceGroup *group); + // Internal : adjust a tooltip with respect to its parent. Returns the number of coordinate that were clamped // against the screen border uint adjustTooltipPosition( CCtrlBase *newCtrl, CInterfaceGroup *win, THotSpot ttParentRef, @@ -624,6 +635,9 @@ namespace NLGUI CEventDescriptorKey lastKeyEvent; + uint32 _WindowSnapDistance; + bool _WindowSnapInvert; + uint32 _ScreenH; uint32 _ScreenW; float _InterfaceScale; diff --git a/code/nel/src/gui/group_container.cpp b/code/nel/src/gui/group_container.cpp index b642a50b5..87fb59c38 100644 --- a/code/nel/src/gui/group_container.cpp +++ b/code/nel/src/gui/group_container.cpp @@ -819,6 +819,8 @@ namespace NLGUI _Parent->setX(x); _Parent->setY(y); + CWidgetManager::getInstance()->snapIfClose(_Parent); + // if some action handler to call when moving if(gc->getAHOnMovePtr()) { diff --git a/code/nel/src/gui/widget_manager.cpp b/code/nel/src/gui/widget_manager.cpp index 282465446..c0a6a4c85 100644 --- a/code/nel/src/gui/widget_manager.cpp +++ b/code/nel/src/gui/widget_manager.cpp @@ -1254,7 +1254,125 @@ namespace NLGUI } } + // ---------------------------------------------------------------------------- + void CWidgetManager::snapIfClose(CInterfaceGroup *group) + { + if (!group || _WindowSnapDistance == 0 || _WindowSnapInvert != lastKeyEvent.isShiftDown()) + return; + + uint hsnap = _WindowSnapDistance; + uint vsnap = _WindowSnapDistance; + + sint32 newX = group->getX(); + sint32 newY = group->getY(); + + // new coords for window without snap + // used to calculate distance from target + sint gLeft = newX; + sint gRight = newX + group->getWReal(); + sint gTop = newY; + sint gBottom = newY - group->getHReal(); + + // current window coords as if already snaped + // used to calculate target for snap + sint gLeftR = group->getXReal(); + sint gRightR = gLeftR + group->getWReal(); + sint gBottomR = group->getYReal(); + sint gTopR = gBottomR + group->getHReal(); + for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++) + { + CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup]; + if (!rMG.Group->getActive()) continue; + + for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0 ; nPriority--) + { + const std::list &rList = rMG.PrioritizedWindows[nPriority-1]; + std::list::const_reverse_iterator itw; + for (itw = rList.rbegin(); itw != rList.rend(); itw++) + { + CInterfaceGroup *pIG = *itw; + // do not snap to self, inactive, or not using mouse interaction + if (group == pIG || !(pIG->getActive() && pIG->getUseCursor())) + continue; + + // target + sint wLeft = pIG->getXReal(); + sint wRight = pIG->getXReal() + pIG->getWReal(); + sint wTop = pIG->getYReal() + pIG->getHReal(); + sint wBottom = pIG->getYReal(); + sint delta; + + if (gTopR >= wBottom && gBottomR <= wTop) + { + delta = abs(gRight - wLeft); + if (delta <= hsnap) + { + hsnap = delta; + newX = wLeft - group->getWReal(); + } + + delta = abs(gLeft - wRight); + if (delta <= hsnap) + { + hsnap = delta; + newX = wRight; + } + + delta = abs(gLeft - wLeft); + if (delta <= hsnap) + { + hsnap = delta; + newX = wLeft; + } + + delta = abs(gRight - wRight); + if (delta <= hsnap) + { + hsnap = delta; + newX = wRight - group->getWReal(); + } + } + + if (gLeftR <= wRight && gRightR >= wLeft) + { + delta = abs(gTop - wBottom); + if (delta <= vsnap) + { + vsnap = delta; + newY = wBottom; + } + + delta = abs(gBottom - wTop); + if (delta <= vsnap) + { + vsnap = delta; + newY = wTop + group->getHReal(); + } + + delta = abs(gTop - wTop); + if (delta <= vsnap) + { + vsnap = delta; + newY = wTop; + } + + delta = abs(gBottom - wBottom); + if (delta <= vsnap) + { + vsnap = delta; + newY = wBottom + group->getHReal(); + } + } + }//windows + }//priority + }//master group + + group->setX(newX); + group->setY(newY); + } + + // ---------------------------------------------------------------------------- uint CWidgetManager::adjustTooltipPosition( CCtrlBase *newCtrl, CInterfaceGroup *win, THotSpot ttParentRef, THotSpot ttPosRef, sint32 xParent, sint32 yParent, sint32 wParent, sint32 hParent ) @@ -3771,6 +3889,9 @@ namespace NLGUI setScreenWH(0, 0); _InterfaceScale = 1.0f; + _WindowSnapDistance = 10; + _WindowSnapInvert = false; + _GroupSelection = false; multiSelection = false; _WidgetCount = 0; diff --git a/code/ryzom/client/client_default.cfg b/code/ryzom/client/client_default.cfg index 501e0097d..7d134ad01 100644 --- a/code/ryzom/client/client_default.cfg +++ b/code/ryzom/client/client_default.cfg @@ -336,6 +336,9 @@ BilinearUI = 1; MaxMapScale = 2.0; R2EDMaxMapScale = 8.0; +WindowSnapInvert = 0; +WindowSnapDistance = 10; + ////////////////// // SOUND CONFIG // ////////////////// diff --git a/code/ryzom/client/src/client_cfg.cpp b/code/ryzom/client/src/client_cfg.cpp index a315a52a9..985f052db 100644 --- a/code/ryzom/client/src/client_cfg.cpp +++ b/code/ryzom/client/src/client_cfg.cpp @@ -316,6 +316,9 @@ CClientConfig::CClientConfig() InterfaceScale_step = 0.05; BilinearUI = true; + WindowSnapInvert = false; + WindowSnapDistance = 10; + VREnable = false; VRDisplayDevice = "Auto"; VRDisplayDeviceId = ""; @@ -866,6 +869,8 @@ void CClientConfig::setValues() READ_FLOAT_FV(InterfaceScale_step); clamp(ClientCfg.InterfaceScale, ClientCfg.InterfaceScale_min, ClientCfg.InterfaceScale_max); READ_BOOL_FV(BilinearUI); + READ_BOOL_FV(WindowSnapInvert); + READ_INT_FV(WindowSnapDistance); // 3D Driver varPtr = ClientCfg.ConfigFile.getVarPtr ("Driver3D"); if (varPtr) diff --git a/code/ryzom/client/src/client_cfg.h b/code/ryzom/client/src/client_cfg.h index 33d1d01e0..a5eff6883 100644 --- a/code/ryzom/client/src/client_cfg.h +++ b/code/ryzom/client/src/client_cfg.h @@ -157,6 +157,10 @@ struct CClientConfig float InterfaceScale_step; bool BilinearUI; + // Window snap + bool WindowSnapInvert; + uint32 WindowSnapDistance; + // VR bool VREnable; std::string VRDisplayDevice; diff --git a/code/ryzom/client/src/init.cpp b/code/ryzom/client/src/init.cpp index 2f6702e4d..1deacd146 100644 --- a/code/ryzom/client/src/init.cpp +++ b/code/ryzom/client/src/init.cpp @@ -1354,6 +1354,9 @@ void prelogInit() CViewRenderer::getInstance()->setInterfaceScale(1.0f, 1024, 768); CViewRenderer::getInstance()->setBilinearFiltering(ClientCfg.BilinearUI); + CWidgetManager::getInstance()->setWindowSnapInvert(ClientCfg.WindowSnapInvert); + CWidgetManager::getInstance()->setWindowSnapDistance(ClientCfg.WindowSnapDistance); + // Yoyo: initialize NOW the InputHandler for Event filtering. CInputHandlerManager *InputHandlerManager = CInputHandlerManager::getInstance(); InputHandlerManager->addToServer (&Driver->EventServer);