diff --git a/code/nel/include/nel/gui/ctrl_text_button.h b/code/nel/include/nel/gui/ctrl_text_button.h index 183b6a65e..d2b49ffa9 100644 --- a/code/nel/include/nel/gui/ctrl_text_button.h +++ b/code/nel/include/nel/gui/ctrl_text_button.h @@ -126,6 +126,7 @@ namespace NLGUI void onRemoved(); void onWidgetDeleted( CInterfaceElement *e ); + void moveBy( sint32 x, sint32 y ); protected: diff --git a/code/nel/include/nel/gui/editor_selection_watcher.h b/code/nel/include/nel/gui/editor_selection_watcher.h index 415f4f9db..7e262bdf1 100644 --- a/code/nel/include/nel/gui/editor_selection_watcher.h +++ b/code/nel/include/nel/gui/editor_selection_watcher.h @@ -15,6 +15,7 @@ // along with this program. If not, see . #include +#include namespace NLGUI { @@ -24,7 +25,7 @@ namespace NLGUI public: /// Notifies the watcher about the change - virtual void selectionChanged( std::string &newSelection ) = 0; + virtual void selectionChanged() = 0; }; } diff --git a/code/nel/include/nel/gui/interface_element.h b/code/nel/include/nel/gui/interface_element.h index db7a499c8..0be4c02e3 100644 --- a/code/nel/include/nel/gui/interface_element.h +++ b/code/nel/include/nel/gui/interface_element.h @@ -508,7 +508,24 @@ namespace NLGUI /// Called when the widget is deleted, /// so other widgets in the group can check if it belongs to them - virtual void onWidgetDeleted( CInterfaceElement *e ){} + virtual void onWidgetDeleted( CInterfaceElement *e ); + + /// Move the element by x in the X direction and y in the Y direction + // Uses real coordinates + virtual void moveBy( sint32 x, sint32 y ) + { + _XReal += x; + _YReal += y; + } + + /// Retrieves the coordinates of the specified hotspot + void getHSCoords( const THotSpot &hs, sint32 &x, sint32 &y ) const; + + /// Tells which hotspot is the closest to the specified element + void getClosestHotSpot( const CInterfaceElement *other, THotSpot &hs ); + + /// Aligns the element to the other element specified + void alignTo( CInterfaceElement *other ); protected: diff --git a/code/nel/include/nel/gui/widget_addition_watcher.h b/code/nel/include/nel/gui/interface_factory.h similarity index 81% rename from code/nel/include/nel/gui/widget_addition_watcher.h rename to code/nel/include/nel/gui/interface_factory.h index a2717e398..bd7f8352a 100644 --- a/code/nel/include/nel/gui/widget_addition_watcher.h +++ b/code/nel/include/nel/gui/interface_factory.h @@ -14,19 +14,22 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -#ifndef WIDGET_ADD_WATCHER -#define WIDGET_ADD_WATCHER +#ifndef IFACE_FACTORY +#define IFACE_FACTORY #include namespace NLGUI { - class IWidgetAdditionWatcher + class CViewBase; + + /// Simple interface element ( widget ) factory + class CInterfaceFactory { public: - virtual void widgetAdded( const std::string &name ) = 0; + static CViewBase* createClass( const std::string &name ); }; } -#endif +#endif diff --git a/code/nel/include/nel/gui/interface_group.h b/code/nel/include/nel/gui/interface_group.h index ff0efac3b..b9efd3357 100644 --- a/code/nel/include/nel/gui/interface_group.h +++ b/code/nel/include/nel/gui/interface_group.h @@ -57,6 +57,7 @@ namespace NLGUI CInterfaceElement* findFromShortId(const std::string &id); /// Dynamic creation + virtual void addElement (CInterfaceElement *child, sint eltOrder = -1 ); virtual void addView (CViewBase *child , sint eltOrder = -1); virtual void addCtrl (CCtrlBase *child, sint eltOrder = -1); virtual void addGroup (CInterfaceGroup *child, sint eltOrder = -1); @@ -327,6 +328,17 @@ namespace NLGUI void onWidgetDeleted( CInterfaceElement *e ); + void moveBy( sint32 x, sint32 y ); + + // Blows up the group, moves it's children to it's parent + bool explode(); + + /// Adjusts the group's size so that all elements are fully inside the borders + void spanElements(); + + /// Aligns the elements - used for forming groups + void alignElements(); + protected: void makeNewClip (sint32 &oldClipX, sint32 &oldClipY, sint32 &oldClipW, sint32 &oldClipH); diff --git a/code/nel/include/nel/gui/view_text.h b/code/nel/include/nel/gui/view_text.h index a14713dcc..d4377f38e 100644 --- a/code/nel/include/nel/gui/view_text.h +++ b/code/nel/include/nel/gui/view_text.h @@ -204,7 +204,11 @@ namespace NLGUI REFLECT_EXPORT_END - virtual void serial(NLMISC::IStream &f); + virtual void serial(NLMISC::IStream &f); + + // Sets the parent element + // See the comment at the field + void setParentElm( CInterfaceElement *parent ){ _ParentElm = parent; } protected: std::string _HardtextFormat; @@ -382,6 +386,9 @@ namespace NLGUI /// Dynamic tooltips std::vector _Tooltips; + // Parent element is the element where this text belongs to + // For example: text button + CInterfaceElement *_ParentElm; private: void setup (); diff --git a/code/nel/include/nel/gui/widget_manager.h b/code/nel/include/nel/gui/widget_manager.h index 5d2468e7a..d722a9165 100644 --- a/code/nel/include/nel/gui/widget_manager.h +++ b/code/nel/include/nel/gui/widget_manager.h @@ -75,6 +75,16 @@ namespace NLGUI virtual void process() = 0; }; + // Interface for event handlers that can be called when widgets are added or moved + class IWidgetWatcher + { + public: + IWidgetWatcher(){} + virtual ~IWidgetWatcher(){} + virtual void onWidgetAdded( const std::string &name ) = 0; + virtual void onWidgetMoved( const std::string &oldid, const std::string &newid ) = 0; + }; + /// Frame render times struct SInterfaceTimes { @@ -493,17 +503,31 @@ namespace NLGUI IParser* getParser() const{ return parser; } - std::string& getCurrentEditorSelection(){ return currentEditorSelection; } - void setCurrentEditorSelection( const std::string &name ); + /// Retrieves the Id of the currently selected widgets + void getEditorSelection( std::vector< std::string > &selection ); + + /// Adds the widget with the specified Id to the selected widgets + void selectWidget( const std::string &name ); + + /// Clears the selection + void clearEditorSelection(); + void notifySelectionWatchers(); void registerSelectionWatcher( IEditorSelectionWatcher *watcher ); void unregisterSelectionWatcher( IEditorSelectionWatcher *watcher ); - - void notifyAdditionWatchers( const std::string &widgetName ); - void registerAdditionWatcher( IWidgetAdditionWatcher *watcher ); - void unregisterAdditionWatcher( IWidgetAdditionWatcher *watcher ); + + + void onWidgetAdded( const std::string &id ); + void onWidgetMoved( const std::string &oldid, const std::string &newid ); + void registerWidgetWatcher( IWidgetWatcher *watcher ); + void unregisterWidgetWatcher( IWidgetWatcher *watcher ); CInterfaceElement* addWidgetToGroup( std::string &group, std::string &widgetClass, std::string &widgetName ); + + void setGroupSelection( bool b ){ _GroupSelection = b; } + bool groupSelection(); + bool unGroupSelection(); + void setMultiSelection( bool b ){ multiSelection = b; } private: CWidgetManager(); @@ -532,7 +556,7 @@ namespace NLGUI NLMISC::CRefPtr< CViewBase > _CapturedView; - NLMISC::CRefPtr< CInterfaceElement > draggedElement; + NLMISC::CRefPtr< CInterfaceElement > draggedElement; // the element that we're currently dragging bool startDragging(); void stopDragging(); @@ -594,10 +618,12 @@ namespace NLGUI std::vector< INewScreenSizeHandler* > newScreenSizeHandlers; std::vector< IOnWidgetsDrawnHandler* > onWidgetsDrawnHandlers; std::vector< IEditorSelectionWatcher* > selectionWatchers; - std::vector< IWidgetAdditionWatcher* > additionWatchers; + std::vector< IWidgetWatcher* > widgetWatchers; - - std::string currentEditorSelection; + std::vector< std::string > editorSelection; + bool _GroupSelection; + bool multiSelection; + uint32 _WidgetCount; }; } diff --git a/code/nel/src/gui/ctrl_text_button.cpp b/code/nel/src/gui/ctrl_text_button.cpp index d3a0f6765..cdf9ea0d2 100644 --- a/code/nel/src/gui/ctrl_text_button.cpp +++ b/code/nel/src/gui/ctrl_text_button.cpp @@ -23,6 +23,7 @@ #include "nel/gui/group_container_base.h" #include "nel/gui/lua_ihm.h" #include "nel/gui/widget_manager.h" +#include "nel/gui/interface_factory.h" #include "nel/misc/i18n.h" using namespace std; @@ -66,8 +67,6 @@ namespace NLGUI { if( _ViewText != NULL ) { - if( _Parent != NULL ) - _Parent->delView( _ViewText, true ); delete _ViewText; _ViewText = NULL; } @@ -569,6 +568,7 @@ namespace NLGUI ((CViewTextID*)_ViewText)->parseTextIdOptions(cur); // Same RenderLayer as us. _ViewText->setRenderLayer(getRenderLayer()); + _ViewText->setParentElm(this); // Parse the hardText (if not text id) if(!_IsViewTextId) { @@ -863,6 +863,8 @@ namespace NLGUI } if(getFrozen() && getFrozenHalfTone()) _ViewText->setAlpha(_ViewText->getAlpha()>>2); + + _ViewText->draw(); } } @@ -873,6 +875,9 @@ namespace NLGUI // Should have been setuped with addCtrl nlassert(_Setuped); + if( _Name == "==MARKED==" ) + bool marked = true; + // Compute Size according to bitmap and Text. if (!(_SizeRef & 1)) { @@ -886,6 +891,8 @@ namespace NLGUI } CViewBase::updateCoords(); + + _ViewText->updateCoords(); } // *************************************************************************** @@ -901,7 +908,7 @@ namespace NLGUI if( _ViewText == NULL ) { - CViewBase *v = CWidgetManager::getInstance()->getParser()->createClass( "text" ); + CViewBase *v = CInterfaceFactory::createClass( "text" ); nlassert( v != NULL ); _ViewText = dynamic_cast< CViewText* >( v ); _ViewText->setId( _Id + "_text" ); @@ -910,15 +917,13 @@ namespace NLGUI } // setup the viewText and add to parent - _ViewText->setParent (getParent()); + _ViewText->setParentElm (this); _ViewText->setParentPos (this); _ViewText->setParentPosRef (_TextParentPosRef); _ViewText->setPosRef (_TextPosRef); _ViewText->setActive(_Active); _ViewText->setX(_TextX); _ViewText->setY(_TextY); - - getParent()->addView(_ViewText); } // *************************************************************************** @@ -1007,17 +1012,18 @@ namespace NLGUI // *************************************************************************** void CCtrlTextButton::onRemoved() { - if( _ViewText != NULL ) - { - if( _Parent != NULL ) - _Parent->delView( _ViewText, true ); - } } void CCtrlTextButton::onWidgetDeleted( CInterfaceElement *e ) { - if( e == _ViewText ) - _ViewText = NULL; + } + + void CCtrlTextButton::moveBy( sint32 x, sint32 y ) + { + CInterfaceElement::moveBy( x, y ); + + if( _ViewText != NULL ) + _ViewText->updateCoords(); } } diff --git a/code/nel/src/gui/group_editbox.cpp b/code/nel/src/gui/group_editbox.cpp index c18c69134..ba65a07c4 100644 --- a/code/nel/src/gui/group_editbox.cpp +++ b/code/nel/src/gui/group_editbox.cpp @@ -27,6 +27,7 @@ #include "nel/gui/widget_manager.h" #include "nel/gui/view_renderer.h" #include "nel/gui/db_manager.h" +#include "nel/gui/interface_factory.h" #include using namespace std; @@ -1543,7 +1544,7 @@ namespace NLGUI if( editorMode ) { nlwarning( "Trying to create a new 'edit_text' for %s", getId().c_str() ); - _ViewText = dynamic_cast< CViewText* >( CWidgetManager::getInstance()->getParser()->createClass( "text" ) ); + _ViewText = dynamic_cast< CViewText* >( CInterfaceFactory::createClass( "text" ) ); if( _ViewText != NULL ) { _ViewText->setParent( this ); diff --git a/code/nel/src/gui/interface_element.cpp b/code/nel/src/gui/interface_element.cpp index 0225d2797..c9b480516 100644 --- a/code/nel/src/gui/interface_element.cpp +++ b/code/nel/src/gui/interface_element.cpp @@ -226,13 +226,13 @@ namespace NLGUI else if( name == "posref" ) { - convertHotSpot( value.c_str() ); + _PosRef = convertHotSpot( value.c_str() ); return; } else if( name == "parentposref" ) { - convertHotSpot( value.c_str() ); + _ParentPosRef = convertHotSpot( value.c_str() ); } else if( name == "sizeref" ) @@ -1594,6 +1594,105 @@ namespace NLGUI } } + void CInterfaceElement::getHSCoords( const THotSpot &hs, sint32 &x, sint32 &y ) const + { + x = _XReal; + y = _YReal; + + if( ( hs & Hotspot_Mx ) != 0 ) + y += _HReal / 2; + else + if( ( hs & Hotspot_Tx ) != 0 ) + y += _HReal; + + + if( ( hs & Hotspot_xM ) != 0 ) + x += _WReal / 2; + else + if( ( hs & Hotspot_xR ) != 0 ) + x += _WReal; + } + + void CInterfaceElement::getClosestHotSpot( const CInterfaceElement *other, THotSpot &hs ) + { + /// Iterate over the following hotspots, calculate the distance and store the closest + + + static THotSpot hslist[] = + { + Hotspot_BL, + Hotspot_BR, + Hotspot_MM, + Hotspot_TL, + Hotspot_TR + }; + + int c = sizeof( hslist ) / sizeof( THotSpot ); + + int x,y,ox,oy,vx,vy; + float d; + float closestd = 9999999.0f; + THotSpot closestHS = Hotspot_TR; + + for( int i = 0; i < c; i++ ) + { + other->getHSCoords( hslist[ i ], ox, oy ); + getHSCoords( hslist[ i ], x, y ); + + // Make a vector between the two hotspots + vx = x - ox; + vy = y - oy; + + // Calculate length + d = sqrt( pow( vx, 2.0f ) + pow( vy, 2.0f ) ); + + // If these hotspots are the closest, store the hotspot + if( d < closestd ) + { + closestd = d; + closestHS = hslist[ i ]; + } + } + + hs = closestHS; + } + + void CInterfaceElement::alignTo( CInterfaceElement *other ) + { + if( other == this ) + return; + + // Check which hotspot is the closest + THotSpot hs; + other->getClosestHotSpot( this, hs ); + + // Get the hotspot coordinates + sint32 x, y, ox, oy; + getHSCoords( hs, x, y ); + other->getHSCoords( hs, ox, oy ); + + // Calculate the difference between the hotspot we found and our current position, + sint32 dx = ox - x; + sint32 dy = oy - y; + + // This difference is our offset, so we remain in the same position + setX( -1 * dx ); + setY( -1 * dy ); + + setPosRef( hs ); + setParentPosRef( hs ); + + invalidateCoords(); + } + + void CInterfaceElement::onWidgetDeleted( CInterfaceElement *e ) + { + if( e == getParentPos() ) + setParentPos( NULL ); + if( e == getParentSize() ) + setParentSize( NULL ); + } + CStringMapper* CStringShared::_UIStringMapper = NULL; diff --git a/code/nel/src/gui/interface_factory.cpp b/code/nel/src/gui/interface_factory.cpp new file mode 100644 index 000000000..ec914baa6 --- /dev/null +++ b/code/nel/src/gui/interface_factory.cpp @@ -0,0 +1,29 @@ +// Ryzom - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "nel/gui/interface_factory.h" +#include "nel/gui/view_base.h" +#include "nel/misc/factory.h" + +namespace NLGUI +{ + CViewBase* CInterfaceFactory::createClass( const std::string &name ) + { + return NLMISC_GET_FACTORY( CViewBase, std::string ).createObject( std::string( name ) , CViewBase::TCtorParam() ); + } +} + + diff --git a/code/nel/src/gui/interface_group.cpp b/code/nel/src/gui/interface_group.cpp index 4d37eda1c..29ad75f8c 100644 --- a/code/nel/src/gui/interface_group.cpp +++ b/code/nel/src/gui/interface_group.cpp @@ -911,6 +911,31 @@ namespace NLGUI } } + // ------------------------------------------------------------------------------------------------ + void CInterfaceGroup::addElement (CInterfaceElement *child, sint eltOrder /*= -1*/) + { + if (!child) + { + nlwarning(" : tried to add a NULL view"); + return; + } + + if( child->isGroup() ) + { + addGroup( static_cast< CInterfaceGroup* >( child ), eltOrder ); + } + else + if( child->isCtrl() ) + { + addCtrl( static_cast< CCtrlBase* >( child ), eltOrder ); + } + else + if( child->isView() ) + { + addView( static_cast< CViewBase* >( child ), eltOrder ); + } + } + // ------------------------------------------------------------------------------------------------ void CInterfaceGroup::addView (CViewBase *child, sint eltOrder /*= -1*/) { @@ -1312,6 +1337,11 @@ namespace NLGUI for (ite = _EltOrder.begin() ; ite != _EltOrder.end(); ite++) { CViewBase *pVB = *ite; + if( pVB->getName() == "=MARKED=" ) + { + nlinfo( "=MARKED=" ); + } + if (pVB->getActive()) pVB->draw(); } @@ -2514,5 +2544,101 @@ namespace NLGUI for( std::vector< CInterfaceGroup* >::iterator itr = _ChildrenGroups.begin(); itr != _ChildrenGroups.end(); ++itr ) (*itr)->onWidgetDeleted( e ); } + + void CInterfaceGroup::moveBy( sint32 x, sint32 y ) + { + CInterfaceElement::moveBy( x, y ); + + for( int i = 0; i < _EltOrder.size(); i++ ) + { + CViewBase *v = _EltOrder[ i ]; + v->updateCoords(); + } + } + + bool CInterfaceGroup::explode() + { + CInterfaceGroup *p = getParent(); + if( p == NULL ) + return false; + + std::string oldId; + + // Reparent children + for( sint32 i = 0; i < _EltOrder.size(); i++ ) + { + CInterfaceElement *e = _EltOrder[ i ]; + + oldId = e->getId(); + + e->setW( e->getWReal() ); + e->setH( e->getHReal() ); + e->setSizeRef( "" ); + + e->setParent( p ); + + e->setParentPos( p ); + e->setParentSize( p ); + e->alignTo( p ); + + p->addElement( e ); + e->setIdRecurse( e->getShortId() ); + + CWidgetManager::getInstance()->onWidgetMoved( oldId, e->getId() ); + } + + _EltOrder.clear(); + _Views.clear(); + _Controls.clear(); + _ChildrenGroups.clear(); + + return true; + } + + void CInterfaceGroup::spanElements() + { + sint32 minx = std::numeric_limits< sint32 >::max(); + sint32 miny = std::numeric_limits< sint32 >::max(); + sint32 maxx = std::numeric_limits< sint32 >::min(); + sint32 maxy = std::numeric_limits< sint32 >::min(); + + sint32 tlx,tly,brx,bry; + + // Find the min and max coordinates of the elements + for( int i = 0; i < _EltOrder.size(); i++ ) + { + CViewBase *v = _EltOrder[ i ]; + + v->getHSCoords( Hotspot_TL, tlx, tly ); + v->getHSCoords( Hotspot_BR, brx, bry ); + + if( tlx < minx ) + minx = tlx; + if( brx > maxx ) + maxx = brx; + if( bry < miny ) + miny = bry; + if( tly > maxy ) + maxy = tly; + } + + // Set the position and the width and height based on these coords + setW( maxx - minx ); + setH( maxy - miny ); + _WReal = getW(); + _HReal = getH(); + _XReal = minx; + _YReal = miny; + } + + void CInterfaceGroup::alignElements() + { + for( int i = 0; i < _EltOrder.size(); i++ ) + { + CViewBase *v = _EltOrder[ i ]; + v->alignTo( this ); + } + } + } diff --git a/code/nel/src/gui/view_base.cpp b/code/nel/src/gui/view_base.cpp index 05d958d3e..2b09061a9 100644 --- a/code/nel/src/gui/view_base.cpp +++ b/code/nel/src/gui/view_base.cpp @@ -57,7 +57,7 @@ namespace NLGUI { if( editorMode ) { - CWidgetManager::getInstance()->setCurrentEditorSelection( getId() ); + CWidgetManager::getInstance()->selectWidget( getId() ); return true; } } diff --git a/code/nel/src/gui/view_text.cpp b/code/nel/src/gui/view_text.cpp index 0186938f7..743ba4ce7 100644 --- a/code/nel/src/gui/view_text.cpp +++ b/code/nel/src/gui/view_text.cpp @@ -1847,9 +1847,18 @@ namespace NLGUI if (_AutoClamp) { CViewBase::updateCoords (); - if (_Parent) + + // If there's no parent, try the parent of the parent element. + // Since we will be under the same group + CInterfaceGroup *parent = _Parent; + if( parent == NULL ) + { + if( _ParentElm != NULL ) + parent = _ParentElm->getParent(); + } + + if (parent) { - CInterfaceGroup *parent = _Parent; // avoid resizing parents to compute the limiter while (parent && (parent->getResizeFromChildW() || parent->isGroupList() )) { diff --git a/code/nel/src/gui/widget_manager.cpp b/code/nel/src/gui/widget_manager.cpp index 9b9a74e77..c68a2c963 100644 --- a/code/nel/src/gui/widget_manager.cpp +++ b/code/nel/src/gui/widget_manager.cpp @@ -34,7 +34,6 @@ #include "nel/gui/interface_expr.h" #include "nel/gui/reflect_register.h" #include "nel/gui/editor_selection_watcher.h" -#include "nel/gui/widget_addition_watcher.h" #include "nel/misc/events.h" namespace NLGUI @@ -1036,7 +1035,7 @@ namespace NLGUI setCapturePointerLeft(NULL); setCapturePointerRight(NULL); _CapturedView = NULL; - + resetColorProps(); resetAlphaRolloverSpeedProps(); resetGlobalAlphasProps(); @@ -2079,9 +2078,9 @@ namespace NLGUI if( CInterfaceElement::getEditorMode() ) { - if( !currentEditorSelection.empty() ) + for( int i = 0; i < editorSelection.size(); i++ ) { - CInterfaceElement *e = getElementFromId( currentEditorSelection ); + CInterfaceElement *e = getElementFromId( editorSelection[ i ] ); if( e != NULL ) e->drawHighlight(); } @@ -2304,6 +2303,14 @@ namespace NLGUI eventDesc.setX( _Pointer->getX() ); eventDesc.setY( _Pointer->getY() ); + if( CInterfaceElement::getEditorMode() ) + { + // Let's pretend we've handled the event... or actually we have! + if( ( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown ) || + ( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup ) ) + return true; + } + if( isMouseHandlingEnabled() ) { // First thing to do : Capture handling @@ -2402,20 +2409,37 @@ namespace NLGUI // This may happen when alt-tab has been used => the sheet is dragged but the left button is up if (!CCtrlDraggable::getDraggedSheet()) { - // Take the top most control. - uint nMaxDepth = 0; - const std::vector< CCtrlBase* >& _CtrlsUnderPointer = getCtrlsUnderPointer(); - for (sint32 i = (sint32)_CtrlsUnderPointer.size()-1; i >= 0; i--) + if( CInterfaceElement::getEditorMode() && _GroupSelection ) { - CCtrlBase *ctrl= _CtrlsUnderPointer[i]; - if (ctrl && ctrl->isCapturable() && ctrl->isInGroup( pNewCurrentWnd ) ) + for( sint32 i = _GroupsUnderPointer.size() - 1; i >= 0; i-- ) { - uint d = ctrl->getDepth( pNewCurrentWnd ); - if (d > nMaxDepth) + CInterfaceGroup *g = _GroupsUnderPointer[ i ]; + if( ( g != NULL ) && ( g->isInGroup( pNewCurrentWnd ) ) ) { - nMaxDepth = d; - setCapturePointerLeft( ctrl ); + _CapturedView = g; captured = true; + break; + } + } + } + + if( !captured ) + { + // Take the top most control. + uint nMaxDepth = 0; + const std::vector< CCtrlBase* >& _CtrlsUnderPointer = getCtrlsUnderPointer(); + for (sint32 i = (sint32)_CtrlsUnderPointer.size()-1; i >= 0; i--) + { + CCtrlBase *ctrl= _CtrlsUnderPointer[i]; + if (ctrl && ctrl->isCapturable() && ctrl->isInGroup( pNewCurrentWnd ) ) + { + uint d = ctrl->getDepth( pNewCurrentWnd ); + if (d > nMaxDepth) + { + nMaxDepth = d; + setCapturePointerLeft( ctrl ); + captured = true; + } } } } @@ -2452,6 +2476,11 @@ namespace NLGUI // handle the capture _CapturedView->handleEvent( evnt ); } + else + { + if( CInterfaceElement::getEditorMode() ) + clearEditorSelection(); + } } // Manage RightClick @@ -2631,9 +2660,10 @@ namespace NLGUI else if( draggedElement != NULL ) { - draggedElement->setXReal( newX ); - draggedElement->setYReal( newY ); - draggedElement->invalidateCoords(); + sint32 dx = newX - oldX; + sint32 dy = newY - oldY; + + draggedElement->moveBy( dx, dy ); } } @@ -2660,13 +2690,36 @@ namespace NLGUI e->setParent( NULL ); draggedElement = e; - + return true; } void CWidgetManager::stopDragging() { - draggedElement = NULL; + if( draggedElement != NULL ) + { + CInterfaceGroup *g = getGroupUnder( draggedElement->getXReal(), draggedElement->getYReal() ); + CInterfaceElement *e = draggedElement; + CInterfaceGroup *tw = getTopWindow(); + + if( g == NULL ) + g = tw; + + std::string oldid = e->getId(); + + e->setParent( g ); + e->setIdRecurse( e->getShortId() ); + e->setParentPos( g ); + e->setParentSize( g ); + g->addElement( e ); + + e->alignTo( g ); + //e->setName( "==MARKED==" ); + + draggedElement = NULL; + + onWidgetMoved( oldid, e->getId() ); + } } // ------------------------------------------------------------------------------------------------ @@ -3297,25 +3350,53 @@ namespace NLGUI } } - - void CWidgetManager::setCurrentEditorSelection( const std::string &name ) + void CWidgetManager::getEditorSelection( std::vector< std::string > &selection ) { + selection.clear(); + for( int i = 0; i < editorSelection.size(); i++ ) + selection.push_back( editorSelection[ i ] ); + } + + void CWidgetManager::selectWidget( const std::string &name ) + { + std::vector< std::string >::iterator itr + = std::find( editorSelection.begin(), editorSelection.end(), name ); + CInterfaceElement *e = getElementFromId( name ); - if( e != NULL ) + + if( itr != editorSelection.end() ) { - if( !currentEditorSelection.empty() ) + // If multiselection is on unselect if already selected + if( multiSelection ) { - CInterfaceElement *prev = getElementFromId( currentEditorSelection ); - if( prev != NULL ) - prev->setEditorSelected( false ); + editorSelection.erase( itr ); + if( e != NULL ) + e->setEditorSelected( false ); } - e->setEditorSelected( true ); } else - if( !name.empty() ) - return; - - currentEditorSelection = name; + { + // Select if not yet selected + if( e != NULL ) + { + // If multiselection is off, we can only have 1 widget selected + if( !multiSelection ) + { + editorSelection.clear(); + } + + e->setEditorSelected( true ); + editorSelection.push_back( name ); + } + + } + + notifySelectionWatchers(); + } + + void CWidgetManager::clearEditorSelection() + { + editorSelection.clear(); notifySelectionWatchers(); } @@ -3324,7 +3405,7 @@ namespace NLGUI std::vector< IEditorSelectionWatcher* >::iterator itr = selectionWatchers.begin(); while( itr != selectionWatchers.end() ) { - (*itr)->selectionChanged( currentEditorSelection ); + (*itr)->selectionChanged(); ++itr; } } @@ -3353,36 +3434,46 @@ namespace NLGUI selectionWatchers.erase( itr ); } - void CWidgetManager::notifyAdditionWatchers( const std::string &widgetName ) + void CWidgetManager::onWidgetAdded( const std::string &id ) { - std::vector< IWidgetAdditionWatcher* >::const_iterator itr = additionWatchers.begin(); - while( itr != additionWatchers.end() ) + std::vector< IWidgetWatcher* >::const_iterator itr = widgetWatchers.begin(); + while( itr != widgetWatchers.end() ) { - (*itr)->widgetAdded( widgetName ); + (*itr)->onWidgetAdded( id ); ++itr; } } - void CWidgetManager::registerAdditionWatcher( IWidgetAdditionWatcher *watcher ) + void CWidgetManager::onWidgetMoved( const std::string &oldid, const std::string &newid ) { - std::vector< IWidgetAdditionWatcher* >::const_iterator itr - = std::find( additionWatchers.begin(), additionWatchers.end(), watcher ); - // already exists - if( itr != additionWatchers.end() ) - return; - - additionWatchers.push_back( watcher ); + std::vector< IWidgetWatcher* >::const_iterator itr = widgetWatchers.begin(); + while( itr != widgetWatchers.end() ) + { + (*itr)->onWidgetMoved( oldid, newid ); + ++itr; + } } - void CWidgetManager::unregisterAdditionWatcher( IWidgetAdditionWatcher *watcher ) + void CWidgetManager::registerWidgetWatcher( IWidgetWatcher *watcher ) { - std::vector< IWidgetAdditionWatcher* >::iterator itr - = std::find( additionWatchers.begin(), additionWatchers.end(), watcher ); - // doesn't exist - if( itr == additionWatchers.end() ) + std::vector< IWidgetWatcher* >::const_iterator itr + = std::find( widgetWatchers.begin(), widgetWatchers.end(), watcher ); + // already exists + if( itr != widgetWatchers.end() ) return; - additionWatchers.erase( itr ); + widgetWatchers.push_back( watcher ); + } + + void CWidgetManager::unregisterWidgetWatcher( IWidgetWatcher *watcher ) + { + std::vector< IWidgetWatcher* >::iterator itr + = std::find( widgetWatchers.begin(), widgetWatchers.end(), watcher ); + // doesn't exist + if( itr == widgetWatchers.end() ) + return; + + widgetWatchers.erase( itr ); } CInterfaceElement* CWidgetManager::addWidgetToGroup( std::string &group, std::string &widgetClass, std::string &widgetName ) @@ -3415,11 +3506,103 @@ namespace NLGUI else g->addView( v ); - notifyAdditionWatchers( v->getId() ); + onWidgetAdded( v->getId() ); return v; } + bool CWidgetManager::groupSelection() + { + std::vector< CInterfaceElement* > elms; + + // Resolve the widget names + for( int i = 0; i < editorSelection.size(); i++ ) + { + CInterfaceElement *e = getElementFromId( editorSelection[ i ] ); + if( e != NULL ) + elms.push_back( e ); + } + + editorSelection.clear(); + + if( elms.empty() ) + return false; + + // Create the group as the subgroup of the top window + CInterfaceGroup *g = static_cast< CInterfaceGroup* >( getParser()->createClass( "interface_group" ) ); + getTopWindow()->addGroup( g ); + g->setParent( getTopWindow() ); + g->setIdRecurse( std::string( "group" ) + NLMISC::toString( _WidgetCount ) ); + _WidgetCount++; + onWidgetAdded( g->getId() ); + + std::string oldId; + + // Reparent the widgets to the new group + for( int i = 0; i < elms.size(); i++ ) + { + CInterfaceElement *e = elms[ i ]; + oldId = e->getId(); + CInterfaceGroup *p = e->getParent(); + if( p != NULL ) + p->takeElement( e ); + + g->addElement( e ); + e->setParent( g ); + e->setParentPos( g ); + e->setParentSize( g ); + e->setIdRecurse( e->getShortId() ); + + onWidgetMoved( oldId, e->getId() ); + } + elms.clear(); + + // Make sure widgets aren't clipped because the group isn't big enough + g->spanElements(); + // Make sure widgets are aligned + g->alignElements(); + // Align the new group to the top window + g->alignTo( getTopWindow() ); + + g->setActive( true ); + + return true; + } + + bool CWidgetManager::unGroupSelection() + { + if( editorSelection.size() != 1 ) + return false; + + // Does the element exist? + CInterfaceElement *e = getElementFromId( editorSelection[ 0 ] ); + if( e == NULL ) + return false; + + // Is the element a group? + CInterfaceGroup *g = dynamic_cast< CInterfaceGroup* >( e ); + if( g == NULL ) + return false; + + // Can't blow up a root group :( + CInterfaceGroup *p = g->getParent(); + if( p == NULL ) + return false; + + // KABOOM! + bool ok = g->explode(); + if( !ok ) + return false; + + p->delElement( g ); + + clearEditorSelection(); + + p->updateCoords(); + + return true; + } + CWidgetManager::CWidgetManager() { @@ -3458,7 +3641,9 @@ namespace NLGUI setScreenWH( 0, 0 ); - currentEditorSelection = ""; + _GroupSelection = false; + multiSelection = false; + _WidgetCount = 0; } CWidgetManager::~CWidgetManager() @@ -3472,6 +3657,8 @@ namespace NLGUI curContextHelp = NULL; CStringShared::deleteStringMapper(); + + editorSelection.clear(); } } diff --git a/code/studio/src/plugins/gui_editor/editor_message_processor.cpp b/code/studio/src/plugins/gui_editor/editor_message_processor.cpp index 691dbdead..ef99c87fc 100644 --- a/code/studio/src/plugins/gui_editor/editor_message_processor.cpp +++ b/code/studio/src/plugins/gui_editor/editor_message_processor.cpp @@ -25,35 +25,40 @@ namespace GUIEditor { void CEditorMessageProcessor::onDelete() { - std::string selection = CWidgetManager::getInstance()->getCurrentEditorSelection(); + std::vector< std::string > selection; + + CWidgetManager::getInstance()->getEditorSelection( selection ); if( selection.empty() ) return; QMessageBox::StandardButton r = QMessageBox::question( NULL, tr( "Deleting widget" ), - tr( "Are you sure you want to delete %1?" ).arg( selection.c_str() ), + tr( "Are you sure you want to delete these?" ), QMessageBox::Yes | QMessageBox::No ); if( r != QMessageBox::Yes ) return; - CInterfaceElement *e = - CWidgetManager::getInstance()->getElementFromId( selection ); - if( e == NULL ) - return; - - CInterfaceElement *p = e->getParent(); - if( p == NULL ) - return; - - CInterfaceGroup *g = dynamic_cast< CInterfaceGroup* >( p ); - if( g == NULL ) - return; - - if( g->delElement( e ) ) + for( int i = 0; i < selection.size(); i++ ) { - CWidgetManager::getInstance()->setCurrentEditorSelection( "" ); + CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( selection[ i ] ); + if( e == NULL ) + continue; + + CInterfaceElement *p = e->getParent(); + if( p == NULL ) + continue; + + CInterfaceGroup *g = dynamic_cast< CInterfaceGroup* >( p ); + if( g == NULL ) + continue; + + g->delElement( e ); + } + + + CWidgetManager::getInstance()->clearEditorSelection(); } void CEditorMessageProcessor::onAdd( const QString &parentGroup, const QString &widgetType, const QString &name ) @@ -130,5 +135,32 @@ namespace GUIEditor e->setActive( false ); e->setActive( true ); } + + void CEditorMessageProcessor::onSetGroupSelection( bool b ) + { + CWidgetManager::getInstance()->setGroupSelection( b ); + } + + void CEditorMessageProcessor::onGroup() + { + CWidgetManager::getInstance()->groupSelection(); + } + + void CEditorMessageProcessor::onUngroup() + { + bool ok = CWidgetManager::getInstance()->unGroupSelection(); + + if( !ok ) + { + QMessageBox::critical( NULL, + tr( "Ungrouping widgets" ), + tr( "Couldn't ungroup widgets." ) ); + } + } + + void CEditorMessageProcessor::onSetMultiSelection( bool b ) + { + CWidgetManager::getInstance()->setMultiSelection( b ); + } } diff --git a/code/studio/src/plugins/gui_editor/editor_message_processor.h b/code/studio/src/plugins/gui_editor/editor_message_processor.h index 5c19a03c2..ee55fcda7 100644 --- a/code/studio/src/plugins/gui_editor/editor_message_processor.h +++ b/code/studio/src/plugins/gui_editor/editor_message_processor.h @@ -38,6 +38,10 @@ namespace GUIEditor public Q_SLOTS: void onDelete(); void onAdd( const QString &parentGroup, const QString &widgetType, const QString &name ); + void onSetGroupSelection( bool b ); + void onGroup(); + void onUngroup(); + void onSetMultiSelection( bool b ); private: CWidgetInfoTree *tree; diff --git a/code/studio/src/plugins/gui_editor/editor_selection_watcher.cpp b/code/studio/src/plugins/gui_editor/editor_selection_watcher.cpp index ee3a079ad..7647c8abb 100644 --- a/code/studio/src/plugins/gui_editor/editor_selection_watcher.cpp +++ b/code/studio/src/plugins/gui_editor/editor_selection_watcher.cpp @@ -18,9 +18,9 @@ namespace GUIEditor { - void CEditorSelectionWatcher::selectionChanged( std::string &newSelection ) + void CEditorSelectionWatcher::selectionChanged() { - Q_EMIT sgnSelectionChanged( newSelection ); + Q_EMIT sgnSelectionChanged(); } } diff --git a/code/studio/src/plugins/gui_editor/editor_selection_watcher.h b/code/studio/src/plugins/gui_editor/editor_selection_watcher.h index 61218c0cd..2eab68310 100644 --- a/code/studio/src/plugins/gui_editor/editor_selection_watcher.h +++ b/code/studio/src/plugins/gui_editor/editor_selection_watcher.h @@ -27,10 +27,10 @@ namespace GUIEditor public: CEditorSelectionWatcher() : QObject( NULL ){} - void selectionChanged( std::string &newSelection ); + void selectionChanged(); Q_SIGNALS: - void sgnSelectionChanged( std::string &id ); + void sgnSelectionChanged(); }; } diff --git a/code/studio/src/plugins/gui_editor/gui_editor_window.cpp b/code/studio/src/plugins/gui_editor/gui_editor_window.cpp index 9f6568936..ca5e240e7 100644 --- a/code/studio/src/plugins/gui_editor/gui_editor_window.cpp +++ b/code/studio/src/plugins/gui_editor/gui_editor_window.cpp @@ -283,8 +283,8 @@ namespace GUIEditor CEditorSelectionWatcher *w = GUICtrl->getWatcher(); - disconnect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), hierarchyView, SLOT( onSelectionChanged( std::string& ) ) ); - disconnect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), &browserCtrl, SLOT( onSelectionChanged( std::string& ) ) ); + disconnect( w, SIGNAL( sgnSelectionChanged() ), hierarchyView, SLOT( onSelectionChanged() ) ); + disconnect( w, SIGNAL( sgnSelectionChanged() ), &browserCtrl, SLOT( onSelectionChanged() ) ); projectFiles.clearAll(); projectWindow->clear(); @@ -322,8 +322,8 @@ namespace GUIEditor linkList->onGUILoaded(); CEditorSelectionWatcher *w = GUICtrl->getWatcher(); - connect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), hierarchyView, SLOT( onSelectionChanged( std::string& ) ) ); - connect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), &browserCtrl, SLOT( onSelectionChanged( std::string& ) ) ); + connect( w, SIGNAL( sgnSelectionChanged() ), hierarchyView, SLOT( onSelectionChanged() ) ); + connect( w, SIGNAL( sgnSelectionChanged() ), &browserCtrl, SLOT( onSelectionChanged() ) ); } void GUIEditorWindow::onAddWidgetClicked() @@ -399,6 +399,30 @@ namespace GUIEditor connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onAddWidgetClicked() ) ); m->addAction( a ); + a = new QAction( "Group", this ); + connect( a, SIGNAL( triggered() ), messageProcessor, SLOT( onGroup() ) ); + m->addAction( a ); + + a = new QAction( "Ungroup", this ); + connect( a, SIGNAL( triggered() ), messageProcessor, SLOT( onUngroup() ) ); + m->addAction( a ); + + + // ---------------------------------------------------------------------------------- + m->addSeparator(); + + a = new QAction( "Select groups", this ); + a->setCheckable( true ); + a->setChecked( false ); + connect( a, SIGNAL( triggered( bool ) ), messageProcessor, SLOT( onSetGroupSelection( bool ) ) ); + m->addAction( a ); + + a = new QAction( "Multiselect", this ); + a->setCheckable( true ); + a->setChecked( false ); + connect( a, SIGNAL( triggered( bool ) ), messageProcessor, SLOT( onSetMultiSelection( bool ) ) ); + m->addAction( a ); + menu = m; } } diff --git a/code/studio/src/plugins/gui_editor/property_browser_ctrl.cpp b/code/studio/src/plugins/gui_editor/property_browser_ctrl.cpp index bd73fb7fa..84302bcf0 100644 --- a/code/studio/src/plugins/gui_editor/property_browser_ctrl.cpp +++ b/code/studio/src/plugins/gui_editor/property_browser_ctrl.cpp @@ -436,7 +436,7 @@ namespace GUIEditor browser->clear(); } - void CPropBrowserCtrl::onSelectionChanged( std::string &id ) + void CPropBrowserCtrl::onSelectionChanged() { if( browser == NULL ) return; @@ -444,14 +444,20 @@ namespace GUIEditor disablePropertyWatchers(); browser->clear(); - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( id ); + std::vector< std::string > selection; + CWidgetManager::getInstance()->getEditorSelection( selection ); + + if( selection.size() != 1 ) + return; + + CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( selection[ 0 ] ); if( e == NULL ) { enablePropertyWatchers(); return; } - currentElement = id; + currentElement = selection[ 0 ]; std::string n = e->getClassName(); @@ -493,6 +499,10 @@ namespace GUIEditor if( e == NULL ) return; e->setProperty( propName.toUtf8().constData(), propValue.toUtf8().constData() ); + + CInterfaceGroup *g = e->getParent(); + if( g != NULL ) + g->updateCoords(); // Make sure the changes are applied @@ -514,13 +524,12 @@ namespace GUIEditor return; std::string type = itr->second; + CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); + if( e == NULL ) + return; if( type == "button_type" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v; v = NelButtonType::toString( value ); if( v.empty() ) @@ -531,10 +540,6 @@ namespace GUIEditor else if( type == "text_justification" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v; v = NelTxtJustification::toString( value ); if( v.empty() ) @@ -545,10 +550,6 @@ namespace GUIEditor else if( type == "posref" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v = NelPosRef::toString( value ); if( v.empty() ) return; @@ -558,10 +559,6 @@ namespace GUIEditor else if( type == "posreftt" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v = NelPosRefTT::toString( value ); if( v.empty() ) return; @@ -608,10 +605,6 @@ namespace GUIEditor else if( type == "tooltip_parent" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v = NelTTParent::toString( value ); if( v.empty() ) return; @@ -621,16 +614,18 @@ namespace GUIEditor else if( type == "bitmap_align" ) { - CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( currentElement ); - if( e == NULL ) - return; - std::string v = NelBMAlign::toString( value ); if( v.empty() ) return; e->setProperty( propName.toUtf8().constData(), v ); } + + + CInterfaceGroup *g = e->getParent(); + if( g != NULL ) + g->updateCoords(); + } @@ -643,6 +638,10 @@ namespace GUIEditor return; e->setProperty( propName.toUtf8().constData(), v.toUtf8().constData() ); + + CInterfaceGroup *g = e->getParent(); + if( g != NULL ) + g->updateCoords(); } void CPropBrowserCtrl::onTexturePropertyChanged( QtProperty *p, const QString &v ) @@ -654,6 +653,10 @@ namespace GUIEditor return; e->setProperty( propName.toUtf8().constData(), v.toUtf8().constData() ); + + CInterfaceGroup *g = e->getParent(); + if( g != NULL ) + g->updateCoords(); } void CPropBrowserCtrl::enablePropertyWatchers() diff --git a/code/studio/src/plugins/gui_editor/property_browser_ctrl.h b/code/studio/src/plugins/gui_editor/property_browser_ctrl.h index abf80d7de..3d72d92ba 100644 --- a/code/studio/src/plugins/gui_editor/property_browser_ctrl.h +++ b/code/studio/src/plugins/gui_editor/property_browser_ctrl.h @@ -59,7 +59,7 @@ namespace GUIEditor void clear(); public Q_SLOTS: - void onSelectionChanged( std::string &id ); + void onSelectionChanged(); private Q_SLOTS: void onPropertyChanged( QtProperty *prop, const QVariant &v ); diff --git a/code/studio/src/plugins/gui_editor/widget_hierarchy.cpp b/code/studio/src/plugins/gui_editor/widget_hierarchy.cpp index 24208f4a3..343d8efd8 100644 --- a/code/studio/src/plugins/gui_editor/widget_hierarchy.cpp +++ b/code/studio/src/plugins/gui_editor/widget_hierarchy.cpp @@ -18,7 +18,6 @@ #include "widget_hierarchy.h" #include "nel/gui/interface_group.h" #include "nel/gui/widget_manager.h" -#include "nel/gui/widget_addition_watcher.h" namespace { @@ -76,18 +75,24 @@ namespace GUIEditor::WidgetHierarchy *h; }; - class CWidgetAdditionWatcher : public IWidgetAdditionWatcher + class CWidgetWatcher : public CWidgetManager::IWidgetWatcher { public: - CWidgetAdditionWatcher(){ h = NULL; } - ~CWidgetAdditionWatcher(){} + CWidgetWatcher(){ h = NULL; } + ~CWidgetWatcher(){} - void widgetAdded( const std::string &name ) + void onWidgetAdded( const std::string &name ) { if( h != NULL ) h->onWidgetAdded( name ); } - + + void onWidgetMoved( const std::string &oldid, const std::string &newid ) + { + if( h != NULL ) + h->onWidgetMoved( oldid, newid ); + } + void setWidgetHierarchy( GUIEditor::WidgetHierarchy *h ){ this->h = h; } private: @@ -95,7 +100,7 @@ namespace }; CWidgetDeletionWatcher deletionWatcher; - CWidgetAdditionWatcher additionWatcher; + CWidgetWatcher widgetwatcher; } namespace GUIEditor @@ -107,7 +112,7 @@ namespace GUIEditor connect( widgetHT, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( onItemDblClicked( QTreeWidgetItem* ) ) ); deletionWatcher.setWidgetHierarchy( this ); - additionWatcher.setWidgetHierarchy( this ); + widgetwatcher.setWidgetHierarchy( this ); } WidgetHierarchy::~WidgetHierarchy() @@ -117,7 +122,7 @@ namespace GUIEditor void WidgetHierarchy::clearHierarchy() { CInterfaceElement::unregisterDeletionWatcher( &deletionWatcher ); - CWidgetManager::getInstance()->unregisterAdditionWatcher( &additionWatcher ); + CWidgetManager::getInstance()->unregisterWidgetWatcher( &widgetwatcher ); widgetHT->clear(); widgetHierarchyMap.clear(); } @@ -126,7 +131,7 @@ namespace GUIEditor { clearHierarchy(); CInterfaceElement::registerDeletionWatcher( &deletionWatcher ); - CWidgetManager::getInstance()->registerAdditionWatcher( &additionWatcher ); + CWidgetManager::getInstance()->registerWidgetWatcher( &widgetwatcher ); CInterfaceGroup *mg = CWidgetManager::getInstance()->getMasterGroupFromId( masterGroup ); if( mg != NULL ) @@ -177,6 +182,27 @@ namespace GUIEditor } } + QTreeWidgetItem* WidgetHierarchy::findItem( const std::string &id ) + { + std::map< std::string, QTreeWidgetItem* >::iterator itr + = widgetHierarchyMap.find( id ); + if( itr == widgetHierarchyMap.end() ) + return NULL; + else + return itr->second; + } + + QTreeWidgetItem* WidgetHierarchy::findParent( const std::string &id ) + { + // Get the parent's name + std::string::size_type p = id.find_last_of( ':' ); + if( p == std::string::npos ) + return NULL; + std::string parentId = id.substr( 0, p ); + + return findItem( parentId ); + } + void WidgetHierarchy::onWidgetDeleted( const std::string &id ) { std::map< std::string, QTreeWidgetItem* >::iterator itr @@ -231,16 +257,62 @@ namespace GUIEditor widgetHierarchyMap[ id ] = item; } + void WidgetHierarchy::onWidgetMoved( const std::string &oldid, const std::string &newid ) + { + QTreeWidgetItem *newParent = NULL; + QTreeWidgetItem *item = NULL; + QString id; + + newParent = findParent( newid ); + item = findItem( oldid ); + + if( ( newParent == NULL ) || ( item == NULL ) ) + return; + + // Remove item from old parent + QTreeWidgetItem *p = item->parent(); + if( p != NULL ) + p->setExpanded( false ); + p->removeChild( item ); + + // Remove reference to old item + widgetHierarchyMap.erase( oldid ); + + // Add item to new parent + newParent->addChild( item ); + + // Add reference to new item + widgetHierarchyMap[ newid ] = item; + + selectItem( item ); + } + + void WidgetHierarchy::selectItem( QTreeWidgetItem *item ) + { + widgetHT->collapseAll(); + + QTreeWidgetItem *currItem = item; + while( currItem != NULL ) + { + currItem->setExpanded( true ); + currItem = currItem->parent(); + } + + widgetHT->setCurrentItem( item ); + item->setSelected( true ); + } + void WidgetHierarchy::getCurrentGroup( QString &g ) { - std::string s = CWidgetManager::getInstance()->getCurrentEditorSelection(); - if( s.empty() ) + std::vector< std::string > selection; + CWidgetManager::getInstance()->getEditorSelection( selection ); + if( selection.size() != 1 ) { g = ""; return; } - NLGUI::CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( s ); + NLGUI::CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( selection[ 0 ] ); if( e == NULL ) { g = ""; @@ -271,8 +343,16 @@ namespace GUIEditor currentSelection.clear(); } - void WidgetHierarchy::onSelectionChanged( std::string &newSelection ) + void WidgetHierarchy::onSelectionChanged() { + std::vector< std::string > selection; + CWidgetManager::getInstance()->getEditorSelection( selection ); + + if( selection.size() != 1 ) + return; + + std::string newSelection = selection[ 0 ]; + if( newSelection == currentSelection ) return; @@ -288,18 +368,11 @@ namespace GUIEditor if( widgetHT->currentItem() != NULL ) widgetHT->currentItem()->setSelected( false ); - // expand the tree items, so that we can see the selected item - QTreeWidgetItem *item = itr->second; - QTreeWidgetItem *currItem = item; - while( currItem != NULL ) - { - currItem->setExpanded( true ); - currItem = currItem->parent(); - } + widgetHT->collapseAll(); // select the current item - item->setSelected( true ); - widgetHT->setCurrentItem( item ); + QTreeWidgetItem *item = itr->second; + selectItem( item ); currentSelection = newSelection; } @@ -307,9 +380,11 @@ namespace GUIEditor { if( item->parent() == NULL ) return; + + selectItem( item ); std::string n = item->text( 0 ).toUtf8().constData(); currentSelection = makeFullName( item, n ); - CWidgetManager::getInstance()->setCurrentEditorSelection( currentSelection ); + CWidgetManager::getInstance()->selectWidget( currentSelection ); } } diff --git a/code/studio/src/plugins/gui_editor/widget_hierarchy.h b/code/studio/src/plugins/gui_editor/widget_hierarchy.h index 4641c8ce8..cdfc9a741 100644 --- a/code/studio/src/plugins/gui_editor/widget_hierarchy.h +++ b/code/studio/src/plugins/gui_editor/widget_hierarchy.h @@ -44,15 +44,19 @@ namespace GUIEditor void onWidgetDeleted( const std::string &id ); void onWidgetAdded( const std::string &id ); + void onWidgetMoved( const std::string &oldid, const std::string &newid ); void getCurrentGroup( QString &g ); private: void buildHierarchy( QTreeWidgetItem *parent, NLGUI::CInterfaceGroup *group ); + QTreeWidgetItem* findItem( const std::string &id ); + QTreeWidgetItem* findParent( const std::string &id ); + void selectItem( QTreeWidgetItem *item ); public Q_SLOTS: void onGUILoaded(); - void onSelectionChanged( std::string &newSelection ); + void onSelectionChanged(); private Q_SLOTS: void onItemDblClicked( QTreeWidgetItem *item );