diff --git a/code/nel/include/nel/gui/ctrl_base.h b/code/nel/include/nel/gui/ctrl_base.h index fe8d5ea60..28eeb2cd0 100644 --- a/code/nel/include/nel/gui/ctrl_base.h +++ b/code/nel/include/nel/gui/ctrl_base.h @@ -68,9 +68,7 @@ namespace NLGUI // special parse virtual bool parse(xmlNodePtr cur, CInterfaceGroup *parentGroup); - - /// Handle all events (implemented by derived classes) (return true to signal event handled) - virtual bool handleEvent (const NLGUI::CEventDescriptor &event); + bool handleEvent (const NLGUI::CEventDescriptor &event); virtual CCtrlBase *getSubCtrl (sint32 /* x */, sint32 /* y */) { return this; } diff --git a/code/nel/include/nel/gui/ctrl_text_button.h b/code/nel/include/nel/gui/ctrl_text_button.h index 2df1dee5d..183b6a65e 100644 --- a/code/nel/include/nel/gui/ctrl_text_button.h +++ b/code/nel/include/nel/gui/ctrl_text_button.h @@ -42,6 +42,7 @@ namespace NLGUI /// Constructor CCtrlTextButton(const TCtorParam ¶m); + ~CCtrlTextButton(); std::string getProperty( const std::string &name ) const; void setProperty( const std::string &name, const std::string &value ); @@ -123,6 +124,9 @@ namespace NLGUI REFLECT_LUA_METHOD("getViewText", luaGetViewText) REFLECT_EXPORT_END + void onRemoved(); + void onWidgetDeleted( CInterfaceElement *e ); + protected: enum {NumTexture= 3}; diff --git a/code/nel/include/nel/gui/editor_selection_watcher.h b/code/nel/include/nel/gui/editor_selection_watcher.h new file mode 100644 index 000000000..415f4f9db --- /dev/null +++ b/code/nel/include/nel/gui/editor_selection_watcher.h @@ -0,0 +1,30 @@ +// 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 + +namespace NLGUI +{ + /// Watches the currently selected GUI widget + class IEditorSelectionWatcher + { + public: + + /// Notifies the watcher about the change + virtual void selectionChanged( std::string &newSelection ) = 0; + }; +} + diff --git a/code/nel/include/nel/gui/interface_element.h b/code/nel/include/nel/gui/interface_element.h index 210c24b2e..764d165ef 100644 --- a/code/nel/include/nel/gui/interface_element.h +++ b/code/nel/include/nel/gui/interface_element.h @@ -70,6 +70,14 @@ namespace NLGUI { public: + /// Watches CInterfaceElement deletions + class IDeletionWatcher + { + public: + IDeletionWatcher(){} + virtual ~IDeletionWatcher(){} + virtual void onDeleted( const std::string &name ){} + }; enum EStrech { @@ -424,6 +432,8 @@ namespace NLGUI void drawHotSpot(THotSpot hs, NLMISC::CRGBA col); + void drawHighlight(); + // Returns 'true' if that element can be downcasted to a view virtual bool isView() const { return false; } @@ -473,6 +483,7 @@ namespace NLGUI bool isInGroup( CInterfaceGroup *group ); static void setEditorMode( bool b ){ editorMode = b; } + static bool getEditorMode(){ return editorMode; } void setEditorSelected( bool b ){ editorSelected = b; } bool isEditorSelected() const{ return editorSelected; } @@ -483,6 +494,19 @@ namespace NLGUI void setSerializable( bool b ){ serializable = b; } bool IsSerializable() const{ return serializable; } + /// Called when the widget is removed from it's parent group + virtual void onRemoved(){} + + /// Registers a deletion watcher + static void registerDeletionWatcher( IDeletionWatcher *watcher ); + + /// Unregisters a deletion watcher + static void unregisterDeletionWatcher( IDeletionWatcher *watcher ); + + /// Called when the widget is deleted, + /// so other widgets in the group can check if it belongs to them + virtual void onWidgetDeleted( CInterfaceElement *e ){} + protected: bool editorSelected; @@ -543,6 +567,11 @@ namespace NLGUI void parseSizeRef(const char *sizeRefStr, sint32 &sizeref, sint32 &sizeDivW, sint32 &sizeDivH); private: + /// Notifies the deletion watchers that this interface element is being deleted + void notifyDeletionWatchers(); + + static std::vector< IDeletionWatcher* > deletionWatchers; + //void snapSize(); bool serializable; diff --git a/code/nel/include/nel/gui/interface_group.h b/code/nel/include/nel/gui/interface_group.h index 61cdc2c9b..f72bc6f1f 100644 --- a/code/nel/include/nel/gui/interface_group.h +++ b/code/nel/include/nel/gui/interface_group.h @@ -322,6 +322,8 @@ namespace NLGUI // Return the current Depth, with no ZBias applied. float getDepthForZSort() const { return _DepthForZSort; } + void onWidgetDeleted( CInterfaceElement *e ); + protected: void makeNewClip (sint32 &oldClipX, sint32 &oldClipY, sint32 &oldClipW, sint32 &oldClipH); diff --git a/code/nel/include/nel/gui/view_base.h b/code/nel/include/nel/gui/view_base.h index b7d2aceab..f64803720 100644 --- a/code/nel/include/nel/gui/view_base.h +++ b/code/nel/include/nel/gui/view_base.h @@ -25,6 +25,7 @@ namespace NLGUI { + class CEventDescriptor; class CViewBase : public CInterfaceElement { @@ -76,6 +77,9 @@ namespace NLGUI // special for mouse over : return true and fill the name of the cursor to display virtual bool getMouseOverShape(std::string &/* texName */, uint8 &/* rot */, NLMISC::CRGBA &/* col */) { return false; } + + /// Handle all events (implemented by derived classes) (return true to signal event handled) + virtual bool handleEvent (const NLGUI::CEventDescriptor &evnt); }; diff --git a/code/nel/include/nel/gui/widget_manager.h b/code/nel/include/nel/gui/widget_manager.h index 7fedc6240..498139ecf 100644 --- a/code/nel/include/nel/gui/widget_manager.h +++ b/code/nel/include/nel/gui/widget_manager.h @@ -47,6 +47,7 @@ namespace NLGUI class CInterfaceOptions; class CInterfaceAnim; class CProcedure; + class IEditorSelectionWatcher; /** GUI Widget Manager @@ -341,6 +342,7 @@ namespace NLGUI /** * Capture */ + CViewBase *getCapturedView(){ return _CapturedView; } CCtrlBase *getCapturePointerLeft() { return _CapturePointerLeft; } CCtrlBase *getCapturePointerRight() { return _CapturePointerRight; } CCtrlBase *getCaptureKeyboard() { return _CaptureKeyboard; } @@ -483,7 +485,11 @@ namespace NLGUI IParser* getParser() const{ return parser; } + std::string& getCurrentEditorSelection(){ return currentEditorSelection; } void setCurrentEditorSelection( const std::string &name ); + void notifySelectionWatchers(); + void registerSelectionWatcher( IEditorSelectionWatcher *watcher ); + void unregisterSelectionWatcher( IEditorSelectionWatcher *watcher ); private: CWidgetManager(); @@ -510,6 +516,8 @@ namespace NLGUI NLMISC::CRefPtr _CapturePointerLeft; NLMISC::CRefPtr _CapturePointerRight; + NLMISC::CRefPtr< CViewBase > _CapturedView; + // What is under pointer std::vector< CViewBase* > _ViewsUnderPointer; std::vector< CCtrlBase* > _CtrlsUnderPointer; @@ -561,6 +569,8 @@ namespace NLGUI std::vector< INewScreenSizeHandler* > newScreenSizeHandlers; std::vector< IOnWidgetsDrawnHandler* > onWidgetsDrawnHandlers; + std::vector< IEditorSelectionWatcher* > selectionWatchers; + std::string currentEditorSelection; }; diff --git a/code/nel/src/gui/ctrl_base.cpp b/code/nel/src/gui/ctrl_base.cpp index f3dcd3712..4f9b616b8 100644 --- a/code/nel/src/gui/ctrl_base.cpp +++ b/code/nel/src/gui/ctrl_base.cpp @@ -39,6 +39,9 @@ namespace NLGUI // *************************************************************************** bool CCtrlBase::handleEvent(const NLGUI::CEventDescriptor &event) { + if( CViewBase::handleEvent( event ) ) + return true; + if (event.getType() == NLGUI::CEventDescriptor::system) { NLGUI::CEventDescriptorSystem &eds = (NLGUI::CEventDescriptorSystem&)event; diff --git a/code/nel/src/gui/ctrl_base_button.cpp b/code/nel/src/gui/ctrl_base_button.cpp index 8c74e3bfc..74c6cf408 100644 --- a/code/nel/src/gui/ctrl_base_button.cpp +++ b/code/nel/src/gui/ctrl_base_button.cpp @@ -669,12 +669,6 @@ namespace NLGUI if (CWidgetManager::getInstance()->getCapturePointerLeft() != this) return false; - if( editorMode ) - { - CWidgetManager::getInstance()->setCurrentEditorSelection( getId() ); - return true; - } - if (_LeftDblClickHandled) // no effect on mouse up after double click has been handled { _LeftDblClickHandled = false; diff --git a/code/nel/src/gui/ctrl_button.cpp b/code/nel/src/gui/ctrl_button.cpp index 571781e11..3a09dfc8e 100644 --- a/code/nel/src/gui/ctrl_button.cpp +++ b/code/nel/src/gui/ctrl_button.cpp @@ -359,7 +359,7 @@ namespace NLGUI - if ( ( _Over && !editorMode ) || editorSelected ) + if ( ( _Over && !editorMode ) ) { if( !editorMode && (lastOver == false) && (_AHOnOver != NULL)) diff --git a/code/nel/src/gui/ctrl_text_button.cpp b/code/nel/src/gui/ctrl_text_button.cpp index ad0ba93aa..a977902b7 100644 --- a/code/nel/src/gui/ctrl_text_button.cpp +++ b/code/nel/src/gui/ctrl_text_button.cpp @@ -62,6 +62,17 @@ namespace NLGUI _ForceTextOver = false; } + CCtrlTextButton::~CCtrlTextButton() + { + if( _ViewText != NULL ) + { + if( _Parent != NULL ) + _Parent->delView( _ViewText, true ); + delete _ViewText; + _ViewText = NULL; + } + } + std::string CCtrlTextButton::getProperty( const std::string &name ) const { std::string prop; @@ -113,7 +124,10 @@ namespace NLGUI else if( name == "hardtext" ) { - return _ViewText->getText().toString(); + if( _ViewText != NULL ) + return _ViewText->getText().toString(); + else + return std::string( "" ); } else if( name == "text_y" ) @@ -128,7 +142,10 @@ namespace NLGUI else if( name == "text_underlined" ) { - return toString( _ViewText->getUnderlined() ); + if( _ViewText != NULL ) + return toString( _ViewText->getUnderlined() ); + else + return std::string( "" ); } else if( name == "text_posref" ) @@ -269,7 +286,8 @@ namespace NLGUI else if( name == "hardtext" ) { - _ViewText->setText( value ); + if( _ViewText != NULL ) + _ViewText->setText( value ); return; } else @@ -292,8 +310,10 @@ namespace NLGUI if( name == "text_underlined" ) { bool b; - if( fromString( value, b ) ) - _ViewText->setUnderlined( b ); + if( _ViewText != NULL ) + if( fromString( value, b ) ) + _ViewText->setUnderlined( b ); + return; } else @@ -766,8 +786,7 @@ namespace NLGUI CCtrlBase *capturePointerLeft = CWidgetManager::getInstance()->getCapturePointerLeft(); // *** Draw Over - if( editorSelected || - ( !editorMode && _Over && (_OverWhenPushed || !(_Pushed || capturePointerLeft == this ) ) ) + if( ( !editorMode && _Over && (_OverWhenPushed || !(_Pushed || capturePointerLeft == this ) ) ) ) { if( !editorMode && (lastOver == false) && (_AHOnOver != NULL) ) @@ -803,32 +822,35 @@ namespace NLGUI } } // Setup ViewText color - if ( pTxId==_TextureIdNormal || editorMode ) + if( _ViewText != NULL ) { - if(_TextHeaderColor) viewTextColor.A= _TextColorNormal.A; - else viewTextColor= _TextColorNormal; - _ViewText->setColor(viewTextColor); - _ViewText->setShadowColor(_TextShadowColorNormal); - _ViewText->setModulateGlobalColor(_TextModulateGlobalColorNormal); + if ( pTxId==_TextureIdNormal || editorMode ) + { + if(_TextHeaderColor) viewTextColor.A= _TextColorNormal.A; + else viewTextColor= _TextColorNormal; + _ViewText->setColor(viewTextColor); + _ViewText->setShadowColor(_TextShadowColorNormal); + _ViewText->setModulateGlobalColor(_TextModulateGlobalColorNormal); + } + else if ( pTxId==_TextureIdPushed ) + { + if(_TextHeaderColor) viewTextColor.A= _TextColorPushed.A; + else viewTextColor= _TextColorPushed; + _ViewText->setColor(viewTextColor); + _ViewText->setShadowColor(_TextShadowColorPushed); + _ViewText->setModulateGlobalColor(_TextModulateGlobalColorPushed); + } + else if ( pTxId==_TextureIdOver ) + { + if(_TextHeaderColor) viewTextColor.A= _TextColorOver.A; + else viewTextColor= _TextColorOver; + _ViewText->setColor(viewTextColor); + _ViewText->setShadowColor(_TextShadowColorOver); + _ViewText->setModulateGlobalColor(_TextModulateGlobalColorOver); + } + if(getFrozen() && getFrozenHalfTone()) + _ViewText->setAlpha(_ViewText->getAlpha()>>2); } - else if ( pTxId==_TextureIdPushed ) - { - if(_TextHeaderColor) viewTextColor.A= _TextColorPushed.A; - else viewTextColor= _TextColorPushed; - _ViewText->setColor(viewTextColor); - _ViewText->setShadowColor(_TextShadowColorPushed); - _ViewText->setModulateGlobalColor(_TextModulateGlobalColorPushed); - } - else if ( pTxId==_TextureIdOver ) - { - if(_TextHeaderColor) viewTextColor.A= _TextColorOver.A; - else viewTextColor= _TextColorOver; - _ViewText->setColor(viewTextColor); - _ViewText->setShadowColor(_TextShadowColorOver); - _ViewText->setModulateGlobalColor(_TextModulateGlobalColorOver); - } - if(getFrozen() && getFrozenHalfTone()) - _ViewText->setAlpha(_ViewText->getAlpha()>>2); } @@ -960,6 +982,19 @@ 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; + } } diff --git a/code/nel/src/gui/interface_element.cpp b/code/nel/src/gui/interface_element.cpp index 759ce5f35..d125bf064 100644 --- a/code/nel/src/gui/interface_element.cpp +++ b/code/nel/src/gui/interface_element.cpp @@ -34,6 +34,7 @@ using namespace NLMISC; namespace NLGUI { bool CInterfaceElement::editorMode = false; + std::vector< CInterfaceElement::IDeletionWatcher* > CInterfaceElement::deletionWatchers; // ------------------------------------------------------------------------------------------------ CInterfaceElement::~CInterfaceElement() @@ -46,6 +47,13 @@ namespace NLGUI } delete _Links; } + + if( editorMode ) + { + notifyDeletionWatchers(); + if( _Parent != NULL ) + _Parent->onWidgetDeleted( this ); + } } // ------------------------------------------------------------------------------------------------ @@ -1302,6 +1310,11 @@ namespace NLGUI } + void CInterfaceElement::drawHighlight() + { + CViewRenderer::getInstance()->drawWiredQuad( _XReal, _YReal, _WReal, _HReal ); + } + // *************************************************************************** void CInterfaceElement::invalidateContent() { @@ -1548,6 +1561,36 @@ namespace NLGUI } } + void CInterfaceElement::registerDeletionWatcher( IDeletionWatcher *watcher ) + { + std::vector< IDeletionWatcher* >::iterator itr + = std::find( deletionWatchers.begin(), deletionWatchers.end(), watcher ); + // Already registered + if( itr != deletionWatchers.end() ) + return; + deletionWatchers.push_back( watcher ); + } + + void CInterfaceElement::unregisterDeletionWatcher( IDeletionWatcher *watcher ) + { + std::vector< IDeletionWatcher* >::iterator itr + = std::find( deletionWatchers.begin(), deletionWatchers.end(), watcher ); + // Not registered + if( itr == deletionWatchers.end() ) + return; + deletionWatchers.erase( itr ); + } + + void CInterfaceElement::notifyDeletionWatchers() + { + std::vector< IDeletionWatcher* >::iterator itr = deletionWatchers.begin(); + while( itr != deletionWatchers.end() ) + { + (*itr)->onDeleted( _Id ); + ++itr; + } + } + CStringMapper* CStringShared::_UIStringMapper = NULL; diff --git a/code/nel/src/gui/interface_group.cpp b/code/nel/src/gui/interface_group.cpp index f981814ba..4d896dfad 100644 --- a/code/nel/src/gui/interface_group.cpp +++ b/code/nel/src/gui/interface_group.cpp @@ -143,12 +143,12 @@ namespace NLGUI // initStart = ryzomGetLocalTime (); clearGroups(); // nlinfo ("%d seconds for clearGroups '%s'", (uint32)(ryzomGetLocalTime ()-initStart)/1000, _Id.c_str()); - // initStart = ryzomGetLocalTime (); - clearViews(); - // nlinfo ("%d seconds for clearViews '%s'", (uint32)(ryzomGetLocalTime ()-initStart)/1000, _Id.c_str()); // initStart = ryzomGetLocalTime (); clearControls(); // nlinfo ("%d seconds for clearControls '%s'", (uint32)(ryzomGetLocalTime ()-initStart)/1000, _Id.c_str()); + // initStart = ryzomGetLocalTime (); + clearViews(); + // nlinfo ("%d seconds for clearViews '%s'", (uint32)(ryzomGetLocalTime ()-initStart)/1000, _Id.c_str()); CWidgetManager::getInstance()->removeRefOnGroup (this); #ifdef AJM_DEBUG_TRACK_INTERFACE_GROUPS @@ -1086,9 +1086,11 @@ namespace NLGUI { if (_Views[i] == child) { - if (!dontDelete) delete _Views[i]; + CViewBase *v = _Views[i]; _Views.erase(_Views.begin()+i); delEltOrder (child); + child->onRemoved(); + if (!dontDelete) delete v; return true; } } @@ -1102,9 +1104,11 @@ namespace NLGUI { if (_Controls[i] == child) { - if (!dontDelete) delete _Controls[i]; + CCtrlBase *c = _Controls[i]; _Controls.erase(_Controls.begin()+i); delEltOrder (child); + child->onRemoved(); + if (!dontDelete) delete c; return true; } } @@ -1118,9 +1122,11 @@ namespace NLGUI { if (_ChildrenGroups[i] == child) { - if (!dontDelete) delete _ChildrenGroups[i]; + CInterfaceGroup *g = _ChildrenGroups[i]; _ChildrenGroups.erase(_ChildrenGroups.begin()+i); delEltOrder (child); + child->onRemoved(); + if (!dontDelete) delete g; return true; } } @@ -2470,4 +2476,16 @@ namespace NLGUI return "IMPLEMENT ME!"; } -} \ No newline at end of file + void CInterfaceGroup::onWidgetDeleted( CInterfaceElement *e ) + { + for( std::vector< CViewBase* >::iterator itr = _Views.begin(); itr != _Views.end(); ++itr ) + (*itr)->onWidgetDeleted( e ); + + for( std::vector< CCtrlBase* >::iterator itr = _Controls.begin(); itr != _Controls.end(); ++itr ) + (*itr)->onWidgetDeleted( e ); + + for( std::vector< CInterfaceGroup* >::iterator itr = _ChildrenGroups.begin(); itr != _ChildrenGroups.end(); ++itr ) + (*itr)->onWidgetDeleted( e ); + } +} + diff --git a/code/nel/src/gui/view_base.cpp b/code/nel/src/gui/view_base.cpp index a4c8f6643..05d958d3e 100644 --- a/code/nel/src/gui/view_base.cpp +++ b/code/nel/src/gui/view_base.cpp @@ -47,5 +47,23 @@ namespace NLGUI CInterfaceElement::visit(visitor); } + + bool CViewBase::handleEvent( const NLGUI::CEventDescriptor &evnt ) + { + if( evnt.getType() == NLGUI::CEventDescriptor::mouse ) + { + const NLGUI::CEventDescriptorMouse &eventDesc = ( const NLGUI::CEventDescriptorMouse& )evnt; + if( eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown ) + { + if( editorMode ) + { + CWidgetManager::getInstance()->setCurrentEditorSelection( getId() ); + return true; + } + } + } + return false; + } + } diff --git a/code/nel/src/gui/widget_manager.cpp b/code/nel/src/gui/widget_manager.cpp index 22839a8cf..0612d54b1 100644 --- a/code/nel/src/gui/widget_manager.cpp +++ b/code/nel/src/gui/widget_manager.cpp @@ -33,6 +33,7 @@ #include "nel/gui/proc.h" #include "nel/gui/interface_expr.h" #include "nel/gui/reflect_register.h" +#include "nel/gui/editor_selection_watcher.h" #include "nel/misc/events.h" namespace NLGUI @@ -1033,6 +1034,7 @@ namespace NLGUI _OldCaptureKeyboard = NULL; setCapturePointerLeft(NULL); setCapturePointerRight(NULL); + _CapturedView = NULL; resetColorProps(); @@ -2056,6 +2058,16 @@ namespace NLGUI getPointer()->draw (); } + if( CInterfaceElement::getEditorMode() ) + { + if( !currentEditorSelection.empty() ) + { + CInterfaceElement *e = getElementFromId( currentEditorSelection ); + if( e != NULL ) + e->drawHighlight(); + } + } + // flush layers CViewRenderer::getInstance()->flush(); @@ -2088,6 +2100,12 @@ namespace NLGUI getCapturePointerRight()->handleEvent( evnt ); setCapturePointerRight( NULL ); } + + if( _CapturedView != NULL ) + { + _CapturedView->handleEvent( evnt ); + _CapturedView = NULL; + } } } @@ -2251,6 +2269,9 @@ namespace NLGUI getCapturePointerLeft() != getCapturePointerRight() ) handled|= getCapturePointerRight()->handleEvent(evnt); + if( _CapturedView != NULL ) + _CapturedView->handleEvent( evnt ); + CInterfaceGroup *ptr = getWindowUnder (eventDesc.getX(), eventDesc.getY()); setCurrentWindowUnder( ptr ); @@ -2328,6 +2349,8 @@ namespace NLGUI } } + bool captured = false; + // must not capture a new element if a sheet is currentlty being dragged. // This may happen when alt-tab has been used => the sheet is dragged but the left button is up if (!CCtrlDraggable::getDraggedSheet()) @@ -2345,9 +2368,25 @@ namespace NLGUI { nMaxDepth = d; setCapturePointerLeft( ctrl ); + captured = true; } } } + + if( CInterfaceElement::getEditorMode() && !captured ) + { + for( sint32 i = _ViewsUnderPointer.size()-1; i >= 0; i-- ) + { + CViewBase *v = _ViewsUnderPointer[i]; + if( ( v != NULL ) && v->isInGroup( pNewCurrentWnd ) ) + { + _CapturedView = v; + captured = true; + break; + } + } + } + notifyElementCaptured( getCapturePointerLeft() ); if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty()) { @@ -2355,13 +2394,16 @@ namespace NLGUI } } //if found - if ( getCapturePointerLeft() != NULL) + if ( captured ) { // consider clicking on a control implies handling of the event. handled= true; // handle the capture - getCapturePointerLeft()->handleEvent(evnt); + if( getCapturePointerLeft() != NULL ) + getCapturePointerLeft()->handleEvent(evnt); + else + _CapturedView->handleEvent( evnt ); } } @@ -2590,6 +2632,8 @@ namespace NLGUI // *************************************************************************** void CWidgetManager::setCapturePointerLeft(CCtrlBase *c) { + _CapturedView = NULL; + // additionally, abort any dragging if( CCtrlDraggable::getDraggedSheet() != NULL ) CCtrlDraggable::getDraggedSheet()->abortDragging(); @@ -3149,8 +3193,47 @@ namespace NLGUI prev->setEditorSelected( false ); } e->setEditorSelected( true ); - currentEditorSelection = name; } + else + if( !name.empty() ) + return; + + currentEditorSelection = name; + notifySelectionWatchers(); + } + + void CWidgetManager::notifySelectionWatchers() + { + std::vector< IEditorSelectionWatcher* >::iterator itr = selectionWatchers.begin(); + while( itr != selectionWatchers.end() ) + { + (*itr)->selectionChanged( currentEditorSelection ); + ++itr; + } + } + + void CWidgetManager::registerSelectionWatcher( IEditorSelectionWatcher *watcher ) + { + std::vector< IEditorSelectionWatcher* >::iterator itr = + std::find( selectionWatchers.begin(), selectionWatchers.end(), watcher ); + + // We already have this watcher + if( itr != selectionWatchers.end() ) + return; + + selectionWatchers.push_back( watcher ); + } + + void CWidgetManager::unregisterSelectionWatcher( IEditorSelectionWatcher *watcher ) + { + std::vector< IEditorSelectionWatcher* >::iterator itr = + std::find( selectionWatchers.begin(), selectionWatchers.end(), watcher ); + + // We don't have this watcher + if( itr == selectionWatchers.end() ) + return; + + selectionWatchers.erase( itr ); } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/CMakeLists.txt index 0a5d8533d..63a7d00cc 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/CMakeLists.txt @@ -60,6 +60,8 @@ SET(OVQT_PLUGIN_GUI_EDITOR_HDR nelgui_widget.h new_property_widget.h new_widget_widget.h + editor_selection_watcher.h + editor_message_processor.h ) SET(OVQT_PLUGIN_GUI_EDITOR_UIS diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_message_processor.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_message_processor.cpp new file mode 100644 index 000000000..28cc7d75b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_message_processor.cpp @@ -0,0 +1,58 @@ +// Object Viewer Qt GUI Editor plugin +// 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 +#include "editor_message_processor.h" + +#include "nel/gui/interface_group.h" +#include "nel/gui/widget_manager.h" + +namespace GUIEditor +{ + void CEditorMessageProcessor::onDelete() + { + std::string selection = CWidgetManager::getInstance()->getCurrentEditorSelection(); + 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() ), + 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 ) ) + { + CWidgetManager::getInstance()->setCurrentEditorSelection( "" ); + } + } +} + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_message_processor.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_message_processor.h new file mode 100644 index 000000000..17cac7683 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_message_processor.h @@ -0,0 +1,33 @@ +// Object Viewer Qt GUI Editor plugin +// 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 + +namespace GUIEditor +{ + /// Processes the GUI Editor's editor messages like delete, new, etc... + class CEditorMessageProcessor : public QObject + { + Q_OBJECT + public: + CEditorMessageProcessor( QObject *parent = NULL ) : QObject( parent ){} + ~CEditorMessageProcessor(){} + + public Q_SLOTS: + void onDelete(); + }; +} + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_selection_watcher.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_selection_watcher.cpp new file mode 100644 index 000000000..ee3a079ad --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_selection_watcher.cpp @@ -0,0 +1,26 @@ +// 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 "editor_selection_watcher.h" + +namespace GUIEditor +{ + void CEditorSelectionWatcher::selectionChanged( std::string &newSelection ) + { + Q_EMIT sgnSelectionChanged( newSelection ); + } +} + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_selection_watcher.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_selection_watcher.h new file mode 100644 index 000000000..61218c0cd --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/editor_selection_watcher.h @@ -0,0 +1,36 @@ +// 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/editor_selection_watcher.h" +#include + +namespace GUIEditor +{ + /// Watches the Editor selection, and emits a signal when it changes + class CEditorSelectionWatcher : public QObject, public NLGUI::IEditorSelectionWatcher + { + Q_OBJECT + + public: + CEditorSelectionWatcher() : QObject( NULL ){} + + void selectionChanged( std::string &newSelection ); + + Q_SIGNALS: + void sgnSelectionChanged( std::string &id ); + }; +} + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/gui_editor_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/gui_editor_window.cpp index 5a0aff4de..f84b555d1 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/gui_editor_window.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/gui_editor_window.cpp @@ -41,6 +41,8 @@ #include "project_file_serializer.h" #include "project_window.h" #include "nelgui_widget.h" +#include "editor_selection_watcher.h" +#include "editor_message_processor.h" namespace GUIEditor { @@ -53,6 +55,7 @@ namespace GUIEditor QMainWindow(parent) { m_ui.setupUi(this); + messageProcessor = new CEditorMessageProcessor; m_undoStack = new QUndoStack(this); widgetProps = new CWidgetProperties; linkList = new LinkList; @@ -91,17 +94,16 @@ namespace GUIEditor viewPort->init(); - connect( viewPort, SIGNAL( guiLoadComplete() ), hierarchyView, SLOT( onGUILoaded() ) ); - connect( viewPort, SIGNAL( guiLoadComplete() ), procList, SLOT( onGUILoaded() ) ); - connect( viewPort, SIGNAL( guiLoadComplete() ), linkList, SLOT( onGUILoaded() ) ); - connect( hierarchyView, SIGNAL( selectionChanged( std::string& ) ), - &browserCtrl, SLOT( onSelectionChanged( std::string& ) ) ); + connect( viewPort, SIGNAL( guiLoadComplete() ), this, SLOT( onGUILoaded() ) ); } GUIEditorWindow::~GUIEditorWindow() { writeSettings(); + delete messageProcessor; + messageProcessor = NULL; + delete widgetProps; widgetProps = NULL; @@ -262,6 +264,11 @@ namespace GUIEditor if( reply != QMessageBox::Yes ) return false; + + CEditorSelectionWatcher *w = viewPort->getWatcher(); + disconnect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), hierarchyView, SLOT( onSelectionChanged( std::string& ) ) ); + disconnect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), &browserCtrl, SLOT( onSelectionChanged( std::string& ) ) ); + projectFiles.clearAll(); projectWindow->clear(); hierarchyView->clearHierarchy(); @@ -291,6 +298,16 @@ namespace GUIEditor setCursor( Qt::ArrowCursor ); } + void GUIEditorWindow::onGUILoaded() + { + hierarchyView->onGUILoaded(); + procList->onGUILoaded(); + linkList->onGUILoaded(); + + CEditorSelectionWatcher *w = viewPort->getWatcher(); + connect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), hierarchyView, SLOT( onSelectionChanged( std::string& ) ) ); + connect( w, SIGNAL( sgnSelectionChanged( std::string& ) ), &browserCtrl, SLOT( onSelectionChanged( std::string& ) ) ); + } void GUIEditorWindow::createMenus() { @@ -299,6 +316,7 @@ namespace GUIEditor QAction *saveAction = mm->action( Core::Constants::SAVE ); QAction *saveAsAction = mm->action( Core::Constants::SAVE_AS ); QAction *closeAction = mm->action( Core::Constants::CLOSE ); + QAction *delAction = mm->action( Core::Constants::DEL ); //if( newAction != NULL ) // newAction->setEnabled( true ); @@ -308,6 +326,11 @@ namespace GUIEditor saveAsAction->setEnabled( true ); if( closeAction != NULL ) closeAction->setEnabled( true ); + if( delAction != NULL ) + { + delAction->setEnabled( true ); + connect( delAction, SIGNAL( triggered( bool ) ), messageProcessor, SLOT( onDelete() ) ); + } QMenu *menu = mm->menu( Core::Constants::M_TOOLS ); if( menu != NULL ) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/gui_editor_window.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/gui_editor_window.h index d4327d3d9..37f33e91c 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/gui_editor_window.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/gui_editor_window.h @@ -36,6 +36,7 @@ namespace GUIEditor class ProjectWindow; class NelGUIWidget; class CWidgetInfoTree; + class CEditorMessageProcessor; class GUIEditorWindow: public QMainWindow { @@ -58,6 +59,7 @@ public Q_SLOTS: private Q_SLOTS: void onProjectFilesChanged(); + void onGUILoaded(); private: void createMenus(); @@ -76,8 +78,8 @@ private: ProcList *procList; ProjectWindow *projectWindow; NelGUIWidget *viewPort; - CWidgetInfoTree *widgetInfoTree; + CEditorMessageProcessor *messageProcessor; CPropBrowserCtrl browserCtrl; QString currentProject; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/nelgui_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/nelgui_widget.cpp index 85525e428..d86d31269 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/nelgui_widget.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/nelgui_widget.cpp @@ -27,6 +27,7 @@ #include #include #include +#include "editor_selection_watcher.h" namespace GUIEditor { @@ -37,6 +38,7 @@ namespace GUIEditor { timerID = 0; guiLoaded = false; + watcher = NULL; } NelGUIWidget::~NelGUIWidget() @@ -70,6 +72,8 @@ namespace GUIEditor NLGUI::CViewRenderer::getInstance()->init(); CWidgetManager::getInstance()->getParser()->setEditorMode( true ); + + watcher = new CEditorSelectionWatcher(); } bool NelGUIWidget::parse( SProjectFiles &files ) @@ -106,6 +110,8 @@ namespace GUIEditor guiLoaded = true; Q_EMIT guiLoadComplete(); + CWidgetManager::getInstance()->registerSelectionWatcher( watcher ); + return true; } @@ -115,6 +121,7 @@ namespace GUIEditor if( timerID != 0 ) killTimer( timerID ); timerID = 0; + CWidgetManager::getInstance()->unregisterSelectionWatcher( watcher ); CWidgetManager::getInstance()->reset(); CWidgetManager::getInstance()->getParser()->removeAll(); CViewRenderer::getInstance()->reset(); diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/nelgui_widget.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/nelgui_widget.h index 5a45cc351..34c510507 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/nelgui_widget.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/nelgui_widget.h @@ -23,6 +23,8 @@ namespace GUIEditor { + class CEditorSelectionWatcher; + /// Qt viewport for the Nel GUI library class NelGUIWidget : public Nel3DWidget { @@ -35,6 +37,7 @@ namespace GUIEditor bool parse( SProjectFiles &files ); void draw(); void reset(); + CEditorSelectionWatcher* getWatcher(){ return watcher; } Q_SIGNALS: void guiLoadComplete(); @@ -49,6 +52,7 @@ Q_SIGNALS: private: int timerID; bool guiLoaded; + CEditorSelectionWatcher *watcher; }; } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/property_browser_ctrl.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/property_browser_ctrl.cpp index 1612ea803..3c5fa9177 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/property_browser_ctrl.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/property_browser_ctrl.cpp @@ -78,7 +78,12 @@ namespace GUIEditor CInterfaceElement *e = CWidgetManager::getInstance()->getElementFromId( id ); if( e == NULL ) + { + connect( propertyMgr, SIGNAL( propertyChanged( QtProperty* ) ), + this, SLOT( onPropertyChanged( QtProperty* ) ) ); + return; + } currentElement = id; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/widget_hierarchy.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/widget_hierarchy.cpp index f510d6fb1..2bab73c1e 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/widget_hierarchy.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/widget_hierarchy.cpp @@ -56,6 +56,26 @@ namespace name = s.toUtf8().constData(); return name; } + + class CWidgetDeletionWatcher : public CInterfaceElement::IDeletionWatcher + { + public: + CWidgetDeletionWatcher(){ h = NULL; } + + ~CWidgetDeletionWatcher(){} + + void onDeleted( const std::string &id ){ + if( h != NULL ) + h->onWidgetDeleted( id ); + } + + void setWidgetHierarchy( GUIEditor::WidgetHierarchy *h ){ this->h = h; } + + private: + GUIEditor::WidgetHierarchy *h; + }; + + CWidgetDeletionWatcher deletionWatcher; } namespace GUIEditor @@ -66,6 +86,7 @@ namespace GUIEditor setupUi( this ); connect( widgetHT, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( onItemDblClicked( QTreeWidgetItem* ) ) ); + deletionWatcher.setWidgetHierarchy( this ); } WidgetHierarchy::~WidgetHierarchy() @@ -74,12 +95,15 @@ namespace GUIEditor void WidgetHierarchy::clearHierarchy() { + CInterfaceElement::unregisterDeletionWatcher( &deletionWatcher ); widgetHT->clear(); + widgetHierarchyMap.clear(); } void WidgetHierarchy::buildHierarchy( std::string &masterGroup ) { clearHierarchy(); + CInterfaceElement::registerDeletionWatcher( &deletionWatcher ); CInterfaceGroup *mg = CWidgetManager::getInstance()->getMasterGroupFromId( masterGroup ); if( mg != NULL ) @@ -87,6 +111,7 @@ namespace GUIEditor QTreeWidgetItem *item = new QTreeWidgetItem( NULL ); item->setText( 0, "ui" ); widgetHT->addTopLevelItem( item ); + widgetHierarchyMap[ "ui" ] = item; buildHierarchy( item, mg ); } @@ -96,7 +121,9 @@ namespace GUIEditor { // First add ourselves QTreeWidgetItem *item = new QTreeWidgetItem( parent ); + item->setText( 0, makeNodeName( group->getId() ).c_str() ); + widgetHierarchyMap[ group->getId() ] = item; // Then add recursively our subgroups const std::vector< CInterfaceGroup* > &groups = group->getGroups(); @@ -113,6 +140,7 @@ namespace GUIEditor { QTreeWidgetItem *subItem = new QTreeWidgetItem( item ); subItem->setText( 0, makeNodeName( (*citr)->getId() ).c_str() ); + widgetHierarchyMap[ (*citr)->getId() ] = subItem; } // Add our views @@ -122,14 +150,81 @@ namespace GUIEditor { QTreeWidgetItem *subItem = new QTreeWidgetItem( item ); subItem->setText( 0, makeNodeName( (*vitr)->getId() ).c_str() ); + widgetHierarchyMap[ (*vitr)->getId() ] = subItem; } } + void WidgetHierarchy::onWidgetDeleted( const std::string &id ) + { + std::map< std::string, QTreeWidgetItem* >::iterator itr + = widgetHierarchyMap.find( id ); + if( itr == widgetHierarchyMap.end() ) + return; + + if( widgetHT->currentItem() == itr->second ) + { + QTreeWidgetItem *item = itr->second; + QTreeWidgetItem *p = item; + + // Deselect item + item->setSelected( false ); + widgetHT->setCurrentItem( NULL ); + + // Collapse the tree + while( p != NULL ) + { + p->setExpanded( false ); + p = p->parent(); + } + + currentSelection = ""; + } + + itr->second->setSelected( false ); + + delete itr->second; + itr->second = NULL; + widgetHierarchyMap.erase( itr ); + } + void WidgetHierarchy::onGUILoaded() { if( masterGroup.empty() ) return; buildHierarchy( masterGroup ); + currentSelection.clear(); + } + + void WidgetHierarchy::onSelectionChanged( std::string &newSelection ) + { + if( newSelection == currentSelection ) + return; + + if( newSelection.empty() ) + return; + + std::map< std::string, QTreeWidgetItem* >::iterator itr = + widgetHierarchyMap.find( newSelection ); + if( itr == widgetHierarchyMap.end() ) + return; + + // deselect current item + 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(); + } + + // select the current item + item->setSelected( true ); + widgetHT->setCurrentItem( item ); + currentSelection = newSelection; } void WidgetHierarchy::onItemDblClicked( QTreeWidgetItem *item ) @@ -138,9 +233,7 @@ namespace GUIEditor return; std::string n = item->text( 0 ).toUtf8().constData(); - std::string selection = makeFullName( item, n ); - CWidgetManager::getInstance()->setCurrentEditorSelection( selection ); - - Q_EMIT selectionChanged( selection ); + currentSelection = makeFullName( item, n ); + CWidgetManager::getInstance()->setCurrentEditorSelection( currentSelection ); } } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/widget_hierarchy.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/widget_hierarchy.h index 493fd2a08..6de6b1366 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/widget_hierarchy.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/gui_editor/widget_hierarchy.h @@ -18,6 +18,8 @@ #define WIDGET_HA_H #include "ui_widget_hierarchy.h" +#include +#include namespace NLGUI { @@ -40,11 +42,14 @@ namespace GUIEditor void clearHierarchy(); void buildHierarchy( std::string &masterGroup ); + void onWidgetDeleted( const std::string &id ); + private: void buildHierarchy( QTreeWidgetItem *parent, NLGUI::CInterfaceGroup *group ); public Q_SLOTS: void onGUILoaded(); + void onSelectionChanged( std::string &newSelection ); private Q_SLOTS: void onItemDblClicked( QTreeWidgetItem *item ); @@ -52,9 +57,7 @@ namespace GUIEditor private: std::string currentSelection; std::string masterGroup; - - Q_SIGNALS: - void selectionChanged( std::string &id ); + std::map< std::string, QTreeWidgetItem* > widgetHierarchyMap; }; }