//------------------------------------------------------------------------------
// Purpose: Set icon being displayed on output button.
//------------------------------------------------------------------------------
void CObjectProperties::UpdateOutputButton(void)
{
	//VPROF_BUDGET( "CObjectProperties::UpdateOutputButton", "Object Properties" );

	if (!m_pOutputButton)
	{
		return;
	}

	bool bHaveConnection = false;
	bool bIgnoreHiddenTargets = false;
	if ( m_pOutput )
		bIgnoreHiddenTargets = !m_pOutput->ShouldShowHiddenTargets();

	FOR_EACH_OBJ( m_DstObjects, pos )
	{
		CMapClass *pObject = m_DstObjects.Element(pos);

		if ((pObject != NULL) && (pObject->IsMapClass(MAPCLASS_TYPE(CMapEntity))))
		{
			CMapEntity *pEntity = (CMapEntity *)pObject;
			int nStatus = CEntityConnection::ValidateOutputConnections(pEntity, true, bIgnoreHiddenTargets);
			if (nStatus == CONNECTION_BAD)
			{
				SetOutputButtonState(CONNECTION_BAD);
				return;
			}
			else if (nStatus == CONNECTION_GOOD)
			{
				bHaveConnection = true;
			}
		}
	}
//-----------------------------------------------------------------------------
// Purpose: Enumerates a this object's children, only recursing into groups.
//			Children of entities will not be enumerated.
// Input  : pfn - Enumeration callback function. Called once per child.
//			dwParam - User data to pass into the enumerating callback.
//			Type - Unless NULL, only objects of the given type will be enumerated.
// Output : Returns FALSE if the enumeration was terminated early, TRUE if it completed.
//-----------------------------------------------------------------------------
BOOL CMapClass::EnumChildrenRecurseGroupsOnly(ENUMMAPCHILDRENPROC pfn, DWORD dwParam, MAPCLASSTYPE Type)
{
	POSITION pos = Children.GetHeadPosition();
	while (pos)
	{
		CMapClass *pChild = Children.GetNext(pos);

		if (!Type || pChild->IsMapClass(Type))
		{
			if (!(*pfn)(pChild, dwParam))
			{
				return FALSE;
			}
		}

		if (pChild->IsGroup())
		{
			if (!pChild->EnumChildrenRecurseGroupsOnly(pfn, dwParam, Type))
			{
				return FALSE;
			}
		}
	}

	return TRUE;
}
//-----------------------------------------------------------------------------
// Purpose: This functions sets up the list of objects to be clipped.  
//          Initially the list is passed in (typically a Selection set).  On 
//          subsequent "translation" updates the list is refreshed from the 
//          m_pOrigObjects list.
//   Input: pList - the list of objects (solids) to be clipped
//-----------------------------------------------------------------------------
void Clipper3D::SetClipObjects( CMapObjectList *pList )
{
    // check for an empty list
    if( !pList )
        return;

    // save the original list
    m_pOrigObjects = pList;

    // clear the clip results list
    ResetClipResults();

    //
    // copy solids into the clip list
    //
    POSITION pos = m_pOrigObjects->GetHeadPosition();
    while( pos )
    {
        CMapClass *pObject = m_pOrigObjects->GetNext( pos );
        if( !pObject )
            continue;

        if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
        {
            AddToClipList( ( CMapSolid* )pObject, this );
        }

        pObject->EnumChildren( ENUMMAPCHILDRENPROC( AddToClipList ), DWORD( this ), MAPCLASS_TYPE( CMapSolid ) );
    }

    // the clipping list is not empty anymore
    m_bEmpty = FALSE;
}
//-----------------------------------------------------------------------------
// Purpose: Handles left mouse button down events in the 3D view.
// Input  : Per CWnd::OnLButtonDown.
// Output : Returns true if the message was handled, false if not.
//-----------------------------------------------------------------------------
bool CToolMaterial::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, CPoint point) 
{
	CMapDoc *pDoc = pView->GetDocument();
	if (pDoc == NULL)
	{
		return false;
	}

	bool bShift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);

	ULONG ulFace;
	CMapClass *pObject = pView->NearestObjectAt(point, ulFace);

	if ((pObject != NULL) && (pObject->IsMapClass(MAPCLASS_TYPE(CMapSolid))))
	{
		CMapSolid *pSolid = (CMapSolid *)pObject;

		int cmd = CMapDoc::scToggle | CMapDoc::scClear | CMapDoc::scUpdateDisplay;

		// No clear if CTRL pressed.
		if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
		{
			cmd &= ~CMapDoc::scClear;	
		}

		// If they are holding down SHIFT, select the entire solid.
		if (bShift)
		{
			pDoc->SelectFace(pSolid, -1, cmd);
		}
		// Otherwise, select a single face.
		else
		{
			pDoc->SelectFace(pSolid, ulFace, cmd);
		}
	}

	// Update the controls given new information (ie. new faces).
	GetMainWnd()->m_pFaceEditSheet->UpdateControls();

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Handles right mouse button down events in the 3D view.
// Input  : Per CWnd::OnRButtonDown.
// Output : Returns true if the message was handled, false if not.
//-----------------------------------------------------------------------------
bool CToolMaterial::OnRMouseDown3D(CMapView3D *pView, UINT nFlags, CPoint point) 
{
	BOOL bShift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
	BOOL bEdgeAlign = ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0);
	
	ULONG ulFace;
	CMapClass *pObject = pView->NearestObjectAt(point, ulFace);

	if (pObject != NULL)
	{
		if (pObject->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
		{
			CMapSolid *pSolid = (CMapSolid *)pObject;
			GetHistory()->MarkUndoPosition(NULL, "Apply texture");
			GetHistory()->Keep(pSolid);
			
			// Setup the flags.
			int cmdFlags = 0;
			if(bEdgeAlign)
				cmdFlags |= CFaceEditSheet::cfEdgeAlign;
			
			// If they are holding down the shift key, apply to the entire solid.
			if (bShift)
			{
				int nFaces = pSolid->GetFaceCount();
				for(int i = 0; i < nFaces; i++)
				{
					GetMainWnd()->m_pFaceEditSheet->ClickFace( pSolid, i, cmdFlags, CFaceEditSheet::ModeApplyAll );
				}
			}
			// If not, apply to a single face.
			else
			{
				GetMainWnd()->m_pFaceEditSheet->ClickFace( pSolid, ulFace, cmdFlags, CFaceEditSheet::ModeApplyAll );
			}
		}				
	}
	
	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Calls an enumerating function for each of our children that are of
//			of a given type, recursively enumerating their children also.
// Input  : pfn - Enumeration callback function. Called once per child.
//			dwParam - User data to pass into the enumerating callback.
//			Type - Unless NULL, only objects of the given type will be enumerated.
// Output : Returns FALSE if the enumeration was terminated early, TRUE if it completed.
//-----------------------------------------------------------------------------
BOOL CMapClass::EnumChildren(ENUMMAPCHILDRENPROC pfn, DWORD dwParam, MAPCLASSTYPE Type)
{
	POSITION p = Children.GetHeadPosition();
	while (p)
	{
		CMapClass *pChild = Children.GetNext(p);
		if (!Type || pChild->IsMapClass(Type))
		{
			if(!(*pfn)(pChild, dwParam))
			{
				return FALSE;
			}
		}

		// enum this child's children
		if (!pChild->EnumChildren(pfn, dwParam, Type))
		{
			return FALSE;
		}
	}

	return TRUE;
}