// Created on: 1997-01-17
// Created by: Robert COUBLANC
// Copyright (c) 1997-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <AIS_InteractiveContext.hxx>

#include <AIS_DataMapIteratorOfDataMapOfIOStatus.hxx>
#include <AIS_ConnectedInteractive.hxx>
#include <AIS_GlobalStatus.hxx>
#include <AIS_InteractiveObject.hxx>
#include <AIS_MultipleConnectedInteractive.hxx>
#include <Precision.hxx>
#include <Prs3d_DatumAspect.hxx>
#include <Prs3d_IsoAspect.hxx>
#include <Prs3d_LineAspect.hxx>
#include <Prs3d_PlaneAspect.hxx>
#include <Prs3d_PointAspect.hxx>
#include <Prs3d_ShadingAspect.hxx>
#include <SelectMgr_EntityOwner.hxx>
#include <TColStd_MapIteratorOfMapOfTransient.hxx>
#include <TopLoc_Location.hxx>
#include <V3d_View.hxx>
#include <V3d_Viewer.hxx>

#include <AIS_Shape.hxx>
#include <StdSelect_BRepOwner.hxx>
#include <TopoDS_Shape.hxx>

IMPLEMENT_STANDARD_RTTIEXT(AIS_InteractiveContext, Standard_Transient)

namespace
{
  typedef NCollection_DataMap<Handle(SelectMgr_SelectableObject), Handle(SelectMgr_IndexedMapOfOwner)> AIS_MapOfObjectOwners;
  typedef NCollection_DataMap<Handle(SelectMgr_SelectableObject), Handle(SelectMgr_IndexedMapOfOwner)>::Iterator AIS_MapIteratorOfMapOfObjectOwners;

  //! Initialize default highlighting attributes.
  static void initDefaultHilightAttributes (const Handle(Prs3d_Drawer)& theDrawer,
                                            const Quantity_Color& theColor)
  {
    theDrawer->SetMethod (Aspect_TOHM_COLOR);
    theDrawer->SetDisplayMode (0);
    theDrawer->SetColor (theColor);

    theDrawer->SetupOwnShadingAspect();
    theDrawer->SetupOwnPointAspect();
    theDrawer->SetLineAspect (new Prs3d_LineAspect (Quantity_NOC_BLACK, Aspect_TOL_SOLID, 1.0));
    *theDrawer->LineAspect()->Aspect() = *theDrawer->Link()->LineAspect()->Aspect();
    theDrawer->SetWireAspect (new Prs3d_LineAspect (Quantity_NOC_BLACK, Aspect_TOL_SOLID, 1.0));
    *theDrawer->WireAspect()->Aspect() = *theDrawer->Link()->WireAspect()->Aspect();
    theDrawer->SetPlaneAspect (new Prs3d_PlaneAspect());
    *theDrawer->PlaneAspect()->EdgesAspect() = *theDrawer->Link()->PlaneAspect()->EdgesAspect();
    theDrawer->SetFreeBoundaryAspect   (new Prs3d_LineAspect (Quantity_NOC_BLACK, Aspect_TOL_SOLID, 1.0));
    *theDrawer->FreeBoundaryAspect()->Aspect() = *theDrawer->Link()->FreeBoundaryAspect()->Aspect();
    theDrawer->SetUnFreeBoundaryAspect (new Prs3d_LineAspect (Quantity_NOC_BLACK, Aspect_TOL_SOLID, 1.0));
    *theDrawer->UnFreeBoundaryAspect()->Aspect() = *theDrawer->Link()->UnFreeBoundaryAspect()->Aspect();
    theDrawer->SetDatumAspect (new Prs3d_DatumAspect());

    theDrawer->ShadingAspect()->SetColor (theColor);
    theDrawer->WireAspect()->SetColor (theColor);
    theDrawer->LineAspect()->SetColor (theColor);
    theDrawer->PlaneAspect()->ArrowAspect()->SetColor (theColor);
    theDrawer->PlaneAspect()->IsoAspect()->SetColor (theColor);
    theDrawer->PlaneAspect()->EdgesAspect()->SetColor (theColor);
    theDrawer->FreeBoundaryAspect()->SetColor (theColor);
    theDrawer->UnFreeBoundaryAspect()->SetColor (theColor);
    theDrawer->PointAspect()->SetColor (theColor);
    for (Standard_Integer aPartIter = 0; aPartIter < Prs3d_DatumParts_None; ++aPartIter)
    {
      if (Handle(Prs3d_LineAspect) aLineAsp = theDrawer->DatumAspect()->LineAspect ((Prs3d_DatumParts )aPartIter))
      {
        aLineAsp->SetColor (theColor);
      }
    }

    theDrawer->WireAspect()->SetWidth (2.0);
    theDrawer->LineAspect()->SetWidth (2.0);
    theDrawer->PlaneAspect()->EdgesAspect()->SetWidth (2.0);
    theDrawer->FreeBoundaryAspect()  ->SetWidth (2.0);
    theDrawer->UnFreeBoundaryAspect()->SetWidth (2.0);
    theDrawer->PointAspect()->SetTypeOfMarker (Aspect_TOM_O_POINT);
    theDrawer->PointAspect()->SetScale (2.0);

    // the triangulation should be computed using main presentation attributes,
    // and should not be overridden by highlighting
    theDrawer->SetAutoTriangulation (Standard_False);
  }
}

//=======================================================================
//function : AIS_InteractiveContext
//purpose  : 
//=======================================================================

AIS_InteractiveContext::AIS_InteractiveContext(const Handle(V3d_Viewer)& MainViewer):
myMainPM (new PrsMgr_PresentationManager (MainViewer->StructureManager())),
myMainVwr(MainViewer),
myToHilightSelected(Standard_True),
mySelection(new AIS_Selection()),
myFilters (new SelectMgr_AndOrFilter(SelectMgr_FilterType_OR)),
myDefaultDrawer(new Prs3d_Drawer()),
myCurDetected(0),
myCurHighlighted(0),
myPickingStrategy (SelectMgr_PickingStrategy_FirstAcceptable),
myAutoHilight(Standard_True),
myIsAutoActivateSelMode(Standard_True)
{
  mgrSelector = new SelectMgr_SelectionManager (new StdSelect_ViewerSelector3d());

  myStyles[Prs3d_TypeOfHighlight_None]          = myDefaultDrawer;
  myStyles[Prs3d_TypeOfHighlight_Selected]      = new Prs3d_Drawer();
  myStyles[Prs3d_TypeOfHighlight_Dynamic]       = new Prs3d_Drawer();
  myStyles[Prs3d_TypeOfHighlight_LocalSelected] = new Prs3d_Drawer();
  myStyles[Prs3d_TypeOfHighlight_LocalDynamic]  = new Prs3d_Drawer();
  myStyles[Prs3d_TypeOfHighlight_SubIntensity]  = new Prs3d_Drawer();

  myDefaultDrawer->SetupOwnDefaults();
  myDefaultDrawer->SetZLayer(Graphic3d_ZLayerId_Default);
  myDefaultDrawer->SetDisplayMode(0);
  {
    const Handle(Prs3d_Drawer)& aStyle = myStyles[Prs3d_TypeOfHighlight_Dynamic];
    aStyle->Link (myDefaultDrawer);
    initDefaultHilightAttributes (aStyle, Quantity_NOC_CYAN1);
    aStyle->SetZLayer(Graphic3d_ZLayerId_Top);
  }
  {
    const Handle(Prs3d_Drawer)& aStyle = myStyles[Prs3d_TypeOfHighlight_LocalDynamic];
    aStyle->Link (myDefaultDrawer);
    initDefaultHilightAttributes (aStyle, Quantity_NOC_CYAN1);
    aStyle->SetZLayer(Graphic3d_ZLayerId_Topmost);
  }
  {
    const Handle(Prs3d_Drawer)& aStyle = myStyles[Prs3d_TypeOfHighlight_Selected];
    aStyle->Link (myDefaultDrawer);
    initDefaultHilightAttributes (aStyle, Quantity_NOC_GRAY80);
    aStyle->SetZLayer(Graphic3d_ZLayerId_UNKNOWN);
  }
  {
    const Handle(Prs3d_Drawer)& aStyle = myStyles[Prs3d_TypeOfHighlight_LocalSelected];
    aStyle->Link (myDefaultDrawer);
    initDefaultHilightAttributes (aStyle, Quantity_NOC_GRAY80);
    aStyle->SetZLayer(Graphic3d_ZLayerId_UNKNOWN);
  }
  {
    const Handle(Prs3d_Drawer)& aStyle = myStyles[Prs3d_TypeOfHighlight_SubIntensity];
    aStyle->SetZLayer(Graphic3d_ZLayerId_UNKNOWN);
    aStyle->SetMethod(Aspect_TOHM_COLOR);
    aStyle->SetColor (Quantity_NOC_GRAY40);
  }

  InitAttributes();
}

//=======================================================================
//function : ~AIS_InteractiveContext
//purpose  :
//=======================================================================
AIS_InteractiveContext::~AIS_InteractiveContext()
{
  // clear the current selection
  mySelection->Clear();
  mgrSelector.Nullify();

  Handle(AIS_InteractiveContext) aNullContext;
  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    const Handle(AIS_InteractiveObject)& anObj = anObjIter.Key();
    anObj->SetContext (aNullContext);
    for (SelectMgr_SequenceOfSelection::Iterator aSelIter (anObj->Selections()); aSelIter.More(); aSelIter.Next())
    {
      aSelIter.Value()->UpdateBVHStatus (SelectMgr_TBU_Renew);
    }
  }
}

//=======================================================================
//function : LastActiveView
//purpose  :
//=======================================================================
Handle(V3d_View) AIS_InteractiveContext::LastActiveView() const
{
  if (myLastActiveView == NULL
   || myMainVwr.IsNull())
  {
    return Handle(V3d_View)();
  }

  // as a precaution - check that myLastActiveView pointer is a valid active View
  for (V3d_ListOfViewIterator aViewIter = myMainVwr->ActiveViewIterator(); aViewIter.More(); aViewIter.Next())
  {
    if (aViewIter.Value() == myLastActiveView)
    {
      return aViewIter.Value();
    }
  }
  return Handle(V3d_View)();
}

//=======================================================================
//function : UpdateCurrentViewer
//purpose  : 
//=======================================================================

void AIS_InteractiveContext::UpdateCurrentViewer()
{
  if (!myMainVwr.IsNull())
    myMainVwr->Update();
}

//=======================================================================
//function : DisplayedObjects
//purpose  :
//=======================================================================
void AIS_InteractiveContext::DisplayedObjects (AIS_ListOfInteractive& theListOfIO) const
{
  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    if (anObjIter.Key()->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
    {
      theListOfIO.Append (anObjIter.Key());
    }
  }
}

//=======================================================================
//function : DisplayedObjects
//purpose  :
//=======================================================================
void AIS_InteractiveContext::DisplayedObjects (const AIS_KindOfInteractive theKind,
                                               const Standard_Integer      theSign,
                                               AIS_ListOfInteractive&      theListOfIO) const
{
  ObjectsByDisplayStatus (theKind, theSign, PrsMgr_DisplayStatus_Displayed, theListOfIO);
}

//=======================================================================
//function : ErasedObjects
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ErasedObjects (AIS_ListOfInteractive& theListOfIO) const
{
  ObjectsByDisplayStatus (PrsMgr_DisplayStatus_Erased, theListOfIO);
}

//=======================================================================
//function : ErasedObjects
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ErasedObjects (const AIS_KindOfInteractive theKind,
                                            const Standard_Integer      theSign,
                                            AIS_ListOfInteractive&      theListOfIO) const
{
  ObjectsByDisplayStatus (theKind, theSign, PrsMgr_DisplayStatus_Erased, theListOfIO);
}

//=======================================================================
//function : ObjectsByDisplayStatus
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ObjectsByDisplayStatus (const PrsMgr_DisplayStatus theStatus,
                                                     AIS_ListOfInteractive&  theListOfIO) const
{
  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    if (anObjIter.Key()->DisplayStatus() == theStatus)
    {
      theListOfIO.Append (anObjIter.Key());
    }
  }
}

//=======================================================================
//function : ObjectsByDisplayStatus
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ObjectsByDisplayStatus (const AIS_KindOfInteractive theKind,
                                                     const Standard_Integer      theSign,
                                                     const PrsMgr_DisplayStatus  theStatus,
                                                     AIS_ListOfInteractive&      theListOfIO) const
{
  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    if (theStatus != PrsMgr_DisplayStatus_None
     && anObjIter.Key()->DisplayStatus() != theStatus)
    {
      continue;
    }
    else if (anObjIter.Key()->Type() != theKind)
    {
      continue;
    }

    if (theSign == -1
     || anObjIter.Key()->Signature() == theSign)
    {
      theListOfIO.Append (anObjIter.Key());
    }
  }
}

//=======================================================================
//function : ObjectsInside
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ObjectsInside (AIS_ListOfInteractive&      theListOfIO,
                                            const AIS_KindOfInteractive theKind,
                                            const Standard_Integer      theSign) const
{
  if (theKind == AIS_KindOfInteractive_None
   && theSign == -1)
  {
    for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
    {
      theListOfIO.Append (anObjIter.Key());
    }
    return;
  }

  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    if (anObjIter.Key()->Type() != theKind)
    {
      continue;
    }

    if (theSign == -1
     || anObjIter.Key()->Signature() == theSign)
    {
      theListOfIO.Append (anObjIter.Key());
    }
  }
}

//=======================================================================
//function : ObjectsForView
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ObjectsForView (AIS_ListOfInteractive&  theListOfIO,
                                             const Handle(V3d_View)& theView,
                                             const Standard_Boolean  theIsVisibleInView,
                                             const PrsMgr_DisplayStatus theStatus) const
{
  Handle(Graphic3d_CView) aViewImpl = theView->View();
  const Standard_Integer  aViewId   = aViewImpl->Identification();
  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    if (theStatus != PrsMgr_DisplayStatus_None
     && anObjIter.Key()->DisplayStatus() != theStatus)
    {
      theListOfIO.Append (anObjIter.Key());
      continue;
    }

    Handle(Graphic3d_ViewAffinity) anAffinity = anObjIter.Key()->ViewAffinity();
    const Standard_Boolean isVisible = anAffinity->IsVisible (aViewId);
    if (isVisible == theIsVisibleInView)
    {
      theListOfIO.Append (anObjIter.Key());
    }
  }
}

//=======================================================================
//function : Display
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Display (const Handle(AIS_InteractiveObject)& theIObj,
                                      const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  Standard_Integer aDispMode = 0, aHiMod = -1, aSelMode = -1;
  GetDefModes (theIObj, aDispMode, aHiMod, aSelMode);
  Display (theIObj, aDispMode, myIsAutoActivateSelMode ? aSelMode : -1, theToUpdateViewer);
}

//=======================================================================
//function : SetViewAffinity
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetViewAffinity (const Handle(AIS_InteractiveObject)& theIObj,
                                              const Handle(V3d_View)&              theView,
                                              const Standard_Boolean               theIsVisible)
{
  if (theIObj.IsNull()
  || !myObjects.IsBound (theIObj))
  {
    return;
  }

  Handle(Graphic3d_ViewAffinity) anAffinity = theIObj->ViewAffinity();
  Handle(Graphic3d_CView) aViewImpl = theView->View();
  anAffinity->SetVisible (aViewImpl->Identification(), theIsVisible == Standard_True);
}

//=======================================================================
//function : Display
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Display (const Handle(AIS_InteractiveObject)& theIObj,
                                      const Standard_Integer               theDispMode,
                                      const Standard_Integer               theSelectionMode,
                                      const Standard_Boolean               theToUpdateViewer,
                                      const PrsMgr_DisplayStatus           theDispStatus)
{
  if (theIObj.IsNull())
  {
    return;
  }

  if (theDispStatus == PrsMgr_DisplayStatus_Erased)
  {
    Erase  (theIObj, theToUpdateViewer);
    Load (theIObj, theSelectionMode);
    if (Handle(AIS_GlobalStatus)* aStatusPtr = myObjects.ChangeSeek (theIObj))
    {
      (*aStatusPtr)->SetDisplayMode (theDispMode);
    }
    return;
  }

  setContextToObject (theIObj);
  if (!myObjects.IsBound (theIObj))
  {
    setObjectStatus (theIObj, PrsMgr_DisplayStatus_Displayed, theDispMode, theSelectionMode);
    theIObj->ViewAffinity()->SetVisible (true); // reset view affinity mask
    myMainVwr->StructureManager()->RegisterObject (theIObj, theIObj->ViewAffinity());
    myMainPM->Display(theIObj, theDispMode);
    if (theSelectionMode != -1)
    {
      const Handle(SelectMgr_SelectableObject)& anObj = theIObj; // to avoid ambiguity
      if (!mgrSelector->Contains (anObj))
      {
        mgrSelector->Load (theIObj);
      }
      mgrSelector->Activate (theIObj, theSelectionMode);
    }
  }
  else
  {
    Handle(AIS_GlobalStatus) aStatus = myObjects (theIObj);

    // Mark the presentation modes hidden of interactive object different from aDispMode.
    // Then make sure aDispMode is displayed and maybe highlighted.
    // Finally, activate selection mode <SelMode> if not yet activated.
    const Standard_Integer anOldMode = aStatus->DisplayMode();
    if (anOldMode != theDispMode)
    {
      if(myMainPM->IsHighlighted (theIObj, anOldMode))
      {
        unhighlightGlobal (theIObj);
      }
      myMainPM->SetVisibility (theIObj, anOldMode, Standard_False);
    }

    aStatus->SetDisplayMode (theDispMode);

    theIObj->SetDisplayStatus (PrsMgr_DisplayStatus_Displayed);
    myMainPM->Display (theIObj, theDispMode);
    if (aStatus->IsHilighted())
    {
      highlightGlobal (theIObj, aStatus->HilightStyle(), theDispMode);
    }
    if (theSelectionMode != -1)
    {
      const Handle(SelectMgr_SelectableObject)& anObj = theIObj; // to avoid ambiguity
      if (!mgrSelector->Contains (anObj))
      {
        mgrSelector->Load (theIObj);
      }
      if (!mgrSelector->IsActivated (theIObj, theSelectionMode))
      {
        aStatus->AddSelectionMode (theSelectionMode);
        mgrSelector->Activate (theIObj, theSelectionMode);
      }
    }
  }

  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : Load
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Load (const Handle(AIS_InteractiveObject)& theIObj,
                                   const Standard_Integer               theSelMode)
{
  if (theIObj.IsNull())
  {
    return;
  }

  setContextToObject (theIObj);
  if (!myObjects.IsBound (theIObj))
  {
    Standard_Integer aDispMode, aHiMod, aSelModeDef;
    GetDefModes (theIObj, aDispMode, aHiMod, aSelModeDef);
    setObjectStatus (theIObj, PrsMgr_DisplayStatus_Erased, aDispMode, theSelMode != -1 ? theSelMode : aSelModeDef);
    theIObj->ViewAffinity()->SetVisible (true); // reset view affinity mask
    myMainVwr->StructureManager()->RegisterObject (theIObj, theIObj->ViewAffinity());
  }

  // Register theIObj in the selection manager to prepare further activation of selection
  const Handle(SelectMgr_SelectableObject)& anObj = theIObj; // to avoid ambiguity
  if (!mgrSelector->Contains (anObj))
  {
    mgrSelector->Load (theIObj);
  }
}

//=======================================================================
//function : Erase
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Erase (const Handle(AIS_InteractiveObject)& theIObj,
                                    const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }
  
  if (!theIObj->IsAutoHilight())
  {
    theIObj->ClearSelected();
  }

  EraseGlobal (theIObj, Standard_False);
  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : EraseAll
//purpose  :
//=======================================================================
void AIS_InteractiveContext::EraseAll (const Standard_Boolean theToUpdateViewer)
{
  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    if (anObjIter.Key()->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
    {
      Erase (anObjIter.Key(), Standard_False);
    }
  }

  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : DisplayAll
//purpose  :
//=======================================================================
void AIS_InteractiveContext::DisplayAll (const Standard_Boolean theToUpdateViewer)
{
  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    const PrsMgr_DisplayStatus aStatus = anObjIter.Key()->DisplayStatus();
    if (aStatus == PrsMgr_DisplayStatus_Erased)
    {
      Display (anObjIter.Key(), Standard_False);
    }
  }

  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : DisplaySelected
//purpose  :
//=======================================================================
void AIS_InteractiveContext::DisplaySelected (const Standard_Boolean theToUpdateViewer)
{
  for (AIS_NListOfEntityOwner::Iterator aSelIter (mySelection->Objects()); aSelIter.More(); aSelIter.Next())
  {
    Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (aSelIter.Value()->Selectable());
    Display (anObj, Standard_False);
  }

  if (theToUpdateViewer && !mySelection->Objects().IsEmpty())
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : EraseSelected
//purpose  :
//=======================================================================
void AIS_InteractiveContext::EraseSelected (const Standard_Boolean theToUpdateViewer)
{
  Standard_Boolean isFound = Standard_False;
  for (AIS_NListOfEntityOwner::Iterator aSelIter (mySelection->Objects()); aSelIter.More(); aSelIter.Init (mySelection->Objects()))
  {
    Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (aSelIter.Value()->Selectable());
    Erase (anObj, Standard_False);
    isFound = Standard_True;
  }

  if (isFound && theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : DisplayStatus
//purpose  :
//=======================================================================
PrsMgr_DisplayStatus AIS_InteractiveContext::DisplayStatus (const Handle(AIS_InteractiveObject)& theIObj) const
{
  if (theIObj.IsNull())
  {
    return PrsMgr_DisplayStatus_None;
  }
  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIObj);
  return aStatus != NULL ? theIObj->DisplayStatus() : PrsMgr_DisplayStatus_None;
}

//=======================================================================
//function : Remove
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Remove (const Handle(AIS_InteractiveObject)& theIObj,
                                     const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  if (theIObj->HasInteractiveContext())
  {
    if (theIObj->myCTXPtr != this)
    {
      throw Standard_ProgramError("AIS_InteractiveContext - object has been displayed in another context!");
    }
    theIObj->SetContext (Handle(AIS_InteractiveContext)());
  }
  ClearGlobal (theIObj, theToUpdateViewer);
}

//=======================================================================
//function : RemoveAll
//purpose  :
//=======================================================================
void AIS_InteractiveContext::RemoveAll (const Standard_Boolean theToUpdateViewer)
{
  ClearDetected();

  AIS_ListOfInteractive aList;
  ObjectsInside (aList);
  for (AIS_ListOfInteractive::Iterator aListIterator (aList); aListIterator.More(); aListIterator.Next())
  {
    Remove (aListIterator.Value(), Standard_False);
  }

  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : HilightWithColor
//purpose  : 
//=======================================================================
void AIS_InteractiveContext::HilightWithColor(const Handle(AIS_InteractiveObject)& theObj,
                                              const Handle(Prs3d_Drawer)& theStyle,
                                              const Standard_Boolean theIsToUpdate)
{
  if (theObj.IsNull())
  {
    return;
  }

  setContextToObject (theObj);
  if (!myObjects.IsBound (theObj))
  {
    return;
  }

  const Handle(AIS_GlobalStatus)& aStatus = myObjects (theObj);
  aStatus->SetHilightStatus (Standard_True);

  if (theObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
  {
    highlightGlobal (theObj, theStyle, aStatus->DisplayMode());
    aStatus->SetHilightStyle (theStyle);
  }

  if (theIsToUpdate)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : Unhilight
//purpose  : 
//=======================================================================
void AIS_InteractiveContext::Unhilight (const Handle(AIS_InteractiveObject)& theObj,
                                        const Standard_Boolean theToUpdateViewer)
{
  Handle(AIS_GlobalStatus)* aStatus = !theObj.IsNull() ? myObjects.ChangeSeek (theObj) : NULL;
  if (aStatus == NULL)
  {
    return;
  }

  (*aStatus)->SetHilightStatus (Standard_False);
  (*aStatus)->SetHilightStyle (Handle(Prs3d_Drawer)());
  if (theObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
  {
    unhighlightGlobal (theObj);
  }

  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : IsHilighted
//purpose  : Returns true if the objects global status is set to highlighted.
//=======================================================================
Standard_Boolean AIS_InteractiveContext::IsHilighted (const Handle(AIS_InteractiveObject)& theObj) const
{
  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theObj);
  return aStatus != NULL
      && (*aStatus)->IsHilighted();
}

//=======================================================================
//function : IsHilighted
//purpose  : Returns true if the owner is highlighted with selection style.
//=======================================================================
Standard_Boolean AIS_InteractiveContext::IsHilighted (const Handle(SelectMgr_EntityOwner)& theOwner) const
{
  if (theOwner.IsNull() || !theOwner->HasSelectable())
    return Standard_False;

  const Handle(AIS_InteractiveObject) anObj =
    Handle(AIS_InteractiveObject)::DownCast (theOwner->Selectable());

  if (anObj->GlobalSelOwner() == theOwner)
  {
    if (!myObjects.IsBound (anObj))
      return Standard_False;

    return myObjects (anObj)->IsHilighted();
  }

  const Handle(Prs3d_Drawer)& aStyle = getSelStyle (anObj, theOwner);
  const Standard_Integer aHiMode = getHilightMode (anObj, aStyle, -1);
  return theOwner->IsHilighted (myMainPM, aHiMode);
}

//=======================================================================
//function : HighlightStyle
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::HighlightStyle (const Handle(AIS_InteractiveObject)& theObj,
                                                         Handle(Prs3d_Drawer)& theStyle) const
{
  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theObj);
  if (aStatus != NULL
   && (*aStatus)->IsHilighted())
  {
    theStyle = (*aStatus)->HilightStyle();
    return Standard_True;
  }

  theStyle.Nullify();
  return Standard_False;
}

//=======================================================================
//function : HighlightStyle
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::HighlightStyle (const Handle(SelectMgr_EntityOwner)& theOwner,
                                                         Handle(Prs3d_Drawer)& theStyle) const
{
  if (theOwner.IsNull() || !theOwner->HasSelectable())
    return Standard_False;

  if (IsHilighted (theOwner))
  {
    const Handle(AIS_InteractiveObject) anObj =
      Handle(AIS_InteractiveObject)::DownCast (theOwner->Selectable());
    if (anObj->GlobalSelOwner() == theOwner)
    {
      theStyle = myObjects (anObj)->HilightStyle();
    }
    else
    {
      // since part selection style is not stored in global status,
      // check if the object has own selection style. If not, it can
      // only be highlighted with default selection style (because
      // sub-intensity does not modify any selection states)
      theStyle = getSelStyle (anObj, theOwner);
    }
    return Standard_True;
  }
  else
  {
    theStyle.Nullify();
    return Standard_False;
  }
}

//=======================================================================
//function : IsDisplayed
//purpose  : 
//=======================================================================

Standard_Boolean AIS_InteractiveContext::IsDisplayed(const Handle(AIS_InteractiveObject)& theObj) const 
{
  if(theObj.IsNull()) return Standard_False;

  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theObj);
  return aStatus != NULL
      && theObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed;
}

//=======================================================================
//function : IsDisplayed
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::IsDisplayed (const Handle(AIS_InteractiveObject)& theIObj,
                                                      const Standard_Integer               theMode) const
{
  if (theIObj.IsNull())
  {
    return Standard_False;
  }

  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIObj);
  return aStatus != NULL
      && theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed
      && (*aStatus)->DisplayMode() == theMode;
}

//=======================================================================
//function : DisplayPriority
//purpose  :
//=======================================================================
Graphic3d_DisplayPriority AIS_InteractiveContext::DisplayPriority (const Handle(AIS_InteractiveObject)& theIObj) const
{
  if (theIObj.IsNull())
  {
    return Graphic3d_DisplayPriority_INVALID;
  }

  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIObj);
  if (aStatus != NULL
   && (theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed
    || theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Erased))
  {
    Standard_Integer aDispMode = theIObj->HasDisplayMode()
                               ? theIObj->DisplayMode()
                               : (theIObj->AcceptDisplayMode (myDefaultDrawer->DisplayMode())
                                ? myDefaultDrawer->DisplayMode()
                                : 0);
    return myMainPM->DisplayPriority (theIObj, aDispMode);
  }
  return Graphic3d_DisplayPriority_INVALID;
}

//=======================================================================
//function : SetDisplayPriority
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetDisplayPriority (const Handle(AIS_InteractiveObject)& theIObj,
                                                 const Graphic3d_DisplayPriority      thePriority)
{
  if (theIObj.IsNull())
  {
    return;
  }

  setContextToObject (theIObj);
  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIObj);
  if (aStatus != NULL
   && (theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed
    || theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Erased))
  {
    Standard_Integer aDisplayMode = theIObj->HasDisplayMode()
                                  ? theIObj->DisplayMode()
                                  : (theIObj->AcceptDisplayMode (myDefaultDrawer->DisplayMode())
                                    ? myDefaultDrawer->DisplayMode()
                                    : 0);
    myMainPM->SetDisplayPriority (theIObj, aDisplayMode, thePriority);
  }
}

//=======================================================================
//function : Redisplay
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Redisplay (const Handle(AIS_InteractiveObject)& theIObj,
                                        const Standard_Boolean               theToUpdateViewer,
                                        const Standard_Boolean               theAllModes)
{
  RecomputePrsOnly (theIObj, theToUpdateViewer, theAllModes);
  RecomputeSelectionOnly (theIObj);
}

//=======================================================================
//function : Redisplay
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Redisplay (const AIS_KindOfInteractive theKOI,
                                        const Standard_Integer    /*theSign*/,
                                        const Standard_Boolean      theToUpdateViewer)
{
  Standard_Boolean isRedisplayed = Standard_False;
  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    const Handle(AIS_InteractiveObject)& anObj = anObjIter.Key();
    if (anObj->Type() != theKOI)
    {
      continue;
    }

    Redisplay (anObj, Standard_False);
    isRedisplayed = anObjIter.Key()->DisplayStatus() == PrsMgr_DisplayStatus_Displayed
                 || isRedisplayed;
  }

  if (theToUpdateViewer
   && isRedisplayed)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : RecomputePrsOnly
//purpose  :
//=======================================================================
void AIS_InteractiveContext::RecomputePrsOnly (const Handle(AIS_InteractiveObject)& theIObj,
                                               const Standard_Boolean               theToUpdateViewer,
                                               const Standard_Boolean               theAllModes)
{
  if (theIObj.IsNull())
  {
    return;
  }

  theIObj->SetToUpdate();
  theIObj->UpdatePresentations (theAllModes);
  if (!theToUpdateViewer)
  {
    return;
  }

  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIObj);
  if (aStatus != NULL
   && theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
  {
    myMainVwr->Update();
  }
}
//=======================================================================
//function : RecomputeSelectionOnly
//purpose  : 
//=======================================================================
void AIS_InteractiveContext::RecomputeSelectionOnly (const Handle(AIS_InteractiveObject)& theIO)
{
  if (theIO.IsNull())
  {
    return;
  }

  TColStd_ListOfInteger aModes;
  ActivatedModes (theIO, aModes);

  for (TColStd_ListIteratorOfListOfInteger aModesIter (aModes); aModesIter.More(); aModesIter.Next())
  {
    mgrSelector->Deactivate (theIO, aModesIter.Value());
  }

  mgrSelector->RecomputeSelection (theIO);

  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIO);
  if (aStatus == NULL
   || theIO->DisplayStatus() != PrsMgr_DisplayStatus_Displayed)
  {
    return;
  }

  for (TColStd_ListIteratorOfListOfInteger aModesIter (aModes); aModesIter.More(); aModesIter.Next())
  {
    mgrSelector->Activate (theIO, aModesIter.Value());
  }
}

//=======================================================================
//function : Update
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Update (const Handle(AIS_InteractiveObject)& theIObj,
                                     const Standard_Boolean               theUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  theIObj->UpdatePresentations();
  mgrSelector->Update(theIObj);

  if (theUpdateViewer)
  {
    const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theIObj);
    if (aStatus != NULL
     && theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
    {
      myMainVwr->Update();
    }
  }
}

//=======================================================================
//function : SetLocation
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetLocation (const Handle(AIS_InteractiveObject)& theIObj,
                                          const TopLoc_Location&               theLoc)
{
  if (theIObj.IsNull())
  {
    return;
  }

  if (theIObj->HasTransformation()
   && theLoc.IsIdentity())
  {
    theIObj->ResetTransformation();
    mgrSelector->Update (theIObj, Standard_False);
    return;
  }
  else if (theLoc.IsIdentity())
  {
    return;
  }

  // first reset the previous location to properly clean everything...
  if (theIObj->HasTransformation())
  {
    theIObj->ResetTransformation();
  }

  theIObj->SetLocalTransformation (theLoc.Transformation());

  mgrSelector->Update (theIObj, Standard_False);

  // if the object or its part is highlighted dynamically, it is necessary to apply location transformation
  // to its highlight structure immediately
  if (!myLastPicked.IsNull() && myLastPicked->IsSameSelectable (theIObj))
  {
    const Standard_Integer aHiMod = theIObj->HasHilightMode() ? theIObj->HilightMode() : 0;
    myLastPicked->UpdateHighlightTrsf (myMainVwr,
                                       myMainPM,
                                       aHiMod);
  }
}

//=======================================================================
//function : ResetLocation
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ResetLocation (const Handle(AIS_InteractiveObject)& theIObj)
{
  if (theIObj.IsNull())
  {
    return;
  }

  theIObj->ResetTransformation();
  mgrSelector->Update (theIObj, Standard_False);
}

//=======================================================================
//function : HasLocation
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::HasLocation (const Handle(AIS_InteractiveObject)& theIObj) const
{
  return !theIObj.IsNull()
       && theIObj->HasTransformation();
}

//=======================================================================
//function : Location
//purpose  :
//=======================================================================
TopLoc_Location AIS_InteractiveContext::Location (const Handle(AIS_InteractiveObject)& theIObj) const
{
  return theIObj->Transformation();
}

//=======================================================================
//function : SetDisplayMode
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetDisplayMode(const Standard_Integer theMode,
                                            const Standard_Boolean theToUpdateViewer)
{
  if (theMode == myDefaultDrawer->DisplayMode())
  {
    return;
  }

  for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjIter (myObjects); anObjIter.More(); anObjIter.Next())
  {
    Handle(AIS_InteractiveObject) anObj = anObjIter.Key();
    Standard_Boolean toProcess = anObj->IsKind (STANDARD_TYPE(AIS_Shape))
                              || anObj->IsKind (STANDARD_TYPE(AIS_ConnectedInteractive))
                              || anObj->IsKind (STANDARD_TYPE(AIS_MultipleConnectedInteractive));
    
    if (!toProcess
     ||  anObj->HasDisplayMode()
     || !anObj->AcceptDisplayMode (theMode))
    {
      continue;
    }

    const Handle(AIS_GlobalStatus)& aStatus = anObjIter.Value();
    aStatus->SetDisplayMode (theMode);

    if (anObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
    {
      myMainPM->Display (anObj, theMode);
      if (!myLastPicked.IsNull() && myLastPicked->IsSameSelectable (anObj))
      {
        myMainPM->BeginImmediateDraw();
        unhighlightGlobal (anObj);
        myMainPM->EndImmediateDraw (myMainVwr);
      }
      if (aStatus->IsSubIntensityOn())
      {
        highlightWithSubintensity (anObj, theMode);
      }
      myMainPM->SetVisibility (anObj, myDefaultDrawer->DisplayMode(), Standard_False);
    }
  }

  myDefaultDrawer->SetDisplayMode (theMode);
  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : SetDisplayMode
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetDisplayMode (const Handle(AIS_InteractiveObject)& theIObj,
                                             const Standard_Integer               theMode,
                                             const Standard_Boolean               theToUpdateViewer)
{
  setContextToObject (theIObj);
  if (!myObjects.IsBound (theIObj))
  {
    theIObj->SetDisplayMode (theMode);
    return;
  }
  else if (!theIObj->AcceptDisplayMode (theMode))
  {
    return;
  }

  Handle(AIS_GlobalStatus) aStatus = myObjects (theIObj);
  if (theIObj->DisplayStatus() != PrsMgr_DisplayStatus_Displayed)
  {
    aStatus->SetDisplayMode (theMode);
    theIObj->SetDisplayMode (theMode);
    return;
  }

  // erase presentations for all display modes different from <aMode>
  const Standard_Integer anOldMode = aStatus->DisplayMode();
  if (anOldMode != theMode)
  {
    if (myMainPM->IsHighlighted (theIObj, anOldMode))
    {
      unhighlightGlobal (theIObj);
    }
    myMainPM->SetVisibility (theIObj, anOldMode, Standard_False);
  }

  aStatus->SetDisplayMode (theMode);

  myMainPM->Display (theIObj, theMode);
  if (aStatus->IsHilighted())
  {
    highlightGlobal (theIObj, getSelStyle (theIObj, theIObj->GlobalSelOwner()), theMode);
  }
  if (aStatus->IsSubIntensityOn())
  {
    highlightWithSubintensity (theIObj, theMode);
  }

  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
  theIObj->SetDisplayMode (theMode);
}

//=======================================================================
//function : UnsetDisplayMode
//purpose  :
//=======================================================================
void AIS_InteractiveContext::UnsetDisplayMode (const Handle(AIS_InteractiveObject)& theIObj,
                                               const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull()
  || !theIObj->HasDisplayMode())
  {
    return;
  }

  if (!myObjects.IsBound (theIObj))
  {
    theIObj->UnsetDisplayMode();
    return;
  }

  const Standard_Integer anOldMode = theIObj->DisplayMode();
  if (myDefaultDrawer->DisplayMode() == anOldMode)
  {
    return;
  }

  const Handle(AIS_GlobalStatus)& aStatus = myObjects (theIObj);
  aStatus->SetDisplayMode (myDefaultDrawer->DisplayMode());

  if (theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
  {
    if (myMainPM->IsHighlighted (theIObj, anOldMode))
    {
      unhighlightGlobal (theIObj);
    }
    myMainPM->SetVisibility (theIObj, anOldMode, Standard_False);
    myMainPM->Display (theIObj, myDefaultDrawer->DisplayMode());
    if (aStatus->IsHilighted())
    {
      highlightSelected (theIObj->GlobalSelOwner());
    }
    if (aStatus->IsSubIntensityOn())
    {
      highlightWithSubintensity (theIObj, myDefaultDrawer->DisplayMode());
    }

    if (theToUpdateViewer)
    {
      myMainVwr->Update();
    }
  }

  theIObj->UnsetDisplayMode();
}

//=======================================================================
//function : SetCurrentFacingModel
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetCurrentFacingModel (const Handle(AIS_InteractiveObject)& theIObj,
                                                    const Aspect_TypeOfFacingModel       theModel)
{
  if (!theIObj.IsNull())
  {
    theIObj->SetCurrentFacingModel (theModel);
  }
}

//=======================================================================
//function : SetColor
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetColor (const Handle(AIS_InteractiveObject)& theIObj,
                                       const Quantity_Color&                theColor,
                                       const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  setContextToObject (theIObj);
  theIObj->SetColor (theColor);
  theIObj->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : SetIsoOnTriangulation
//purpose  :
//=======================================================================
void AIS_InteractiveContext::IsoOnTriangulation (const Standard_Boolean theIsEnabled,
                                                 const Handle(AIS_InteractiveObject)& theObject)
{
  if (theObject.IsNull())
  {
    return;
  }

  theObject->SetIsoOnTriangulation (theIsEnabled);
}

//=======================================================================
//function : SetDeviationCoefficient
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetDeviationCoefficient (const Handle(AIS_InteractiveObject)& theIObj,
                                                      const Standard_Real                  theCoefficient,
                                                      const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  // to be modified after the related methods of AIS_Shape are passed to InteractiveObject
  setContextToObject (theIObj);
  if (theIObj->Type() != AIS_KindOfInteractive_Object
   && theIObj->Type() != AIS_KindOfInteractive_Shape)
  {
    return;
  }
  else if (theIObj->Signature() != 0)
  {
    return;
  }

  Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (theIObj);
  aShape->SetOwnDeviationCoefficient (theCoefficient);
  aShape->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : SetDeviationAngle
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetDeviationAngle (const Handle(AIS_InteractiveObject)& theIObj,
                                                const Standard_Real                  theAngle,
                                                const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  // To be modified after the related methods of AIS_Shape are passed to InteractiveObject
  setContextToObject (theIObj);
  if (theIObj->Type() != AIS_KindOfInteractive_Shape)
  {
    return;
  }
  else if (theIObj->Signature() != 0)
  {
    return;
  }

  Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (theIObj);
  aShape->SetOwnDeviationAngle (theAngle);
  aShape->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : SetAngleAndDeviation
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetAngleAndDeviation (const Handle(AIS_InteractiveObject)& theIObj,
                                                   const Standard_Real                  theAngle,
                                                   const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  // To be modified after the related methods of AIS_Shape are passed to InteractiveObject
  setContextToObject (theIObj);
  if (theIObj->Type() != AIS_KindOfInteractive_Shape)
  {
    return;
  }
  if (theIObj->Signature() != 0)
  {
    return;
  }

  Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (theIObj);
  aShape->SetAngleAndDeviation (theAngle);
  aShape->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : UnsetColor
//purpose  :
//=======================================================================
void AIS_InteractiveContext::UnsetColor (const Handle(AIS_InteractiveObject)& theIObj,
                                         const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  theIObj->UnsetColor();
  theIObj->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : HasColor
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::HasColor (const Handle(AIS_InteractiveObject)& theIObj) const
{
  return theIObj->HasColor();
}

//=======================================================================
//function : Color
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Color (const Handle(AIS_InteractiveObject)& theIObj,
                                    Quantity_Color&                      theColor) const
{
  theIObj->Color (theColor);
}

//=======================================================================
//function : Width
//purpose  :
//=======================================================================
Standard_Real AIS_InteractiveContext::Width (const Handle(AIS_InteractiveObject)& theIObj) const
{
  return theIObj->Width();
}

//=======================================================================
//function : SetWidth
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetWidth (const Handle(AIS_InteractiveObject)& theIObj,
                                       const Standard_Real                  theWidth,
                                       const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  setContextToObject (theIObj);
  theIObj->SetWidth (theWidth);
  theIObj->UpdatePresentations();
  if (!myLastPicked.IsNull() && myLastPicked->IsSameSelectable (theIObj))
  {
    if (myLastPicked->IsAutoHilight())
    {
      const Standard_Integer aHiMode = theIObj->HasHilightMode() ? theIObj->HilightMode() : 0;
      myLastPicked->HilightWithColor (myMainPM,
                                      myLastPicked->IsSelected() ? getSelStyle (theIObj, myLastPicked) : getHiStyle (theIObj, myLastPicked),
                                      aHiMode);
    }
    else
    {
      theIObj->HilightOwnerWithColor (myMainPM,
                                      myLastPicked->IsSelected() ? getSelStyle (theIObj, myLastPicked) : getHiStyle (theIObj, myLastPicked),
                                      myLastPicked);
    }
  }
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : UnsetWidth
//purpose  :
//=======================================================================
void AIS_InteractiveContext::UnsetWidth (const Handle(AIS_InteractiveObject)& theIObj,
                                         const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  theIObj->UnsetWidth();
  theIObj->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : SetMaterial
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetMaterial (const Handle(AIS_InteractiveObject)& theIObj,
                                          const Graphic3d_MaterialAspect&      theMaterial,
                                          const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  setContextToObject (theIObj);
  theIObj->SetMaterial (theMaterial);
  theIObj->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : UnsetMaterial
//purpose  :
//=======================================================================
void AIS_InteractiveContext::UnsetMaterial (const Handle(AIS_InteractiveObject)& theIObj,
                                            const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }
  theIObj->UnsetMaterial();
  theIObj->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : SetTransparency
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetTransparency (const Handle(AIS_InteractiveObject)& theIObj,
                                              const Standard_Real                  theValue,
                                              const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  setContextToObject (theIObj);
  if (!theIObj->IsTransparent()
    && theValue <= 0.005)
  {
    return;
  }

  if (theValue <= 0.005)
  {
    UnsetTransparency (theIObj, theToUpdateViewer);
    return;
  }

  theIObj->SetTransparency (theValue);
  theIObj->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : UnsetTransparency
//purpose  :
//=======================================================================
void AIS_InteractiveContext::UnsetTransparency (const Handle(AIS_InteractiveObject)& theIObj,
                                                const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  theIObj->UnsetTransparency();
  theIObj->UpdatePresentations();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : SetSelectedAspect
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetSelectedAspect (const Handle(Prs3d_BasicAspect)& theAspect,
                                                const Standard_Boolean           theToUpdateViewer)
{
  Standard_DISABLE_DEPRECATION_WARNINGS
  Standard_Boolean isFound = Standard_False;
  for (AIS_NListOfEntityOwner::Iterator aSelIter (mySelection->Objects()); aSelIter.More(); aSelIter.Next())
  {
    isFound = Standard_True;
    Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (aSelIter.Value()->Selectable());
    anObj->SetAspect (theAspect);
  }
  Standard_ENABLE_DEPRECATION_WARNINGS

  if (isFound && theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : SetLocalAttributes
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetLocalAttributes (const Handle(AIS_InteractiveObject)& theIObj,
                                                 const Handle(Prs3d_Drawer)&          theDrawer,
                                                 const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  setContextToObject (theIObj);
  theIObj->SetAttributes (theDrawer);
  Update (theIObj, theToUpdateViewer);
}

//=======================================================================
//function : UnsetLocalAttributes
//purpose  :
//=======================================================================
void AIS_InteractiveContext::UnsetLocalAttributes (const Handle(AIS_InteractiveObject)& theIObj,
                                                   const Standard_Boolean               theToUpdateViewer)
{
  if (theIObj.IsNull())
  {
    return;
  }

  setContextToObject (theIObj);
  theIObj->UnsetAttributes();
  Update (theIObj, theToUpdateViewer);
}

//=======================================================================
//function : Status
//purpose  :
//=======================================================================
void AIS_InteractiveContext::Status (const Handle(AIS_InteractiveObject)& theIObj,
                                     TCollection_ExtendedString&          theStatus) const
{
  theStatus = "";
  if (theIObj.IsNull()
  || !myObjects.IsBound (theIObj))
  {
    return;
  }

  theStatus += "\t ____________________________________________";
  theStatus += "\t| Known at Neutral Point:\n\tDisplayStatus:";
  const Handle(AIS_GlobalStatus)& aStatus = myObjects (theIObj);
  switch (theIObj->DisplayStatus())
  {
    case PrsMgr_DisplayStatus_Displayed:
    {
      theStatus += "\t| -->Displayed\n";
      break;
    }
    case PrsMgr_DisplayStatus_Erased:
    {
      theStatus += "\t| -->Erased\n";
      break;
    }
    default:
      break;
  }

  theStatus += "\t| Active Display Modes in the MainViewer :\n";
  theStatus += "\t|\t Mode ";
  theStatus += TCollection_AsciiString (aStatus->DisplayMode());
  theStatus += "\n";

  if (IsSelected(theIObj)) theStatus +="\t| Selected\n";

  theStatus += "\t| Active Selection Modes in the MainViewer :\n";
  for (TColStd_ListIteratorOfListOfInteger aSelModeIter (aStatus->SelectionModes()); aSelModeIter.More(); aSelModeIter.Next())
  {
    theStatus += "\t\t Mode ";
    theStatus += TCollection_AsciiString (aSelModeIter.Value());
    theStatus += "\n";
  }
  theStatus += "\t ____________________________________________";
}

//=======================================================================
//function : GetDefModes
//purpose  :
//=======================================================================
void AIS_InteractiveContext::GetDefModes (const Handle(AIS_InteractiveObject)& theIObj,
                                          Standard_Integer&                    theDispMode,
                                          Standard_Integer&                    theHiMode,
                                          Standard_Integer&                    theSelMode) const
{
  if (theIObj.IsNull())
  {
    return;
  }

  theDispMode = theIObj->HasDisplayMode()
              ? theIObj->DisplayMode()
              : (theIObj->AcceptDisplayMode (myDefaultDrawer->DisplayMode())
               ? myDefaultDrawer->DisplayMode()
               : 0);
  theHiMode  = theIObj->HasHilightMode()   ? theIObj->HilightMode()   : theDispMode;
  theSelMode = theIObj->GlobalSelectionMode();
}

//=======================================================================
//function : EraseGlobal
//purpose  :
//=======================================================================
void AIS_InteractiveContext::EraseGlobal (const Handle(AIS_InteractiveObject)& theIObj,
                                          const Standard_Boolean               theToUpdateviewer)
{
  Handle(AIS_GlobalStatus) aStatus;
  if (theIObj.IsNull()
  || !myObjects.Find (theIObj, aStatus)
  ||  theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Erased)
  {
    return;
  }

  const Standard_Integer aDispMode = theIObj->HasHilightMode() ? theIObj->HilightMode() : 0;
  unselectOwners (theIObj);
  myMainPM->SetVisibility (theIObj, aStatus->DisplayMode(), Standard_False);

  if (!myLastPicked.IsNull()
    && myLastPicked->IsSameSelectable (theIObj))
  {
    clearDynamicHighlight();
  }

  // make sure highlighting presentations are properly erased
  theIObj->ErasePresentations (false);

  if (IsSelected (theIObj)
   && aStatus->DisplayMode() != aDispMode)
  {
    myMainPM->SetVisibility (theIObj, aDispMode, Standard_False);
  }

  for (TColStd_ListIteratorOfListOfInteger aSelModeIter (aStatus->SelectionModes()); aSelModeIter.More(); aSelModeIter.Next())
  {
    mgrSelector->Deactivate (theIObj, aSelModeIter.Value());
  }
  aStatus->ClearSelectionModes();
  theIObj->SetDisplayStatus (PrsMgr_DisplayStatus_Erased);

  if (theToUpdateviewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : unselectOwners
//purpose  :
//=======================================================================
void AIS_InteractiveContext::unselectOwners (const Handle(AIS_InteractiveObject)& theObject)
{
  SelectMgr_SequenceOfOwner aSeq;
  for (AIS_NListOfEntityOwner::Iterator aSelIter (mySelection->Objects()); aSelIter.More(); aSelIter.Next())
  {
    if (aSelIter.Value()->IsSameSelectable (theObject))
    {
      aSeq.Append (aSelIter.Value());
    }
  }
  for (SelectMgr_SequenceOfOwner::Iterator aDelIter (aSeq); aDelIter.More(); aDelIter.Next())
  {
    AddOrRemoveSelected (aDelIter.Value(), Standard_False);
  }
}

//=======================================================================
//function : ClearGlobal
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ClearGlobal (const Handle(AIS_InteractiveObject)& theIObj,
                                          const Standard_Boolean               theToUpdateviewer)
{
  Handle(AIS_GlobalStatus) aStatus;
  if (theIObj.IsNull()
  || !myObjects.Find (theIObj, aStatus))
  {
    // for cases when reference shape of connected interactives was not displayed
    // but its selection primitives were calculated
    const Handle(SelectMgr_SelectableObject)& anObj = theIObj; // to avoid ambiguity
    mgrSelector->Remove (anObj);
    return;
  }

  unselectOwners (theIObj);

  myMainPM->Erase (theIObj, -1);
  theIObj->ErasePresentations (true); // make sure highlighting presentations are properly erased

  // Object removes from Detected sequence
  for (Standard_Integer aDetIter = myDetectedSeq.Lower(); aDetIter <= myDetectedSeq.Upper();)
  {
    Handle(SelectMgr_EntityOwner) aPicked = MainSelector()->Picked (myDetectedSeq (aDetIter));
    Handle(AIS_InteractiveObject) anObj;
    if (!aPicked.IsNull())
    {
      anObj = Handle(AIS_InteractiveObject)::DownCast (aPicked->Selectable());
    }

    if (!anObj.IsNull()
      && anObj == theIObj)
    {
      myDetectedSeq.Remove (aDetIter);
      if (myCurDetected == aDetIter)
      {
        myCurDetected = Min (myDetectedSeq.Upper(), aDetIter);
      }
      if (myCurHighlighted == aDetIter)
      {
        myCurHighlighted = 0;
      }
    }
    else
    {
      aDetIter++;
    }
  }

  // remove IO from the selection manager to avoid memory leaks
  const Handle(SelectMgr_SelectableObject)& anObj = theIObj; // to avoid ambiguity
  mgrSelector->Remove (anObj);

  setObjectStatus (theIObj, PrsMgr_DisplayStatus_None, -1, -1);
  theIObj->ViewAffinity()->SetVisible (true); // reset view affinity mask
  myMainVwr->StructureManager()->UnregisterObject (theIObj);

  if (!myLastPicked.IsNull())
  {
    if (myLastPicked->IsSameSelectable (theIObj))
    {
      clearDynamicHighlight();
      myLastPicked.Nullify();
    }
  }

  if (theToUpdateviewer
   && theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : ClearGlobalPrs
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ClearGlobalPrs (const Handle(AIS_InteractiveObject)& theIObj,
                                             const Standard_Integer               theMode,
                                             const Standard_Boolean               theToUpdateViewer)
{
  const Handle(AIS_GlobalStatus)* aStatus = !theIObj.IsNull() ? myObjects.Seek (theIObj) : NULL;
  if (aStatus == NULL)
  {
    return;
  }

  if ((*aStatus)->DisplayMode() == theMode)
  {
    const Standard_Integer aDispMode = theIObj->HasHilightMode() ? theIObj->HilightMode() : 0;
    if (aDispMode == theMode
     && myMainPM->IsHighlighted (theIObj, theMode))
    {
      unhighlightGlobal (theIObj);
    }

    myMainPM->Erase (theIObj, theMode);
  }

  if (theIObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed
   && theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : ClearDetected
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::ClearDetected (Standard_Boolean theToRedrawImmediate)
{
  myCurDetected = 0;
  myCurHighlighted = 0;
  myDetectedSeq.Clear();
  Standard_Boolean toUpdate = Standard_False;
  if (!myLastPicked.IsNull() && myLastPicked->HasSelectable())
  {
    toUpdate = Standard_True;
    clearDynamicHighlight();
  }
  myLastPicked.Nullify();
  MainSelector()->ClearPicked();
  if (toUpdate && theToRedrawImmediate)
  {
    myMainVwr->RedrawImmediate();
  }
  return toUpdate;
}

//=======================================================================
//function : SetIsoNumber
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetIsoNumber (const Standard_Integer theNb,
                                           const AIS_TypeOfIso    theType)
{
  switch (theType)
  {
    case AIS_TOI_IsoU:
      myDefaultDrawer->UIsoAspect()->SetNumber (theNb);
      break;
    case AIS_TOI_IsoV:
      myDefaultDrawer->VIsoAspect()->SetNumber (theNb);
      break;
    case AIS_TOI_Both:
      myDefaultDrawer->UIsoAspect()->SetNumber (theNb);
      myDefaultDrawer->VIsoAspect()->SetNumber (theNb);
      break;
  }
}

//=======================================================================
//function : IsoNumber
//purpose  :
//=======================================================================
Standard_Integer AIS_InteractiveContext::IsoNumber (const AIS_TypeOfIso theType)
{
  switch (theType)
  {
    case AIS_TOI_IsoU: return myDefaultDrawer->UIsoAspect()->Number();
    case AIS_TOI_IsoV: return myDefaultDrawer->VIsoAspect()->Number();
    case AIS_TOI_Both: return myDefaultDrawer->UIsoAspect()->Number() == myDefaultDrawer->VIsoAspect()->Number()
                            ? myDefaultDrawer->UIsoAspect()->Number()
                            : -1;
  }
  return 0;
}

//=======================================================================
//function : SetPixelTolerance
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetPixelTolerance (const Standard_Integer thePrecision)
{
  MainSelector()->SetPixelTolerance (thePrecision);
}

//=======================================================================
//function : PixelTolerance
//purpose  :
//=======================================================================
Standard_Integer AIS_InteractiveContext::PixelTolerance() const
{
  return MainSelector()->PixelTolerance();
}

//=======================================================================
//function : SetSelectionSensitivity
//purpose  : Allows to manage sensitivity of a particular selection of interactive object theObject
//=======================================================================
void AIS_InteractiveContext::SetSelectionSensitivity (const Handle(AIS_InteractiveObject)& theObject,
                                                      const Standard_Integer theMode,
                                                      const Standard_Integer theNewSensitivity)
{
  mgrSelector->SetSelectionSensitivity (theObject, theMode, theNewSensitivity);
}

//=======================================================================
//function : InitAttributes
//purpose  :
//=======================================================================
void AIS_InteractiveContext::InitAttributes()
{
  Graphic3d_MaterialAspect aMat (Graphic3d_NameOfMaterial_Brass);
  myDefaultDrawer->ShadingAspect()->SetMaterial (aMat);

//  myDefaultDrawer->ShadingAspect()->SetColor(Quantity_NOC_GRAY70);
  Handle(Prs3d_LineAspect) aLineAspect = myDefaultDrawer->HiddenLineAspect();
  aLineAspect->SetColor      (Quantity_NOC_GRAY20);
  aLineAspect->SetWidth      (1.0);
  aLineAspect->SetTypeOfLine (Aspect_TOL_DASH);

  // tolerance to 2 pixels...
  SetPixelTolerance (2);

  // Customizing the drawer for trihedrons and planes...
  Handle(Prs3d_DatumAspect) aTrihAspect = myDefaultDrawer->DatumAspect();
  const Standard_Real aLength = 100.0;
  aTrihAspect->SetAxisLength (aLength, aLength, aLength);
  const Quantity_Color aColor = Quantity_NOC_LIGHTSTEELBLUE4;
  aTrihAspect->LineAspect(Prs3d_DatumParts_XAxis)->SetColor (aColor);
  aTrihAspect->LineAspect(Prs3d_DatumParts_YAxis)->SetColor (aColor);
  aTrihAspect->LineAspect(Prs3d_DatumParts_ZAxis)->SetColor (aColor);

  Handle(Prs3d_PlaneAspect) aPlaneAspect = myDefaultDrawer->PlaneAspect();
  const Standard_Real aPlaneLength = 200.0;
  aPlaneAspect->SetPlaneLength (aPlaneLength, aPlaneLength);
  aPlaneAspect->EdgesAspect()->SetColor (Quantity_NOC_SKYBLUE);
}

//=======================================================================
//function : TrihedronSize
//purpose  :
//=======================================================================
Standard_Real AIS_InteractiveContext::TrihedronSize() const
{
  return myDefaultDrawer->DatumAspect()->AxisLength(Prs3d_DatumParts_XAxis);
}

//=======================================================================
//function : SetTrihedronSize
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetTrihedronSize (const Standard_Real    theVal,
                                               const Standard_Boolean /*updateviewer*/)
{
  myDefaultDrawer->DatumAspect()->SetAxisLength (theVal, theVal, theVal);
  Redisplay (AIS_KindOfInteractive_Datum, 3, Standard_False);
  Redisplay (AIS_KindOfInteractive_Datum, 4, Standard_True);
}

//=======================================================================
//function : SetPlaneSize
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetPlaneSize(const Standard_Real    theValX,
                                          const Standard_Real    theValY,
                                          const Standard_Boolean theToUpdateViewer)
{
  myDefaultDrawer->PlaneAspect()->SetPlaneLength (theValX, theValY);
  Redisplay (AIS_KindOfInteractive_Datum, 7, theToUpdateViewer);
}

//=======================================================================
//function : SetPlaneSize
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetPlaneSize (const Standard_Real    theVal,
                                           const Standard_Boolean theToUpdateViewer)
{
  SetPlaneSize (theVal, theVal, theToUpdateViewer);
}

//=======================================================================
//function : PlaneSize
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::PlaneSize (Standard_Real& theX,
                                                    Standard_Real& theY) const
{
  theX = myDefaultDrawer->PlaneAspect()->PlaneXLength();
  theY = myDefaultDrawer->PlaneAspect()->PlaneYLength();
  return (Abs (theX - theY) <= Precision::Confusion());
}

//=======================================================================
//function : SetZLayer
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetZLayer (const Handle(AIS_InteractiveObject)& theIObj,
                                        const Graphic3d_ZLayerId theLayerId)
{
  if (theIObj.IsNull())
    return;

  theIObj->SetZLayer (theLayerId);
}

//=======================================================================
//function : GetZLayer
//purpose  :
//=======================================================================
Graphic3d_ZLayerId AIS_InteractiveContext::GetZLayer (const Handle(AIS_InteractiveObject)& theIObj) const
{
  return !theIObj.IsNull()
       ?  theIObj->ZLayer()
       :  Graphic3d_ZLayerId_UNKNOWN;
}

//=======================================================================
//function : RebuildSelectionStructs
//purpose  : Rebuilds 1st level of BVH selection forcibly
//=======================================================================
void AIS_InteractiveContext::RebuildSelectionStructs()
{
  MainSelector()->RebuildObjectsTree (Standard_True);
}

//=======================================================================
//function : Disconnect
//purpose  : Disconnects selectable object from an assembly and updates selection structures
//=======================================================================
void AIS_InteractiveContext::Disconnect (const Handle(AIS_InteractiveObject)& theAssembly,
                                         const Handle(AIS_InteractiveObject)& theObjToDisconnect)
{
  if (theAssembly->IsInstance ("AIS_MultipleConnectedInteractive"))
  {
    Handle(AIS_MultipleConnectedInteractive) theObj (Handle(AIS_MultipleConnectedInteractive)::DownCast (theAssembly));
    theObj->Disconnect (theObjToDisconnect);
    if (!myObjects.IsBound (theObjToDisconnect))
    {
      // connected presentation might contain displayed presentations
      myMainPM->Erase (theObjToDisconnect, -1);
      theObjToDisconnect->ErasePresentations (true);
    }

    const Handle(SelectMgr_SelectableObject)& anObj = theObjToDisconnect; // to avoid ambiguity
    mgrSelector->Remove (anObj);
  }
  else if (theAssembly->IsInstance ("AIS_ConnectedInteractive") && theObjToDisconnect.IsNull())
  {
    Handle(AIS_ConnectedInteractive) theObj (Handle(AIS_ConnectedInteractive)::DownCast (theAssembly));
    theObj->Disconnect();
    const Handle(SelectMgr_SelectableObject)& anObj = theObj; // to avoid ambiguity
    mgrSelector->Remove (anObj);
  }
  else
    return;
}

//=======================================================================
//function : FitSelected
//purpose  : Fits the view corresponding to the bounds of selected objects
//=======================================================================
void AIS_InteractiveContext::FitSelected (const Handle(V3d_View)& theView)
{
  FitSelected (theView, 0.01, Standard_True);
}

//=======================================================================
//function : BoundingBoxOfSelection
//purpose  :
//=======================================================================
Bnd_Box AIS_InteractiveContext::BoundingBoxOfSelection (const Handle(V3d_View)& theView) const
{
  Bnd_Box aBndSelected;
  AIS_MapOfObjectOwners anObjectOwnerMap;
  const Standard_Integer aViewId = !theView.IsNull() ? theView->View()->Identification() : -1;
  for (AIS_NListOfEntityOwner::Iterator aSelIter (mySelection->Objects()); aSelIter.More(); aSelIter.Next())
  {
    const Handle(SelectMgr_EntityOwner)& anOwner = aSelIter.Value();
    Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast(anOwner->Selectable());
    if (anObj->IsInfinite())
    {
      continue;
    }

    Handle(Graphic3d_ViewAffinity) anAffinity = anObj->ViewAffinity();
    const Standard_Boolean isVisible = aViewId == -1 || anAffinity->IsVisible (aViewId);
    if (!isVisible)
    {
      continue;
    }

    if (anOwner == anObj->GlobalSelOwner())
    {
      Bnd_Box aTmpBnd;
      anObj->BoundingBox (aTmpBnd);
      aBndSelected.Add (aTmpBnd);
    }
    else
    {
      Handle(SelectMgr_IndexedMapOfOwner) anOwnerMap;
      if (!anObjectOwnerMap.Find (anOwner->Selectable(), anOwnerMap))
      {
        anOwnerMap = new SelectMgr_IndexedMapOfOwner();
        anObjectOwnerMap.Bind (anOwner->Selectable(), anOwnerMap);
      }

      anOwnerMap->Add (anOwner);
    }
  }

  for (AIS_MapIteratorOfMapOfObjectOwners anIter (anObjectOwnerMap); anIter.More(); anIter.Next())
  {
    const Handle(SelectMgr_SelectableObject)& anObject = anIter.Key();
    Bnd_Box aTmpBox = anObject->BndBoxOfSelected (anIter.ChangeValue());
    aBndSelected.Add (aTmpBox);
  }

  return aBndSelected;
}

//=======================================================================
//function : FitSelected
//purpose  : Fits the view corresponding to the bounds of selected objects
//=======================================================================
void AIS_InteractiveContext::FitSelected (const Handle(V3d_View)& theView,
                                          const Standard_Real theMargin,
                                          const Standard_Boolean theToUpdate)
{
  Bnd_Box aBndSelected = BoundingBoxOfSelection (theView);
  if (!aBndSelected.IsVoid())
  {
    theView->FitAll (aBndSelected, theMargin, theToUpdate);
  }
}

//=======================================================================
//function : SetTransformPersistence
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetTransformPersistence (const Handle(AIS_InteractiveObject)& theObject,
                                                      const Handle(Graphic3d_TransformPers)& theTrsfPers)
{
  theObject->SetTransformPersistence (theTrsfPers);
  if (!myObjects.IsBound (theObject))
  {
    return;
  }

  mgrSelector->UpdateSelection (theObject);

  const Graphic3d_ZLayerId  aLayerId   = theObject->ZLayer();
  const Handle(V3d_Viewer)& aCurViewer = CurrentViewer();
  for (V3d_ListOfViewIterator anActiveViewIter (aCurViewer->ActiveViewIterator()); anActiveViewIter.More(); anActiveViewIter.Next())
  {
    anActiveViewIter.Value()->View()->InvalidateBVHData (aLayerId);
    anActiveViewIter.Value()->View()->InvalidateZLayerBoundingBox (aLayerId);
  }
}

//=======================================================================
//function : GravityPoint
//purpose  :
//=======================================================================
gp_Pnt AIS_InteractiveContext::GravityPoint (const Handle(V3d_View)& theView) const
{
  return theView->GravityPoint();
}

//=======================================================================
//function : setContextToObject
//purpose  :
//=======================================================================
void AIS_InteractiveContext::setContextToObject (const Handle(AIS_InteractiveObject)& theObj)
{
  if (theObj->HasInteractiveContext())
  {
    if (theObj->myCTXPtr != this)
    {
      throw Standard_ProgramError("AIS_InteractiveContext - object has been already displayed in another context!");
    }
  }
  else
  {
    theObj->SetContext (this);
  }

  for (PrsMgr_ListOfPresentableObjectsIter aPrsIter (theObj->Children()); aPrsIter.More(); aPrsIter.Next())
  {
    if (Handle(AIS_InteractiveObject) aChild = Handle(AIS_InteractiveObject)::DownCast (aPrsIter.Value()))
    {
      setContextToObject (aChild);
    }
  }
}

//=======================================================================
//function : setObjectStatus
//purpose  :
//=======================================================================
void AIS_InteractiveContext::setObjectStatus (const Handle(AIS_InteractiveObject)& theIObj,
                                              const PrsMgr_DisplayStatus theStatus,
                                              const Standard_Integer theDispMode,
                                              const Standard_Integer theSelectionMode)
{
  theIObj->SetDisplayStatus (theStatus);
  if (theStatus != PrsMgr_DisplayStatus_None)
  {
    Handle(AIS_GlobalStatus) aStatus = new AIS_GlobalStatus();
    aStatus->SetDisplayMode (theDispMode);
    if (theSelectionMode != -1)
    {
      aStatus->AddSelectionMode (theSelectionMode);
    }
    myObjects.Bind (theIObj, aStatus);
  }
  else
  {
    myObjects.UnBind (theIObj);
  }

  for (PrsMgr_ListOfPresentableObjectsIter aPrsIter (theIObj->Children()); aPrsIter.More(); aPrsIter.Next())
  {
    Handle(AIS_InteractiveObject) aChild (Handle(AIS_InteractiveObject)::DownCast (aPrsIter.Value()));
    if (aChild.IsNull())
    {
      continue;
    }

    setObjectStatus (aChild, theStatus, theDispMode, theSelectionMode);
  }
}

//=======================================================================
//function : highlightWithColor
//purpose  :
//=======================================================================
void AIS_InteractiveContext::highlightWithColor (const Handle(SelectMgr_EntityOwner)& theOwner,
                                                 const Handle(V3d_Viewer)& theViewer)
{
  const Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (theOwner->Selectable());
  if (anObj.IsNull())
  {
    return;
  }

  const Handle(Prs3d_Drawer)& aStyle = getHiStyle (anObj, theOwner);
  const Standard_Integer aHiMode = getHilightMode (anObj, aStyle, -1);

  myMainPM->BeginImmediateDraw();
  theOwner->HilightWithColor (myMainPM, aStyle, aHiMode);
  myMainPM->EndImmediateDraw (theViewer.IsNull() ? myMainVwr : theViewer);
}

//=======================================================================
//function : highlightSelected
//purpose  :
//=======================================================================
void AIS_InteractiveContext::highlightSelected (const Handle(SelectMgr_EntityOwner)& theOwner)
{
  AIS_NListOfEntityOwner anOwners;
  const Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (theOwner->Selectable());
  if (anObj.IsNull())
  {
    return;
  }

  if (!theOwner->IsAutoHilight())
  {
    SelectMgr_SequenceOfOwner aSeq;
    for (AIS_NListOfEntityOwner::Iterator aSelIter (mySelection->Objects()); aSelIter.More(); aSelIter.Next())
    {
      if (aSelIter.Value()->IsSameSelectable (anObj))
      {
        anOwners.Append (aSelIter.Value());
      }
    }
  }
  else
  {
    anOwners.Append (theOwner);
  }
  highlightOwners (anOwners, Handle(Prs3d_Drawer)());
}

//=======================================================================
//function : highlightGlobal
//purpose  :
//=======================================================================
void AIS_InteractiveContext::highlightGlobal (const Handle(AIS_InteractiveObject)& theObj,
                                              const Handle(Prs3d_Drawer)& theStyle,
                                              const Standard_Integer theDispMode)
{
  if (theObj.IsNull())
  {
    return;
  }

  const Standard_Integer aHiMode = getHilightMode (theObj, theStyle, theDispMode);
  const Handle(SelectMgr_EntityOwner)& aGlobOwner = theObj->GlobalSelOwner();

  if (aGlobOwner.IsNull())
  {
    myMainPM->Color (theObj, theStyle, aHiMode);
    return;
  }

  AIS_NListOfEntityOwner anOwners;
  if (!aGlobOwner->IsAutoHilight())
  {
    SelectMgr_SequenceOfOwner aSeq;
    for (AIS_NListOfEntityOwner::Iterator aSelIter (mySelection->Objects()); aSelIter.More(); aSelIter.Next())
    {
      if (aSelIter.Value()->IsSameSelectable (theObj))
      {
        anOwners.Append (aSelIter.Value());
      }
    }
  }
  else
  {
    anOwners.Append (aGlobOwner);
  }
  highlightOwners (anOwners, theStyle);
}

//=======================================================================
//function : unhighlightSelected
//purpose  :
//=======================================================================
void AIS_InteractiveContext::unhighlightSelected (const Standard_Boolean theIsToHilightSubIntensity)
{
  unhighlightOwners (mySelection->Objects(), theIsToHilightSubIntensity);
}

//=======================================================================
//function : unhighlightOwners
//purpose  :
//=======================================================================
void AIS_InteractiveContext::unhighlightOwners (const AIS_NListOfEntityOwner& theOwners,
                                                const Standard_Boolean theIsToHilightSubIntensity)
{
  NCollection_IndexedMap<Handle(AIS_InteractiveObject)> anObjToClear;
  for (AIS_NListOfEntityOwner::Iterator aSelIter (theOwners); aSelIter.More(); aSelIter.Next())
  {
    const Handle(SelectMgr_EntityOwner) anOwner = aSelIter.Value();
    const Handle(AIS_InteractiveObject) anInteractive = Handle(AIS_InteractiveObject)::DownCast (anOwner->Selectable());
    Handle(AIS_GlobalStatus)* aStatusPtr = myObjects.ChangeSeek (anInteractive);
    if (!aStatusPtr)
    {
      continue;
    }

    if (anOwner->IsAutoHilight())
    {
      anOwner->Unhilight (myMainPM);
      if (theIsToHilightSubIntensity)
      {
        if ((*aStatusPtr)->IsSubIntensityOn())
        {
          const Standard_Integer aHiMode = getHilightMode (anInteractive, (*aStatusPtr)->HilightStyle(), (*aStatusPtr)->DisplayMode());
          highlightWithSubintensity (anOwner, aHiMode);
        }
      }
    }
    else
    {
      anObjToClear.Add (anInteractive);
    }
    if (anOwner == anInteractive->GlobalSelOwner())
    {
      (*aStatusPtr)->SetHilightStatus (Standard_False);
    }
    (*aStatusPtr)->SetHilightStyle (Handle(Prs3d_Drawer)());
  }
  for (NCollection_IndexedMap<Handle(AIS_InteractiveObject)>::Iterator anIter (anObjToClear); anIter.More(); anIter.Next())
  {
    const Handle(AIS_InteractiveObject)& anObj = anIter.Value();
    myMainPM->Unhighlight (anObj);
    anObj->ClearSelected();
  }
}

//=======================================================================
//function : unhighlightGlobal
//purpose  :
//=======================================================================
void AIS_InteractiveContext::unhighlightGlobal (const Handle(AIS_InteractiveObject)& theObj)
{
  if (theObj.IsNull())
  {
    return;
  }

  const Handle(SelectMgr_EntityOwner)& aGlobOwner = theObj->GlobalSelOwner();
  if (aGlobOwner.IsNull())
  {
    myMainPM->Unhighlight (theObj);
    return;
  }

  AIS_NListOfEntityOwner anOwners;
  anOwners.Append (aGlobOwner);
  unhighlightOwners (anOwners);
}

//=======================================================================
//function : turnOnSubintensity
//purpose  :
//=======================================================================
void AIS_InteractiveContext::turnOnSubintensity (const Handle(AIS_InteractiveObject)& theObject,
                                                 const Standard_Integer theDispMode,
                                                 const Standard_Boolean theIsDisplayedOnly) const
{
  // the only differ with selection highlight is color, so sync transparency values
  const Handle(Prs3d_Drawer)& aSubStyle = myStyles[Prs3d_TypeOfHighlight_SubIntensity];
  aSubStyle->SetTransparency (myStyles[Prs3d_TypeOfHighlight_Selected]->Transparency());

  if (theObject.IsNull())
  {
    for (AIS_DataMapIteratorOfDataMapOfIOStatus anObjsIter (myObjects); anObjsIter.More(); anObjsIter.Next())
    {
      const Handle(AIS_GlobalStatus)& aStatus = anObjsIter.Value();
      if (theObject->DisplayStatus() != PrsMgr_DisplayStatus_Displayed && theIsDisplayedOnly)
      {
        continue;
      }

      aStatus->SetSubIntensity (true);
      myMainPM->Color (anObjsIter.Key(), aSubStyle, theDispMode != -1 ? theDispMode : aStatus->DisplayMode());
    }
  }
  else
  {
    Handle(AIS_GlobalStatus) aStatus;
    if (!myObjects.Find (theObject, aStatus))
    {
      return;
    }

    if (theObject->DisplayStatus() != PrsMgr_DisplayStatus_Displayed && theIsDisplayedOnly)
    {
      return;
    }

    aStatus->SetSubIntensity (true);
    myMainPM->Color (theObject, aSubStyle, theDispMode != -1 ? theDispMode : aStatus->DisplayMode());
  }
}

//=======================================================================
//function : highlightWithSubintensity
//purpose  :
//=======================================================================
void AIS_InteractiveContext::highlightWithSubintensity (const Handle(AIS_InteractiveObject)& theObject,
                                                        const Standard_Integer theMode) const
{
  // the only differ with selection highlight is color, so
  // sync transparency values
  myStyles[Prs3d_TypeOfHighlight_SubIntensity]->SetTransparency (myStyles[Prs3d_TypeOfHighlight_Selected]->Transparency());

  myMainPM->Color (theObject, myStyles[Prs3d_TypeOfHighlight_SubIntensity], theMode);
}

//=======================================================================
//function : highlightWithSubintensity
//purpose  :
//=======================================================================
void AIS_InteractiveContext::highlightWithSubintensity (const Handle(SelectMgr_EntityOwner)& theOwner,
                                                        const Standard_Integer theMode) const
{
  // the only differ with selection highlight is color, so
  // sync transparency values
  myStyles[Prs3d_TypeOfHighlight_SubIntensity]->SetTransparency (myStyles[Prs3d_TypeOfHighlight_Selected]->Transparency());

  theOwner->HilightWithColor (myMainPM, myStyles[Prs3d_TypeOfHighlight_SubIntensity], theMode);
}

//=======================================================================
//function : isSlowHiStyle
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::isSlowHiStyle (const Handle(SelectMgr_EntityOwner)& theOwner,
                                                        const Handle(V3d_Viewer)& theViewer) const
{
  if (const Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (theOwner->Selectable()))
  {
    const Handle(Prs3d_Drawer)& aHiStyle = getHiStyle (anObj, myLastPicked);
    return aHiStyle->ZLayer() == Graphic3d_ZLayerId_UNKNOWN
       || !theViewer->ZLayerSettings (aHiStyle->ZLayer()).IsImmediate();
  }
  return Standard_False;
}

//=======================================================================
//function : MoveTo
//purpose  :
//=======================================================================
AIS_StatusOfDetection AIS_InteractiveContext::MoveTo (const Standard_Integer  theXPix,
                                                      const Standard_Integer  theYPix,
                                                      const Handle(V3d_View)& theView,
                                                      const Standard_Boolean  theToRedrawOnUpdate)
{
  if (theView->Viewer() != myMainVwr)
  {
    throw Standard_ProgramError ("AIS_InteractiveContext::MoveTo() - invalid argument");
  }
  MainSelector()->Pick (theXPix, theYPix, theView);
  return moveTo (theView, theToRedrawOnUpdate);
}

//=======================================================================
//function : MoveTo
//purpose  :
//=======================================================================
AIS_StatusOfDetection AIS_InteractiveContext::MoveTo (const gp_Ax1& theAxis,
                                                      const Handle(V3d_View)& theView,
                                                      const Standard_Boolean  theToRedrawOnUpdate)
{
  if (theView->Viewer() != myMainVwr)
  {
    throw Standard_ProgramError ("AIS_InteractiveContext::MoveTo() - invalid argument");
  }
  MainSelector()->Pick (theAxis, theView);
  return moveTo (theView, theToRedrawOnUpdate);
}

//=======================================================================
//function : moveTo
//purpose  :
//=======================================================================
AIS_StatusOfDetection AIS_InteractiveContext::moveTo (const Handle(V3d_View)& theView,
                                                      const Standard_Boolean  theToRedrawOnUpdate)
{
  myCurDetected = 0;
  myCurHighlighted = 0;
  myDetectedSeq.Clear();
  myLastActiveView = theView.get();

  // preliminaries
  AIS_StatusOfDetection aStatus        = AIS_SOD_Nothing;
  Standard_Boolean      toUpdateViewer = Standard_False;

  // filling of myAISDetectedSeq sequence storing information about detected AIS objects
  // (the objects must be AIS_Shapes)
  const Standard_Integer aDetectedNb = MainSelector()->NbPicked();
  Standard_Integer aNewDetected = 0;
  Standard_Boolean toIgnoreDetTop = Standard_False;
  for (Standard_Integer aDetIter = 1; aDetIter <= aDetectedNb; ++aDetIter)
  {
    Handle(SelectMgr_EntityOwner) anOwner = MainSelector()->Picked (aDetIter);
    if (anOwner.IsNull()
     || !myFilters->IsOk (anOwner))
    {
      if (myPickingStrategy == SelectMgr_PickingStrategy_OnlyTopmost)
      {
        toIgnoreDetTop = Standard_True;
      }
      continue;
    }

    if (aNewDetected < 1
    && !toIgnoreDetTop)
    {
      aNewDetected = aDetIter;
    }

    myDetectedSeq.Append (aDetIter);
  }

  if (aNewDetected >= 1)
  {
    myCurHighlighted = myDetectedSeq.Lower();

    // Does nothing if previously detected object is equal to the current one.
    // However in advanced selection modes the owners comparison
    // is not effective because in that case only one owner manage the
    // selection in current selection mode. It is necessary to check the current detected
    // entity and hilight it only if the detected entity is not the same as
    // previous detected (IsForcedHilight call)
    Handle(SelectMgr_EntityOwner) aNewPickedOwner = MainSelector()->Picked (aNewDetected);
    if (aNewPickedOwner == myLastPicked && !aNewPickedOwner->IsForcedHilight())
    {
      return myLastPicked->IsSelected()
           ? AIS_SOD_Selected
           : AIS_SOD_OnlyOneDetected;
    }

    // Previously detected object is unhilighted if it is not selected or hilighted
    // with selection color if it is selected. Such highlighting with selection color
    // is needed only if myToHilightSelected flag is true. In this case previously detected
    // object has been already highlighted with myHilightColor during previous MoveTo()
    // method call. As result it is necessary to rehighligt it with mySelectionColor.
    if (!myLastPicked.IsNull() && myLastPicked->HasSelectable())
    {
      if (isSlowHiStyle (myLastPicked, theView->Viewer()))
      {
        theView->Viewer()->Invalidate();
      }

      clearDynamicHighlight();
      toUpdateViewer = Standard_True;
    }

    // initialize myLastPicked field with currently detected object
    myLastPicked = aNewPickedOwner;

    // highlight detected object if it is not selected or myToHilightSelected flag is true
    if (myLastPicked->HasSelectable())
    {
      if (myAutoHilight
       && (!myLastPicked->IsSelected()
         || myToHilightSelected))
      {
        if (isSlowHiStyle (myLastPicked, theView->Viewer()))
        {
          theView->Viewer()->Invalidate();
        }

        highlightWithColor (myLastPicked, theView->Viewer());
        toUpdateViewer = Standard_True;
      }

      aStatus = myLastPicked->IsSelected()
              ? AIS_SOD_Selected
              : AIS_SOD_OnlyOneDetected;
    }
  }
  else
  {
    // previously detected object is unhilighted if it is not selected or hilighted
    // with selection color if it is selected
    aStatus = AIS_SOD_Nothing;
    if (myAutoHilight
    && !myLastPicked.IsNull()
     && myLastPicked->HasSelectable())
    {
      if (isSlowHiStyle (myLastPicked, theView->Viewer()))
      {
        theView->Viewer()->Invalidate();
      }

      clearDynamicHighlight();
      toUpdateViewer = Standard_True;
    }

    myLastPicked.Nullify();
  }

  if (toUpdateViewer
   && theToRedrawOnUpdate)
  {
    if (theView->ComputedMode())
    {
      theView->Viewer()->Update();
    }
    else
    {
      if (theView->IsInvalidated())
      {
        theView->Viewer()->Redraw();
      }
      else
      {
        theView->Viewer()->RedrawImmediate();
      }
    }
  }

  return aStatus;
}

//=======================================================================
//function : AddSelect
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::AddSelect (const Handle(SelectMgr_EntityOwner)& theObject)
{
  mySelection->AddSelect (theObject);

  Standard_Integer aSelNum = NbSelected();
  return (aSelNum == 0) ? AIS_SOP_NothingSelected
                        : (aSelNum == 1) ? AIS_SOP_OneSelected
                                         : AIS_SOP_SeveralSelected;
}

//=======================================================================
//function : SelectRectangle
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::SelectRectangle (const Graphic3d_Vec2i&    thePntMin,
                                                          const Graphic3d_Vec2i&    thePntMax,
                                                          const Handle(V3d_View)&   theView,
                                                          const AIS_SelectionScheme theSelScheme)
{
  if (theView->Viewer() != myMainVwr)
  {
    throw Standard_ProgramError ("AIS_InteractiveContext::SelectRectangle() - invalid argument");
  }

  myLastActiveView = theView.get();
  MainSelector()->Pick (thePntMin.x(), thePntMin.y(), thePntMax.x(), thePntMax.y(), theView);

  AIS_NArray1OfEntityOwner aPickedOwners;
  if (MainSelector()->NbPicked() > 0)
  {
    aPickedOwners.Resize (1, MainSelector()->NbPicked(), false);
    for (Standard_Integer aPickIter = 1; aPickIter <= MainSelector()->NbPicked(); ++aPickIter)
    {
      aPickedOwners.SetValue (aPickIter, MainSelector()->Picked (aPickIter));
    }
  }

  return Select (aPickedOwners, theSelScheme);
}

//=======================================================================
//function : SelectPolygon
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::SelectPolygon (const TColgp_Array1OfPnt2d& thePolyline,
                                                        const Handle(V3d_View)&     theView,
                                                        const AIS_SelectionScheme   theSelScheme)
{
  if (theView->Viewer() != myMainVwr)
  {
    throw Standard_ProgramError ("AIS_InteractiveContext::SelectPolygon() - invalid argument");
  }

  myLastActiveView = theView.get();
  MainSelector()->Pick (thePolyline, theView);

  AIS_NArray1OfEntityOwner aPickedOwners;
  if (MainSelector()->NbPicked() > 0)
  {
    aPickedOwners.Resize (1, MainSelector()->NbPicked(), false);
    for (Standard_Integer aPickIter = 1; aPickIter <= MainSelector()->NbPicked(); ++aPickIter)
    {
      aPickedOwners.SetValue (aPickIter, MainSelector()->Picked (aPickIter));
    }
  }

  return Select (aPickedOwners, theSelScheme);
}

//=======================================================================
//function : SelectPoint
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::SelectPoint (const Graphic3d_Vec2i&    thePnt,
                                                      const Handle(V3d_View)&   theView,
                                                      const AIS_SelectionScheme theSelScheme)
{
  if (theView->Viewer() != myMainVwr)
  {
    throw Standard_ProgramError ("AIS_InteractiveContext::SelectPoint() - invalid argument");
  }

  myLastActiveView = theView.get();
  MainSelector()->Pick (thePnt.x(), thePnt.y(), theView);

  AIS_NArray1OfEntityOwner aPickedOwners;
  if (MainSelector()->NbPicked() > 0)
  {
    aPickedOwners.Resize (1, MainSelector()->NbPicked(), false);
    for (Standard_Integer aPickIter = 1; aPickIter <= MainSelector()->NbPicked(); ++aPickIter)
    {
      aPickedOwners.SetValue (aPickIter, MainSelector()->Picked (aPickIter));
    }
  }

  return Select (aPickedOwners, theSelScheme);
}

//=======================================================================
//function : SelectDetected
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::SelectDetected (const AIS_SelectionScheme theSelScheme)
{
  if (theSelScheme == AIS_SelectionScheme_Replace && !myLastPicked.IsNull())
  {
    Graphic3d_Vec2i aMousePos (-1, -1);
    gp_Pnt2d aMouseRealPos = MainSelector()->GetManager().GetMousePosition();
    if (!Precision::IsInfinite (aMouseRealPos.X()) &&
        !Precision::IsInfinite (aMouseRealPos.Y()))
    {
      aMousePos.SetValues ((Standard_Integer )aMouseRealPos.X(), (Standard_Integer )aMouseRealPos.Y());
    }
    if (myLastPicked->HandleMouseClick (aMousePos, Aspect_VKeyMouse_LeftButton, Aspect_VKeyFlags_NONE, false))
    {
      return AIS_SOP_NothingSelected;
    }
  }

  AIS_NArray1OfEntityOwner aPickedOwners (1, 1);
  aPickedOwners.SetValue (1, myLastPicked);
  return Select (aPickedOwners, theSelScheme);
}

//=======================================================================
//function : Select
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::Select (const Standard_Integer  theXPMin,
                                                 const Standard_Integer  theYPMin,
                                                 const Standard_Integer  theXPMax,
                                                 const Standard_Integer  theYPMax,
                                                 const Handle(V3d_View)& theView,
                                                 const Standard_Boolean  theToUpdateViewer)
{
  AIS_StatusOfPick aStatus = SelectRectangle (Graphic3d_Vec2i (theXPMin, theYPMin),
                                              Graphic3d_Vec2i (theXPMax, theYPMax),
                                              theView);
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
  return aStatus;
}

//=======================================================================
//function : Select
//purpose  : Selection by polyline
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::Select (const TColgp_Array1OfPnt2d& thePolyline,
                                                 const Handle(V3d_View)&     theView,
                                                 const Standard_Boolean      theToUpdateViewer)
{
  AIS_StatusOfPick aStatus = SelectPolygon (thePolyline, theView);
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
  return aStatus;
}

//=======================================================================
//function : Select
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::Select (const Standard_Boolean theToUpdateViewer)
{
  AIS_StatusOfPick aStatus = SelectDetected();
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
  return aStatus;
}

//=======================================================================
//function : ShiftSelect
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::ShiftSelect (const Standard_Boolean theToUpdateViewer)
{
  AIS_StatusOfPick aStatus = SelectDetected (AIS_SelectionScheme_XOR);
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
  return aStatus;
}

//=======================================================================
//function : ShiftSelect
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::ShiftSelect (const Standard_Integer theXPMin,
                                                      const Standard_Integer theYPMin,
                                                      const Standard_Integer theXPMax,
                                                      const Standard_Integer theYPMax,
                                                      const Handle(V3d_View)& theView,
                                                      const Standard_Boolean theToUpdateViewer)
{
  AIS_StatusOfPick aStatus = SelectRectangle (Graphic3d_Vec2i (theXPMin, theYPMin),
                                              Graphic3d_Vec2i (theXPMax, theYPMax),
                                              theView,
                                              AIS_SelectionScheme_XOR);
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
  return aStatus;
}

//=======================================================================
//function : ShiftSelect
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::ShiftSelect (const TColgp_Array1OfPnt2d& thePolyline,
                                                      const Handle(V3d_View)& theView,
                                                      const Standard_Boolean theToUpdateViewer)
{
  AIS_StatusOfPick aStatus = SelectPolygon (thePolyline, theView, AIS_SelectionScheme_XOR);
  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
  return aStatus;
}

//=======================================================================
//function : Select
//purpose  :
//=======================================================================
AIS_StatusOfPick AIS_InteractiveContext::Select (const AIS_NArray1OfEntityOwner& theOwners,
                                                 const AIS_SelectionScheme theSelScheme)
{
  NCollection_IndexedMap<Handle(SelectMgr_EntityOwner)> aSelOwnerMap (myAutoHilight ? mySelection->Objects().Size() : 0);
  if (myAutoHilight)
  {
    clearDynamicHighlight();

    // collect currently selected owners
    for (AIS_NListOfEntityOwner::Iterator anOwnerIter (mySelection->Objects()); anOwnerIter.More(); anOwnerIter.Next())
    {
      aSelOwnerMap.Add (anOwnerIter.Value());
    }
  }

  mySelection->SelectOwners (theOwners, theSelScheme, MainSelector()->GetManager().IsOverlapAllowed(), myFilters);

  if (myAutoHilight)
  {
    // collect lists of owners to unhighlight (unselected) and to highlight (selected)
    AIS_NListOfEntityOwner anOwnersToUnhighlight, anOwnersToHighlight;
    for (AIS_NListOfEntityOwner::Iterator anOwnerIter (mySelection->Objects()); anOwnerIter.More(); anOwnerIter.Next())
    {
      // add newly selected owners
      const Handle(SelectMgr_EntityOwner)& anOwner = anOwnerIter.Value();
      if (!aSelOwnerMap.RemoveKey (anOwner))
      {
        // newly selected owner
        anOwnersToHighlight.Append (anOwner);
      }
      else
      {
        // already selected owner
        if (!anOwner->IsAutoHilight()
          && theSelScheme != AIS_SelectionScheme_XOR
          && theSelScheme != AIS_SelectionScheme_Add)
        {
          // hack to perform AIS_InteractiveObject::ClearSelected() before highlighting
          anOwnersToUnhighlight.Append (anOwner);
          anOwnersToHighlight.Append (anOwner);
        }
        else if (anOwner->IsForcedHilight()
             || !anOwner->IsAutoHilight())
        {
          anOwnersToHighlight.Append (anOwner);
        }
      }
    }

    for (NCollection_IndexedMap<Handle(SelectMgr_EntityOwner)>::Iterator anOwnerIter (aSelOwnerMap); anOwnerIter.More(); anOwnerIter.Next())
    {
      // owners removed from selection
      const Handle(SelectMgr_EntityOwner)& anOwner = anOwnerIter.Value();
      anOwnersToUnhighlight.Append (anOwner);
    }

    unhighlightOwners (anOwnersToUnhighlight);
    highlightOwners (anOwnersToHighlight, Handle(Prs3d_Drawer)());
  }

  Standard_Integer aSelNum = NbSelected();
  return (aSelNum == 0) ? AIS_SOP_NothingSelected
                        : (aSelNum == 1) ? AIS_SOP_OneSelected
                                         : AIS_SOP_SeveralSelected;
}

//=======================================================================
//function : HilightSelected
//purpose  :
//=======================================================================
void AIS_InteractiveContext::HilightSelected (const Standard_Boolean theToUpdateViewer)
{
  // In case of selection without using local context
  clearDynamicHighlight();

  highlightOwners (mySelection->Objects(), Handle(Prs3d_Drawer)());

  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : highlightOwners
//purpose  :
//=======================================================================
void AIS_InteractiveContext::highlightOwners (const AIS_NListOfEntityOwner& theOwners,
                                              const Handle(Prs3d_Drawer)& theStyle)
{
  NCollection_DataMap<Handle(AIS_InteractiveObject), NCollection_Handle<SelectMgr_SequenceOfOwner> > anObjOwnerMap;
  for (AIS_NListOfEntityOwner::Iterator aSelIter (theOwners); aSelIter.More(); aSelIter.Next())
  {
    const Handle(SelectMgr_EntityOwner) anOwner = aSelIter.Value();
    const Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (anOwner->Selectable());
    if (anObj.IsNull())
      continue;

    const Handle(Prs3d_Drawer)& anObjSelStyle = !theStyle.IsNull() ? theStyle : getSelStyle (anObj, anOwner);
    Handle(AIS_GlobalStatus)* aStatusPtr = myObjects.ChangeSeek (anObj);
    if (!aStatusPtr)
    {
      continue;
    }
    if (anOwner == anObj->GlobalSelOwner())
    {
      (*aStatusPtr)->SetHilightStatus (Standard_True);
      (*aStatusPtr)->SetHilightStyle (anObjSelStyle);
    }
    if (!anOwner->IsAutoHilight())
    {
      NCollection_Handle<SelectMgr_SequenceOfOwner> aSeq;
      if (anObjOwnerMap.Find (anObj, aSeq))
      {
        aSeq->Append (anOwner);
      }
      else
      {
        aSeq = new SelectMgr_SequenceOfOwner();
        aSeq->Append (anOwner);
        anObjOwnerMap.Bind (anObj, aSeq);
      }
    }
    else
    {
      const Standard_Integer aHiMode = getHilightMode (anObj, anObjSelStyle, (*aStatusPtr)->DisplayMode());
      anOwner->HilightWithColor (myMainPM, anObjSelStyle, aHiMode);
    }
  }

  if (!anObjOwnerMap.IsEmpty())
  {
    for (NCollection_DataMap<Handle(AIS_InteractiveObject), NCollection_Handle<SelectMgr_SequenceOfOwner> >::Iterator anIter (anObjOwnerMap);
         anIter.More(); anIter.Next())
    {
      anIter.Key()->HilightSelected (myMainPM, *anIter.Value());
    }
    anObjOwnerMap.Clear();
  }
}

//=======================================================================
//function : UnhilightSelected
//purpose  :
//=======================================================================
void AIS_InteractiveContext::UnhilightSelected (const Standard_Boolean theToUpdateViewer)
{
  unhighlightSelected();

  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : ClearSelected
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ClearSelected (const Standard_Boolean theToUpdateViewer)
{
  if (NbSelected() == 0)
  {
    return;
  }

  if (myAutoHilight)
  {
    unhighlightSelected();
  }

  mySelection->Clear();
  if (myAutoHilight)
  {
    clearDynamicHighlight();
  }

  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : isDetected
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::isDetected (const Handle(AIS_InteractiveObject)& theObject)
{
  for (Standard_Integer aDetIter = myDetectedSeq.Lower(); aDetIter <= myDetectedSeq.Upper(); aDetIter++)
  {
    Handle(SelectMgr_EntityOwner) aPicked = MainSelector()->Picked(myDetectedSeq(aDetIter));
    Handle(AIS_InteractiveObject) anObj;
    if (!aPicked.IsNull())
    {
      anObj = Handle(AIS_InteractiveObject)::DownCast(aPicked->Selectable());
    }

    if (!anObj.IsNull()
      && anObj == theObject)
    {
      return Standard_True;
    }
  }
  return Standard_False;
}

//=======================================================================
//function : SetSelected
//purpose  : Sets the whole object as selected and highlights it with selection color
//=======================================================================
void AIS_InteractiveContext::SetSelected (const Handle(AIS_InteractiveObject)& theObject,
                                          const Standard_Boolean theToUpdateViewer)
{
  if (theObject.IsNull())
  {
    return;
  }

  if (!myObjects.IsBound (theObject))
  {
    return;
  }

  Handle(SelectMgr_EntityOwner) anOwner = theObject->GlobalSelOwner();
  if (anOwner.IsNull())
  {
    return;
  }

  const Handle(Prs3d_Drawer)& anObjSelStyle = getSelStyle (theObject, anOwner);
  if (NbSelected() == 1 && myObjects (theObject)->IsHilighted() && myAutoHilight)
  {
    Handle(Prs3d_Drawer) aCustomStyle;
    if (HighlightStyle (theObject, aCustomStyle))
    {
      if (!aCustomStyle.IsNull() && anObjSelStyle != aCustomStyle)
      {
        HilightWithColor (theObject, anObjSelStyle, theToUpdateViewer);
      }
    }
    return;
  }

  for (AIS_NListOfEntityOwner::Iterator aSelIter (mySelection->Objects()); aSelIter.More(); aSelIter.Next())
  {
    const Handle(SelectMgr_EntityOwner)& aSelOwner = aSelIter.Value();
    if (!myFilters->IsOk (aSelOwner))
    {
      continue;
    }

    Handle(AIS_InteractiveObject) aSelectable = Handle(AIS_InteractiveObject)::DownCast (aSelOwner->Selectable());
    if (myAutoHilight)
    {
      Unhilight (aSelectable, Standard_False);
    }
    if (aSelOwner == aSelectable->GlobalSelOwner())
    {
      if (Handle(AIS_GlobalStatus)* aStatusPtr = myObjects.ChangeSeek (aSelectable))
      {
        (*aStatusPtr)->SetHilightStatus (Standard_False);
      }
    }
  }

  // added to avoid untimely viewer update...
  const Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (anOwner->Selectable());
  mySelection->ClearAndSelect (anOwner, myFilters, isDetected (anObj));

  if (myAutoHilight)
  {
    Handle(Prs3d_Drawer) aCustomStyle;
    if (HighlightStyle (theObject, aCustomStyle))
    {
      if (!aCustomStyle.IsNull() && anObjSelStyle != aCustomStyle)
      {
        HilightWithColor (theObject, anObjSelStyle, Standard_False);
      }
    }
    else
    {
      HilightWithColor (theObject, anObjSelStyle, Standard_False);
    }
  }

  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : SetSelected
//purpose  : Sets the whole object as selected and highlights it with selection color
//=======================================================================
void AIS_InteractiveContext::SetSelected (const Handle(SelectMgr_EntityOwner)& theOwner,
                                          const Standard_Boolean theToUpdateViewer)
{
  if (theOwner.IsNull() || !theOwner->HasSelectable() || !myFilters->IsOk (theOwner))
  {
    return;
  }

  const Handle(AIS_InteractiveObject) anObject = Handle(AIS_InteractiveObject)::DownCast (theOwner->Selectable());
  const Handle(Prs3d_Drawer)& anObjSelStyle = getSelStyle (anObject, theOwner);
  if (NbSelected() == 1 && theOwner->IsSelected() && !theOwner->IsForcedHilight())
  {
    Handle(Prs3d_Drawer) aCustomStyle;
    if (myAutoHilight && HighlightStyle (theOwner, aCustomStyle))
    {
      if (!aCustomStyle.IsNull() && anObjSelStyle != aCustomStyle)
      {
        const Standard_Integer aHiMode = anObject->HasHilightMode() ? anObject->HilightMode() : 0;
        theOwner->HilightWithColor (myMainPM, anObjSelStyle, aHiMode);
      }
    }
    return;
  }

  if (!myObjects.IsBound (anObject))
  {
    return;
  }

  if (myAutoHilight)
  {
    unhighlightSelected();
  }

  mySelection->ClearAndSelect (theOwner, myFilters, isDetected (anObject));
  if (myAutoHilight)
  {
    Handle(Prs3d_Drawer) aCustomStyle;
    if (!HighlightStyle (theOwner, aCustomStyle) ||
      (!aCustomStyle.IsNull() && aCustomStyle != anObjSelStyle))
    {
      highlightSelected (theOwner);
    }
  }

  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

//=======================================================================
//function : AddOrRemoveSelected
//purpose  :
//=======================================================================
void AIS_InteractiveContext::AddOrRemoveSelected (const Handle(AIS_InteractiveObject)& theObject,
                                                  const Standard_Boolean theToUpdateViewer)
{
  if (theObject.IsNull()
  || !myObjects.IsBound (theObject))
  {
    return;
  }

  const Handle(SelectMgr_EntityOwner) anOwner = theObject->GlobalSelOwner();
  if (!anOwner.IsNull()
    && anOwner->HasSelectable())
  {
    AddOrRemoveSelected (anOwner, theToUpdateViewer);
  }
}

//=======================================================================
//function : AddOrRemoveSelected
//purpose  : Allows to highlight or unhighlight the owner given depending on
//           its selection status
//=======================================================================
void AIS_InteractiveContext::AddOrRemoveSelected (const Handle(SelectMgr_EntityOwner)& theOwner,
                                                  const Standard_Boolean theToUpdateViewer)
{
  if (theOwner.IsNull() || !theOwner->HasSelectable())
  {
    return;
  }

  if (!myFilters->IsOk (theOwner) && !theOwner->IsSelected())
  {
    return;
  }

  AIS_SelectionScheme aSelScheme = theOwner->IsSelected() ? AIS_SelectionScheme_Remove : AIS_SelectionScheme_Add;
  const Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast (theOwner->Selectable());
  mySelection->Select (theOwner, myFilters, aSelScheme, isDetected (anObj));

  if (myAutoHilight)
  {
    Handle(AIS_GlobalStatus)* aStatusPtr = myObjects.ChangeSeek (anObj);
    if (!aStatusPtr)
    {
      return;
    }

    if (theOwner->IsSelected())
    {
      highlightSelected (theOwner);
    }
    else
    {
      AIS_NListOfEntityOwner anOwners;
      anOwners.Append (theOwner);
      unhighlightOwners (anOwners);

      (*aStatusPtr)->SetHilightStyle (Handle(Prs3d_Drawer)());
    }
  }

  if (theToUpdateViewer)
  {
    UpdateCurrentViewer();
  }
}

// =======================================================================
// function : SetSelectedState
// purpose  :
// =======================================================================
Standard_Boolean AIS_InteractiveContext::SetSelectedState (const Handle(SelectMgr_EntityOwner)& theEntity,
                                                           const Standard_Boolean theIsSelected)
{
  if (theEntity.IsNull())
  {
    throw Standard_ProgramError ("Internal error: AIS_InteractiveContext::SetSelectedState() called with NO object");
  }

  if (!theEntity->HasSelectable()
    || mySelection->IsSelected (theEntity) == theIsSelected)
  {
    return false;
  }

  if (theEntity->IsAutoHilight())
  {
    AddOrRemoveSelected (theEntity, false);
    return true;
  }

  if (theIsSelected)
  {
    const AIS_SelectStatus aSelStatus = mySelection->AddSelect (theEntity);
    theEntity->SetSelected (true);
    return aSelStatus == AIS_SS_Added;
  }
  else
  {
    const Handle(AIS_InteractiveObject) anObj = Handle(AIS_InteractiveObject)::DownCast(theEntity->Selectable());
    const AIS_SelectStatus aSelStatus = mySelection->Select (theEntity, myFilters, AIS_SelectionScheme_Remove, isDetected (anObj));
    theEntity->SetSelected (false);
    return aSelStatus == AIS_SS_Removed;
  }
}

//=======================================================================
//function : IsSelected
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::IsSelected (const Handle(AIS_InteractiveObject)& theObj) const
{
  if (theObj.IsNull())
  {
    return Standard_False;
  }

  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theObj);
  if (aStatus == NULL)
  {
    return Standard_False;
  }

  const Standard_Integer aGlobalSelMode = theObj->GlobalSelectionMode();
  const TColStd_ListOfInteger& anActivatedModes = (*aStatus)->SelectionModes();
  for (TColStd_ListIteratorOfListOfInteger aModeIter (anActivatedModes); aModeIter.More(); aModeIter.Next())
  {
    if (aModeIter.Value() == aGlobalSelMode)
    {
      if (Handle(SelectMgr_EntityOwner) aGlobOwner = theObj->GlobalSelOwner())
      {
        return aGlobOwner->IsSelected();
      }
      return Standard_False;
    }
  }
  return Standard_False;
}

//=======================================================================
//function : FirstSelectedObject
//purpose  :
//=======================================================================
Handle(AIS_InteractiveObject) AIS_InteractiveContext::FirstSelectedObject() const
{
  return !mySelection->Objects().IsEmpty()
        ? Handle(AIS_InteractiveObject)::DownCast (mySelection->Objects().First()->Selectable())
        : Handle(AIS_InteractiveObject)();
}

//=======================================================================
//function : HasSelectedShape
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::HasSelectedShape() const
{
  if (!mySelection->More())
  {
    return Standard_False;
  }

  const Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast (mySelection->Value());
  return !anOwner.IsNull() && anOwner->HasShape();
}

//=======================================================================
//function : SelectedShape
//purpose  :
//=======================================================================
TopoDS_Shape AIS_InteractiveContext::SelectedShape() const
{
  if (!mySelection->More())
  {
    return TopoDS_Shape();
  }

  const Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast (mySelection->Value());
  if (anOwner.IsNull() || !anOwner->HasSelectable())
  {
    return TopoDS_Shape();
  }

  return anOwner->Shape().Located (anOwner->Location() * anOwner->Shape().Location());
}

//=======================================================================
//function : EntityOwners
//purpose  :
//=======================================================================
void AIS_InteractiveContext::EntityOwners (Handle(SelectMgr_IndexedMapOfOwner)& theOwners,
                                           const Handle(AIS_InteractiveObject)& theIObj,
                                           const Standard_Integer theMode) const
{
  if (theIObj.IsNull())
  {
    return;
  }

  TColStd_ListOfInteger aModes;
  if (theMode == -1)
  {
    ActivatedModes (theIObj, aModes);
  }
  else
  {
    aModes.Append (theMode);
  }

  if (theOwners.IsNull())
  {
    theOwners = new SelectMgr_IndexedMapOfOwner();
  }

  for (TColStd_ListIteratorOfListOfInteger anItr (aModes); anItr.More(); anItr.Next())
  {
    const int aMode = anItr.Value();
    const Handle(SelectMgr_Selection)& aSel = theIObj->Selection (aMode);
    if (aSel.IsNull())
    {
      continue;
    }

    for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (aSel->Entities()); aSelEntIter.More(); aSelEntIter.Next())
    {
      if (Handle(Select3D_SensitiveEntity) aEntity = aSelEntIter.Value()->BaseSensitive())
      {
        if (const Handle(SelectMgr_EntityOwner)& aOwner = aEntity->OwnerId())
        {
          theOwners->Add (aOwner);
        }
      }
    }
  }
}

//=======================================================================
//function : HasDetectedShape
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::HasDetectedShape() const
{
  Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast (myLastPicked);
  return !anOwner.IsNull()
       && anOwner->HasShape();
}

//=======================================================================
//function : DetectedShape
//purpose  :
//=======================================================================
const TopoDS_Shape& AIS_InteractiveContext::DetectedShape() const
{
  Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast (myLastPicked);
  return anOwner->Shape();
}

//=======================================================================
//function : HilightNextDetected
//purpose  :
//=======================================================================
Standard_Integer AIS_InteractiveContext::HilightNextDetected (const Handle(V3d_View)& theView,
                                                              const Standard_Boolean  theToRedrawImmediate)
{
  myMainPM->ClearImmediateDraw();
  if (myDetectedSeq.IsEmpty())
  {
    return 0;
  }

  if (++myCurHighlighted > myDetectedSeq.Upper())
  {
    myCurHighlighted = myDetectedSeq.Lower();
  }
  const Handle(SelectMgr_EntityOwner)& anOwner = MainSelector()->Picked (myDetectedSeq (myCurHighlighted));
  if (anOwner.IsNull())
  {
    return 0;
  }

  highlightWithColor (anOwner, theView->Viewer());
  myLastPicked = anOwner;

  if (theToRedrawImmediate)
  {
    myMainPM->RedrawImmediate (theView->Viewer());
    myMainVwr->RedrawImmediate();
  }

  return myCurHighlighted;
}

//=======================================================================
//function : HilightPreviousDetected
//purpose  :
//=======================================================================
Standard_Integer AIS_InteractiveContext::HilightPreviousDetected (const Handle(V3d_View)& theView,
                                                                  const Standard_Boolean  theToRedrawImmediate)
{
  myMainPM->ClearImmediateDraw();
  if (myDetectedSeq.IsEmpty())
  {
    return 0;
  }

  if (--myCurHighlighted < myDetectedSeq.Lower())
  {
    myCurHighlighted = myDetectedSeq.Upper();
  }
  const Handle(SelectMgr_EntityOwner)& anOwner = MainSelector()->Picked (myDetectedSeq (myCurHighlighted));
  if (anOwner.IsNull())
  {
    return 0;
  }

  highlightWithColor (anOwner, theView->Viewer());
  myLastPicked = anOwner;

  if (theToRedrawImmediate)
  {
    myMainPM->RedrawImmediate (theView->Viewer());
    myMainVwr->RedrawImmediate();
  }

  return myCurHighlighted;
}

//=======================================================================
//function : DetectedCurrentOwner
//purpose  :
//=======================================================================
Handle(SelectMgr_EntityOwner) AIS_InteractiveContext::DetectedCurrentOwner() const
{
  return MoreDetected()
       ? MainSelector()->Picked (myDetectedSeq (myCurDetected))
       : Handle(SelectMgr_EntityOwner)();
}

//=======================================================================
//function : DetectedCurrentShape
//purpose  :
//=======================================================================
const TopoDS_Shape& AIS_InteractiveContext::DetectedCurrentShape() const
{
  static const TopoDS_Shape AIS_InteractiveContext_myDummyShape;

  Standard_DISABLE_DEPRECATION_WARNINGS
  Handle(AIS_Shape) aCurrentShape = Handle(AIS_Shape)::DownCast (DetectedCurrentObject());
  Standard_ENABLE_DEPRECATION_WARNINGS
  return !aCurrentShape.IsNull()
        ? aCurrentShape->Shape()
        : AIS_InteractiveContext_myDummyShape;
}

//=======================================================================
//function : DetectedCurrentObject
//purpose  :
//=======================================================================
Handle(AIS_InteractiveObject) AIS_InteractiveContext::DetectedCurrentObject() const
{
  return MoreDetected()
       ? Handle(AIS_InteractiveObject)::DownCast (MainSelector()->Picked (myDetectedSeq (myCurDetected))->Selectable())
       : Handle(AIS_InteractiveObject)();
}

//=======================================================================
//function : SetSelectionModeActive
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetSelectionModeActive (const Handle(AIS_InteractiveObject)& theObj,
                                                     const Standard_Integer theMode,
                                                     const Standard_Boolean theIsActive,
                                                     const AIS_SelectionModesConcurrency theActiveFilter,
                                                     const Standard_Boolean theIsForce)
{
  if (theObj.IsNull())
  {
    return;
  }

  const Handle(AIS_GlobalStatus)* aStat = myObjects.Seek (theObj);
  if (aStat == NULL)
  {
    return;
  }

  if (!theIsActive
   || (theMode == -1
    && theActiveFilter == AIS_SelectionModesConcurrency_Single))
  {
    if (theObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed
     || theIsForce)
    {
      if (theMode == -1)
      {
        for (TColStd_ListIteratorOfListOfInteger aModeIter ((*aStat)->SelectionModes()); aModeIter.More(); aModeIter.Next())
        {
          mgrSelector->Deactivate (theObj, aModeIter.Value());
        }
      }
      else
      {
        mgrSelector->Deactivate (theObj, theMode);
      }
    }

    if (theMode == -1)
    {
      (*aStat)->ClearSelectionModes();
    }
    else
    {
      (*aStat)->RemoveSelectionMode (theMode);
    }
    return;
  }
  else if (theMode == -1)
  {
    return;
  }

  if ((*aStat)->SelectionModes().Size() == 1
   && (*aStat)->SelectionModes().First() == theMode)
  {
    return;
  }

  if (theObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed
   || theIsForce)
  {
    switch (theActiveFilter)
    {
      case AIS_SelectionModesConcurrency_Single:
      {
        for (TColStd_ListIteratorOfListOfInteger aModeIter ((*aStat)->SelectionModes()); aModeIter.More(); aModeIter.Next())
        {
          mgrSelector->Deactivate (theObj, aModeIter.Value());
        }
        (*aStat)->ClearSelectionModes();
        break;
      }
      case AIS_SelectionModesConcurrency_GlobalOrLocal:
      {
        const Standard_Integer aGlobSelMode = theObj->GlobalSelectionMode();
        TColStd_ListOfInteger aRemovedModes;
        for (TColStd_ListIteratorOfListOfInteger aModeIter ((*aStat)->SelectionModes()); aModeIter.More(); aModeIter.Next())
        {
          if ((theMode == aGlobSelMode && aModeIter.Value() != aGlobSelMode)
           || (theMode != aGlobSelMode && aModeIter.Value() == aGlobSelMode))
          {
            mgrSelector->Deactivate (theObj, aModeIter.Value());
            aRemovedModes.Append (aModeIter.Value());
          }
        }
        if (aRemovedModes.Size() == (*aStat)->SelectionModes().Size())
        {
          (*aStat)->ClearSelectionModes();
        }
        else
        {
          for (TColStd_ListIteratorOfListOfInteger aModeIter (aRemovedModes); aModeIter.More(); aModeIter.Next())
          {
            (*aStat)->RemoveSelectionMode (aModeIter.Value());
          }
        }
        break;
      }
      case AIS_SelectionModesConcurrency_Multiple:
      {
        break;
      }
    }
    mgrSelector->Activate (theObj, theMode);
  }
  (*aStat)->AddSelectionMode (theMode);
}

// ============================================================================
// function : Activate
// purpose  :
// ============================================================================
void AIS_InteractiveContext::Activate (const Standard_Integer theMode,
                                       const Standard_Boolean theIsForce)
{
  AIS_ListOfInteractive aDisplayedObjects;
  DisplayedObjects (aDisplayedObjects);
  for (AIS_ListOfInteractive::Iterator anIter (aDisplayedObjects); anIter.More(); anIter.Next())
  {
    Load (anIter.Value(), -1);
    Activate (anIter.Value(), theMode, theIsForce);
  }
}

// ============================================================================
// function : Deactivate
// purpose  :
// ============================================================================
void AIS_InteractiveContext::Deactivate (const Standard_Integer theMode)
{
  AIS_ListOfInteractive aDisplayedObjects;
  DisplayedObjects (aDisplayedObjects);
  for (AIS_ListOfInteractive::Iterator anIter (aDisplayedObjects); anIter.More(); anIter.Next())
  {
    Deactivate (anIter.Value(), theMode);
  }
}

// ============================================================================
// function : Deactivate
// purpose  :
// ============================================================================
void AIS_InteractiveContext::Deactivate()
{
  AIS_ListOfInteractive aDisplayedObjects;
  DisplayedObjects (aDisplayedObjects);

  for (AIS_ListOfInteractive::Iterator anIter (aDisplayedObjects); anIter.More(); anIter.Next())
  {
    Deactivate (anIter.Value());
  }
}

//=======================================================================
//function : ActivatedModes
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ActivatedModes (const Handle(AIS_InteractiveObject)& theObj,
                                             TColStd_ListOfInteger& theList) const
{
  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theObj);
  if (aStatus != NULL)
  {
    for (TColStd_ListIteratorOfListOfInteger aModeIter ((*aStatus)->SelectionModes()); aModeIter.More(); aModeIter.Next())
    {
      theList.Append (aModeIter.Value());
    }
  }
}

//=======================================================================
//function : SubIntensityOn
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SubIntensityOn (const Handle(AIS_InteractiveObject)& theObj,
                                             const Standard_Boolean theToUpdateViewer)
{
  turnOnSubintensity (theObj);
  if (theToUpdateViewer)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : SubIntensityOff
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SubIntensityOff (const Handle(AIS_InteractiveObject)& theObj,
                                              const Standard_Boolean theToUpdateViewer)
{
  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theObj);
  if (aStatus == NULL
   || !(*aStatus)->IsSubIntensityOn())
  {
    return;
  }

  (*aStatus)->SetSubIntensity (false);
  Standard_Boolean toUpdateMain = Standard_False;
  if (theObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
  {
    myMainPM->Unhighlight (theObj);
    toUpdateMain = Standard_True;
  }

  if (IsSelected (theObj))
  {
    highlightSelected (theObj->GlobalSelOwner());
  }

  if (theToUpdateViewer && toUpdateMain)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : DisplayActiveSensitive
//purpose  :
//=======================================================================
void AIS_InteractiveContext::DisplayActiveSensitive(const Handle(V3d_View)& theView)
{
  MainSelector()->DisplaySensitive (theView);
}

//=======================================================================
//function : DisplayActiveSensitive
//purpose  :
//=======================================================================
void AIS_InteractiveContext::DisplayActiveSensitive (const Handle(AIS_InteractiveObject)& theObj,
                                                     const Handle(V3d_View)& theView)
{
  const Handle(AIS_GlobalStatus)* aStatus = myObjects.Seek (theObj);
  if (aStatus == NULL)
  {
    return;
  }

  for (TColStd_ListIteratorOfListOfInteger aModeIter ((*aStatus)->SelectionModes()); aModeIter.More(); aModeIter.Next())
  {
    const Handle(SelectMgr_Selection)& aSel = theObj->Selection (aModeIter.Value());
    MainSelector()->DisplaySensitive (aSel, theObj->Transformation(), theView, Standard_False);
  }
}

//=======================================================================
//function : ClearActiveSensitive
//purpose  :
//=======================================================================
void AIS_InteractiveContext::ClearActiveSensitive (const Handle(V3d_View)& theView)
{
  MainSelector()->ClearSensitive (theView);
}

//=======================================================================
//function : IsImmediateModeOn
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::IsImmediateModeOn() const
{
  return myMainPM->IsImmediateModeOn();
}

//=======================================================================
//function : BeginImmediateDraw
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::BeginImmediateDraw()
{
  if (myMainPM->IsImmediateModeOn())
  {
    myMainPM->BeginImmediateDraw();
    return Standard_True;
  }
  return Standard_False;
}

//=======================================================================
//function : ImmediateAdd
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::ImmediateAdd (const Handle(AIS_InteractiveObject)& theObj,
                                                       const Standard_Integer theMode)
{
  if (myMainPM->IsImmediateModeOn())
  {
    myMainPM->AddToImmediateList (myMainPM->Presentation (theObj, theMode));
    return Standard_True;
  }
  return Standard_False;
}

//=======================================================================
//function : EndImmediateDraw
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::EndImmediateDraw (const Handle(V3d_View)& theView)
{
  if (myMainPM->IsImmediateModeOn())
  {
    myMainPM->EndImmediateDraw (theView->Viewer());
    return Standard_True;
  }
  return Standard_False;
}

//=======================================================================
//function : EndImmediateDraw
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::EndImmediateDraw()
{
  if (myMainPM->IsImmediateModeOn())
  {
    myMainPM->EndImmediateDraw (myMainVwr);
    return Standard_True;
  }
  return Standard_False;
}

//=======================================================================
//function : SetPolygonOffsets
//purpose  :
//=======================================================================
void AIS_InteractiveContext::SetPolygonOffsets (const Handle(AIS_InteractiveObject)& theObj,
                                                const Standard_Integer   theMode,
                                                const Standard_ShortReal theFactor,
                                                const Standard_ShortReal theUnits,
                                                const Standard_Boolean   theToUpdateViewer)
{
  if (theObj.IsNull())
  {
    return;
  }

  setContextToObject (theObj);
  theObj->SetPolygonOffsets (theMode, theFactor, theUnits);

  const Handle(AIS_GlobalStatus)* aStatus = theToUpdateViewer ? myObjects.Seek (theObj) : NULL;
  if (aStatus != NULL
   && theObj->DisplayStatus() == PrsMgr_DisplayStatus_Displayed)
  {
    myMainVwr->Update();
  }
}

//=======================================================================
//function : HasPolygonOffsets
//purpose  :
//=======================================================================
Standard_Boolean AIS_InteractiveContext::HasPolygonOffsets (const Handle(AIS_InteractiveObject)& theObj) const
{
  return !theObj.IsNull() && theObj->HasPolygonOffsets();
}

//=======================================================================
//function : PolygonOffsets
//purpose  :
//=======================================================================
void AIS_InteractiveContext::PolygonOffsets (const Handle(AIS_InteractiveObject)& theObj,
                                             Standard_Integer&   theMode,
                                             Standard_ShortReal& theFactor,
                                             Standard_ShortReal& theUnits) const
{
  if (HasPolygonOffsets (theObj))
  {
    theObj->PolygonOffsets (theMode, theFactor, theUnits);
  }
}

//=======================================================================
//function : DumpJson
//purpose  :
//=======================================================================
void AIS_InteractiveContext::DumpJson (Standard_OStream& theOStream, Standard_Integer) const
{
  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)

  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myObjects.Size())

  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, mgrSelector.get())
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myMainPM.get())
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myMainVwr.get())
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myLastActiveView)

  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myLastPicked.get())

  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToHilightSelected)

  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, mySelection.get())
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myFilters.get())
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myDefaultDrawer.get())

  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myStyles[Prs3d_TypeOfHighlight_Selected])
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myStyles[Prs3d_TypeOfHighlight_Dynamic])
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myStyles[Prs3d_TypeOfHighlight_LocalSelected])
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myStyles[Prs3d_TypeOfHighlight_LocalDynamic])
  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myStyles[Prs3d_TypeOfHighlight_SubIntensity])

  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedSeq.Size())

  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myCurDetected)
  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myCurHighlighted)
  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPickingStrategy)
  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAutoHilight)
  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsAutoActivateSelMode)
}
