From 94fb323fc5d378f717e074c1e1d1834e0a6dc0ca Mon Sep 17 00:00:00 2001 From: apo Date: Wed, 7 Sep 2005 11:37:27 +0000 Subject: [PATCH] To customize popup actions --- src/VISUGUI/Makefile.in | 1 + src/VISUGUI/VisuGUI_Module.cxx | 148 +++++++++++++++++++++- src/VISUGUI/VisuGUI_Module.h | 18 ++- src/VISUGUI/VisuGUI_PopupTools.cxx | 49 ++++++-- src/VISUGUI/VisuGUI_Prs3dTools.h | 24 ++-- src/VISUGUI/VisuGUI_ViewTools.cxx | 69 +++++++++++ src/VISUGUI/VisuGUI_ViewTools.h | 191 ++++++++++++++++++++++++++--- 7 files changed, 455 insertions(+), 45 deletions(-) create mode 100644 src/VISUGUI/VisuGUI_ViewTools.cxx diff --git a/src/VISUGUI/Makefile.in b/src/VISUGUI/Makefile.in index 72f189c9..0d25f017 100644 --- a/src/VISUGUI/Makefile.in +++ b/src/VISUGUI/Makefile.in @@ -52,6 +52,7 @@ LIB_SRC = VisuGUI.cxx \ VisuGUI_Module.cxx \ VisuGUI_Selection.cxx \ VisuGUI_Tools.cxx \ + VisuGUI_ViewTools.cxx \ VisuGUI_PopupTools.cxx \ VisuGUI_NameDlg.cxx \ VisuGUI_FileDlg.cxx \ diff --git a/src/VISUGUI/VisuGUI_Module.cxx b/src/VISUGUI/VisuGUI_Module.cxx index 47984e5c..5631b2de 100644 --- a/src/VISUGUI/VisuGUI_Module.cxx +++ b/src/VISUGUI/VisuGUI_Module.cxx @@ -227,7 +227,7 @@ VisuGUI_Module this, SLOT(OnDisplayPrs())); mgr->insert( action( GAUSS_DISPLAY_PRS ), -1, -1, -1 ); // display mgr->setRule( action( GAUSS_DISPLAY_PRS ), - aRule + " and ((isVisible=false and isActiveView=true) or (isActiveView=false))", true ); + aRule + " and (isVisible=false)", true ); createAction( GAUSS_DISPLAY_ONLY_PRS, VisuGUI::tr("MEN_DISPLAY_ONLY"), QIconSet(), VisuGUI::tr("MEN_DISPLAY_ONLY"), "", 0, this, false, @@ -235,6 +235,27 @@ VisuGUI_Module mgr->insert( action( GAUSS_DISPLAY_ONLY_PRS ), -1, -1, -1 ); // display only mgr->setRule( action( GAUSS_DISPLAY_ONLY_PRS ), aRule, true ); + + QString aSVTKCompatiblePrs; + aSVTKCompatiblePrs = + "'VISU::TSCALARMAP' " + "'VISU::TISOSURFACE' " + "'VISU::TDEFORMEDSHAPE' " + "'VISU::TCUTPLANES' " + "'VISU::TCUTLINES' " + "'VISU::TVECTORS' " + "'VISU::TSTREAMLINES' " + "'VISU::TPLOT3D'"; + + aRule = + "(client='ObjectBrowser' and selcount>0 and (" + "(type='VISU::TTABLE' and nbChildren>0) or " + "($type in {'VISU::TCURVE' 'VISU::TCONTAINER'}) or " + "$type in {" + aSVTKCompatiblePrs +"} or " + "$type='VISU::TGAUSSPOINTS' " + ")) and (isVisible=false)"; + + mgr->setRule( action( VISU_DISPLAY ), aRule, true ); } //--------------------------------------------------------------- @@ -264,11 +285,12 @@ VisuGUI_Module //--------------------------------------------------------------- -void +SUIT_ViewManager* VisuGUI_Module ::onCreateViewManager() { - new Viewer( this, myViewerMap ); + Viewer* aViewer = new Viewer( this, myViewerMap ); + return aViewer->getViewManager(); } @@ -354,7 +376,7 @@ void VisuGUI_Module ::OnCreateGaussPoints() { - CreatePrs3d(this); + CreatePrs3d(this,true); } void @@ -444,6 +466,23 @@ VisuGUI_Module } } + +//--------------------------------------------------------------- +SUIT_ViewManager* +VisuGUI_Module +::getViewManager(const QString& theType, + const bool theIsCreate) +{ + if(SUIT_ViewManager* aViewManager = VisuGUI::getViewManager(theType,theIsCreate)) + return aViewManager; + + if(theIsCreate && VVTK_Viewer::Type() == theType) + return onCreateViewManager(); + + return NULL; +} + +//--------------------------------------------------------------- void VisuGUI_Module:: OnEditGaussPoints() @@ -451,8 +490,105 @@ OnEditGaussPoints() Handle(SALOME_InteractiveObject) anIO; if(VISU::Prs3d_i* aPrs3d = GetPrsToModify(this,&anIO)){ EditPrs3d(this, aPrs3d); - if(SVTK_ViewWindow* aViewWindow = GetViewWindow()){ - aViewWindow->highlight(anIO, 1); + if(SVTK_ViewWindow* aViewWindow = GetViewWindow(this,true)){ + aViewWindow->highlight(anIO,1); } } } + + +//--------------------------------------------------------------- +void +VisuGUI_Module:: +OnDisplayPrs() +{ + if(MYDEBUG) MESSAGE("VisuGUI_Module::OnDisplayPrs"); + + QApplication::setOverrideCursor(Qt::waitCursor); + + if(SalomeApp_SelectionMgr* aSelectionMgr = GetSelectionMgr(this)){ + SALOME_ListIO aList; + aSelectionMgr->selectedObjects(aList); + for(SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next()){ + Handle(SALOME_InteractiveObject) anIO = it.Value(); + CORBA::Object_var anObject = GetSelectedObj( GetAppStudy(this), anIO->getEntry() ); + + // is it a Prs3d object ? + if(!CORBA::is_nil(anObject)){ + if(VISU::Prs3d_i* aPrs3d = dynamic_cast(VISU::GetServant(anObject).in())){ + if(MYDEBUG) MESSAGE("VisuGUI_Module::OnDisplayPrs : Prs3d object"); + if(aPrs3d->GetType() != VISU::TGAUSSPOINTS) + VISU::UpdateViewer(this,aPrs3d,false,true,true); + else + VISU::UpdateViewer(this,aPrs3d,false,true,true); + continue; + } + } + + // is it Curve ? + if(VISU::Curve_i* aCurve = dynamic_cast(VISU::GetServant(anObject).in())){ + if(MYDEBUG) MESSAGE("VisuGUI_Module::OnDisplayPrs : Curve object"); + PlotCurve( this, aCurve, VISU::eDisplay ); + continue; + } + + // is it Container ? + if(VISU::Container_i* aContainer = dynamic_cast(VISU::GetServant(anObject).in())){ + if(MYDEBUG) MESSAGE("VisuGUI_Module::DisplayPrs : Container object"); + PlotContainer( this, aContainer, VISU::eDisplay ); + continue; + } + + // is it Table ? + if(VISU::Table_i* aTable = dynamic_cast(VISU::GetServant(anObject).in())){ + if(MYDEBUG) MESSAGE("VisuGUI_Module::DisplayPrs : Table object"); + PlotTable( this, aTable, VISU::eDisplay ); + continue; + } + } + } + + QApplication::restoreOverrideCursor(); +} + + +//--------------------------------------------------------------- +void +VisuGUI_Module +::OnEraseAll() +{ + if(SUIT_ViewManager* aViewManager = getApp()->activeViewManager()){ + QString aType = aViewManager->getType(); + if(aType == SVTK_Viewer::Type()) + VISU::OnEraseAll(this); + else if(aType == VVTK_Viewer::Type()) + VISU::OnEraseAll(this); + else if(aType == SPlot2d_Viewer::Type()) + VISU::OnEraseAll(this); + } +} + + +//--------------------------------------------------------------- +void +VisuGUI_Module:: +OnErasePrs() +{ + QApplication::setOverrideCursor(Qt::waitCursor); + + SALOME_ListIO aList; + SalomeApp_SelectionMgr* aSelectionMgr = GetSelectionMgr(this); + aSelectionMgr->selectedObjects(aList); + + for(SALOME_ListIteratorOfListIO it( aList ); it.More(); it.Next()){ + Handle(SALOME_InteractiveObject) anIO = it.Value(); + CORBA::Object_var anObject = GetSelectedObj(GetAppStudy(this),anIO->getEntry()); + if(!CORBA::is_nil(anObject)){ + VISU::Base_var aBase = VISU::Base::_narrow(anObject); + if(!CORBA::is_nil(aBase)) + VISU::ErasePrs(this,aBase,true); + } + } + + QApplication::restoreOverrideCursor(); +} diff --git a/src/VISUGUI/VisuGUI_Module.h b/src/VISUGUI/VisuGUI_Module.h index ecc6c4cf..ee821526 100644 --- a/src/VISUGUI/VisuGUI_Module.h +++ b/src/VISUGUI/VisuGUI_Module.h @@ -71,6 +71,10 @@ public: void preferencesChanged( const QString&, const QString& ); + virtual + SUIT_ViewManager* + getViewManager(const QString& theType, + const bool theIsCreate); public slots: virtual @@ -82,7 +86,7 @@ public slots: activateModule( SUIT_Study* ); protected slots: - void + SUIT_ViewManager* onCreateViewManager(); void @@ -101,6 +105,18 @@ protected slots: void OnEditGaussPoints(); + virtual + void + OnDisplayPrs(); + + virtual + void + OnEraseAll(); + + virtual + void + OnErasePrs(); + protected: VISU::TViewerMap myViewerMap; diff --git a/src/VISUGUI/VisuGUI_PopupTools.cxx b/src/VISUGUI/VisuGUI_PopupTools.cxx index e0f55458..9cdb25ad 100644 --- a/src/VISUGUI/VisuGUI_PopupTools.cxx +++ b/src/VISUGUI/VisuGUI_PopupTools.cxx @@ -26,10 +26,9 @@ // Module : VISU #include "VisuGUI_PopupTools.h" +#include "VisuGUI_ViewTools.h" #include "VisuGUI_Tools.h" -#include "VISU_Actor.h" - using namespace VISU; ////////////////////////////////////////////////// @@ -188,15 +187,47 @@ QString VisuGUI_Selection::nbNamedChildren( const int ind ) const return aResStr; } -QString VisuGUI_Selection::isVisible( const int ind ) const +namespace { - QString aResStr; - - if ( SVTK_ViewWindow* aView = GetViewWindow( myModule ) ) - if ( VISU_Actor* anVISUActor = FindActor( aView, entry( ind ).latin1() ) ) - aResStr = anVISUActor->GetVisibility() ? "1" : "0"; + struct TIsVisibleFunctor + { + template + QString + Get(VisuGUI* theModule, + const QString& theEntry) + { + typedef typename TViewer::TViewWindow TViewWindow; + if(TViewWindow* aViewWindow = GetViewWindow(theModule)) + if(VISU_Actor* anActor = FindActor(aViewWindow,theEntry.latin1())) + return anActor->GetVisibility() ? "1" : "0"; + + return QString(); + } + }; + + template + struct TPopupDispatcher + { + QString + operator()(VisuGUI* theModule, + const QString& theEntry) + { + if(SUIT_ViewManager* aViewManager = theModule->getApp()->activeViewManager()){ + QString aType = aViewManager->getType(); + TPopupFunctor aFunctor; + if(aType == SVTK_Viewer::Type()) + return aFunctor.template Get(theModule,theEntry); + else if(aType == VVTK_Viewer::Type()) + return aFunctor.template Get(theModule,theEntry); + } + return QString(); + } + }; +} - return aResStr; +QString VisuGUI_Selection::isVisible( const int ind ) const +{ + return TPopupDispatcher()((VisuGUI*)myModule,entry(ind)); } QString VisuGUI_Selection::isShrunk( const int ind ) const diff --git a/src/VISUGUI/VisuGUI_Prs3dTools.h b/src/VISUGUI/VisuGUI_Prs3dTools.h index 72f3d95a..a4177ac7 100644 --- a/src/VISUGUI/VisuGUI_Prs3dTools.h +++ b/src/VISUGUI/VisuGUI_Prs3dTools.h @@ -40,7 +40,8 @@ namespace VISU //--------------------------------------------------------------- template void - EditPrs3d (SalomeApp_Module* theModule, VISU::Prs3d_i* thePrs3d) + EditPrs3d(VisuGUI* theModule, + VISU::Prs3d_i* thePrs3d) { TPrs3d_i* aPrsObject = dynamic_cast(thePrs3d); if (aPrsObject) { @@ -72,7 +73,7 @@ namespace VISU //--------------------------------------------------------------- template TPrs3d_i* - CreatePrs3d(SalomeApp_Module* theModule, + CreatePrs3d(VisuGUI* theModule, _PTR(SObject) theTimeStamp, const char* theMeshName, VISU::Entity theEntity, @@ -100,9 +101,10 @@ namespace VISU //--------------------------------------------------------------- template bool - CreatePrs3d(SalomeApp_Module* theModule, + CreatePrs3d(VisuGUI* theModule, _PTR(SObject) theTimeStamp, - const Handle(SALOME_InteractiveObject)& theIO) + const Handle(SALOME_InteractiveObject)& theIO, + const bool theIsCreateView = false) { Storable::TRestoringMap aMap = getMapOfValue(theTimeStamp); @@ -153,7 +155,7 @@ namespace VISU } } } - PublishInView(theModule,aPrs3d); + PublishInView(theModule,aPrs3d,true,theIsCreateView); return true; } @@ -165,7 +167,8 @@ namespace VISU //--------------------------------------------------------------- template void - CreatePrs3d(SalomeApp_Module* theModule) + CreatePrs3d(VisuGUI* theModule, + const bool theIsCreateView = false) { if (CheckLock(GetCStudy(GetAppStudy(theModule)))) return; @@ -175,22 +178,23 @@ namespace VISU if(!CheckTimeStamp(theModule,aTimeStampSObj,&anIO)) return; - if(!CreatePrs3d(theModule,aTimeStampSObj,anIO)) + if(!CreatePrs3d(theModule,aTimeStampSObj,anIO,theIsCreateView)) return; theModule->application()->putInfo(QObject::tr("INF_DONE")); UpdateObjBrowser(theModule); typedef typename TViewer::TViewWindow TView; - if(TView* aView = GetViewWindow(theModule)) + if(TView* aView = GetViewWindow(theModule,theIsCreateView)) aView->onFitAll(); } template void - CreatePrs3d(SalomeApp_Module* theModule) + CreatePrs3d(VisuGUI* theModule, + const bool theIsCreateView = false) { - CreatePrs3d(theModule); + CreatePrs3d(theModule,theIsCreateView); } } diff --git a/src/VISUGUI/VisuGUI_ViewTools.cxx b/src/VISUGUI/VisuGUI_ViewTools.cxx new file mode 100644 index 00000000..bc2650dc --- /dev/null +++ b/src/VISUGUI/VisuGUI_ViewTools.cxx @@ -0,0 +1,69 @@ +// VISU VISUGUI : GUI of VISU component +// +// Copyright (C) 2005 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org +// +// +// +// File : VisuGUI_Tools.cxx +// Author : Sergey Anikin +// Module : VISU + + +#include "VisuGUI_ViewTools.h" + +#include "VISU_Actor.h" + +#include "SVTK_ViewModel.h" +#include "SVTK_ViewWindow.h" + +namespace VISU +{ + void + ErasePrs(VisuGUI* theModule, + VISU::Base_ptr theBase, + bool thIsUpdate) + { + VISU::VISUType aType = theBase->GetType(); + switch (aType) { + case VISU::TCURVE: { + if (VISU::Curve_i* aCurve = dynamic_cast(VISU::GetServant(theBase).in())) + PlotCurve(theModule, aCurve, VISU::eErase ); + break; + } + case VISU::TCONTAINER: { + if (VISU::Container_i* aContainer = dynamic_cast(VISU::GetServant(theBase).in())) + PlotContainer(theModule, aContainer, VISU::eErase ); + break; + } + case VISU::TTABLE: { + if (VISU::Table_i* aTable = dynamic_cast(VISU::GetServant(theBase).in())) + PlotTable(theModule, aTable, VISU::eErase ); + break; + } + default: { + if(VISU::Prs3d_i* aPrsObject = dynamic_cast(VISU::GetServant(theBase).in())){ + if(aType == VISU::TGAUSSPOINTS) + ErasePrs3d(theModule,aPrsObject,thIsUpdate); + else + ErasePrs3d(theModule,aPrsObject,thIsUpdate); + } + }} // switch (aType) + } +} diff --git a/src/VISUGUI/VisuGUI_ViewTools.h b/src/VISUGUI/VisuGUI_ViewTools.h index c4a272c1..fb288f78 100644 --- a/src/VISUGUI/VisuGUI_ViewTools.h +++ b/src/VISUGUI/VisuGUI_ViewTools.h @@ -28,6 +28,8 @@ #ifndef VisuGUI_ViewTools_HeaderFile #define VisuGUI_ViewTools_HeaderFile +#include "VisuGUI.h" + #include "SUIT_MessageBox.h" #include "SUIT_ViewManager.h" #include "SUIT_ViewWindow.h" @@ -37,20 +39,47 @@ #include "VISU_Prs3d_i.hh" +#include "VVTK_ViewModel.h" +#include "VVTK_ViewWindow.h" + +#include "SVTK_ViewModel.h" +#include "SVTK_ViewWindow.h" + +#include "VisuGUI_Tools.h" +#include "VTKViewer_Algorithm.h" +#include "SVTK_Functor.h" + +#include "VISU_Table_i.hh" +#include "VISU_ViewManager_i.hh" +#include "SALOME_ListIO.hxx" +#include "SALOME_ListIteratorOfListIO.hxx" + +#include "SPlot2d_ViewModel.h" + +#include "VISU_Actor.h" + +#include +#include + +class VVTK_Viewer; + namespace VISU { //--------------------------------------------------------------- template + inline typename TViewer::TViewWindow* - GetViewWindow(const SalomeApp_Module* theModule, - const bool theCreate = false) + GetViewWindow(VisuGUI* theModule, + const bool theIsViewCreate = false) { typedef typename TViewer::TViewWindow TView; - if(SalomeApp_Application* anApp = theModule->getApp()){ - if(SUIT_ViewManager* aViewManager = anApp->getViewManager( TViewer::Type(), theCreate )){ - if(SUIT_ViewWindow* aViewWindow = aViewManager->getActiveView()){ - return dynamic_cast(aViewWindow); - } + if(SUIT_ViewManager* aViewManager = theModule->getViewManager(TViewer::Type(),theIsViewCreate)){ + if(SUIT_ViewWindow* aViewWindow = aViewManager->getActiveView()){ + if(TView* aView = dynamic_cast(aViewWindow)){ + aViewWindow->raise(); + aViewWindow->setFocus(); + return aView; + } } } return NULL; @@ -59,31 +88,155 @@ namespace VISU //--------------------------------------------------------------- template + inline VISU_Actor* - PublishInView(const SalomeApp_Module* theModule, - Prs3d_i* thePrs) + PublishInView(VisuGUI* theModule, + Prs3d_i* thePrs, + const bool theIsHighlight = false, + const bool theIsCreateView = false) { - VISU_Actor* aActor = NULL; - - if(!thePrs) - return aActor; - typedef typename TViewer::TViewWindow TView; - if(TView* aView = GetViewWindow(theModule)){ + if(TView* aView = GetViewWindow(theModule,theIsCreateView)){ QApplication::setOverrideCursor( Qt::waitCursor ); try{ - if(aActor = thePrs->CreateActor()) - aView->AddActor(aActor); + if(VISU_Actor* anActor = thePrs->CreateActor()){ + aView->AddActor(anActor); + if(theIsHighlight) + aView->highlight(anActor->getIO(),true); + aView->getRenderer()->ResetCameraClippingRange(); + aView->Repaint(); + QApplication::restoreOverrideCursor(); + return anActor; + } }catch(std::exception& exc){ SUIT_MessageBox::warn1(GetDesktop(theModule), QObject::tr("WRN_VISU"), QObject::tr("ERR_CANT_CREATE_ACTOR"), QObject::tr("BUT_OK")); } - QApplication::restoreOverrideCursor(); } - return aActor; + return NULL; } + + + //--------------------------------------------------------------- + template + inline + VISU_Actor* + UpdateViewer(VisuGUI* theModule, + VISU::Prs3d_i* thePrs, + bool theDispOnly = false, + const bool theIsHighlight = false, + const bool theIsViewCreate = false) + { + typedef typename TViewer::TViewWindow TView; + if(TView* aView = GetViewWindow(theModule,theIsViewCreate)){ + vtkRenderer *aRen = aView->getRenderer(); + vtkActorCollection *anActColl = aRen->GetActors(); + anActColl->InitTraversal(); + VISU_Actor* aResActor = NULL; + while(vtkActor *anAct = anActColl->GetNextActor()){ + if(VISU_Actor* anActor = dynamic_cast(anAct)){ + if(VISU::Prs3d_i* aPrs3d = anActor->GetPrs3d()){ + if(thePrs == aPrs3d){ + aResActor = anActor->GetParent(); + thePrs->UpdateActor(aResActor); + aResActor->VisibilityOn(); + }else if(theDispOnly){ + anActor->GetParent()->VisibilityOff(); + } + }else if(theDispOnly && anActor->GetVisibility()){ + anActor->VisibilityOff(); + } + } + } + if(aResActor){ + if(theIsHighlight) + aView->highlight(aResActor->getIO(),true); + aView->getRenderer()->ResetCameraClippingRange(); + aView->Repaint(); + return aResActor; + } + return PublishInView(theModule,thePrs,theIsHighlight,theIsViewCreate); + } + return NULL; + } + + + //--------------------------------------------------------------- + template + inline + void + OnEraseAll(VisuGUI* theModule) + { + typedef typename TViewer::TViewWindow TViewWindow; + if(TViewWindow* aViewWindow = GetViewWindow(theModule)){ + aViewWindow->unHighlightAll(); + if(vtkRenderer *aRen = aViewWindow->getRenderer()){ + vtkActorCollection *aCollection = aRen->GetActors(); + aCollection->InitTraversal(); + while(vtkActor *anAct = aCollection->GetNextActor()){ + if(anAct->GetVisibility() > 0) + if(VISU_Actor* anActor = dynamic_cast(anAct)){ + anActor = anActor->GetParent(); + anActor->VisibilityOff(); + } + } + aViewWindow->Repaint(); + } + } + } + + template<> + inline + void + OnEraseAll(VisuGUI* theModule) + { + if(SPlot2d_Viewer* aPlot2d = GetPlot2dViewer(theModule,false)) + aPlot2d->EraseAll(); + } + + + //--------------------------------------------------------------- + template + inline + VISU_Actor* + FindActor(TVieweWindow* theViewWindow, + const char* theEntry) + { + using namespace VTK; + if(vtkRenderer* aRenderer = theViewWindow->getRenderer()){ + if(vtkActorCollection* aCollection = aRenderer->GetActors()){ + if(VISU_Actor* anActor = Find(aCollection,TIsSameEntry(theEntry))){ + return anActor->GetParent(); + } + } + } + return NULL; + } + + template + inline + void + ErasePrs3d(VisuGUI* theModule, + VISU::Prs3d_i* thePrs, + const bool thIsUpdate = true) + { + typedef typename TViewer::TViewWindow TViewWindow; + if(TViewWindow* aViewWindow = GetViewWindow(theModule)){ + if(VISU_Actor* anActor = FindActor(aViewWindow,thePrs)){ + anActor->VisibilityOff(); + if(thIsUpdate) + aViewWindow->Repaint(); + } + } + } + + + void + ErasePrs(VisuGUI* theModule, + VISU::Base_ptr theBase, + bool thIsUpdate); } #endif -- 2.39.2