Скачиваний:
11
Добавлен:
01.05.2014
Размер:
16.16 Кб
Скачать
// ShapeHandler.cpp: implementation of the ShapeHandler class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Sketcher.h"
#include "ShapeHandler.h"
//////////////////////////////////////////////////////////////////////////
#include "Elements.h"

#include "shapes/Rectangle.h"
#include "shapes/Text.h"
#include "shapes/Oval.h"
#include "shapes/TextInOval.h"

#include "container/Iterator.h"
//////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

ShapeHandler::ShapeHandler(CSketcherView* view): _view(view)
{
    m_FirstPoint = CPoint(0,0);         // Set 1st recorded point to 0,0
    m_SecondPoint = CPoint(0,0);        // Set 2nd recorded point to 0,0
    m_pTempElement = NULL;              // Set temporary element pointer to 0

    m_pSelected = NULL;                 // No element selected initially
    m_MoveMode = FALSE;                 // Set move mode off

    m_CursorPos = CPoint(0,0);          // Initialize as zero
    m_FirstPos = CPoint(0,0);           // Initialize as zero

    _isGraphVisible = true;
    _ribble = NULL;
    _lastNearestRibbles = NULL;
    _firstVertex = NULL;

    m_Scale = 1;                        // Set scale to 1:1
}


ShapeHandler::~ShapeHandler()
{
}


void ShapeHandler::changeVertex()
{
    if (canProceed())
    { // переходим по ребру
        _firstVertex = _ribble->getAnotherVertex(_firstVertex);
        
        // подсвечиваем переход
        markHighlighted(_firstVertex);
        drawRibble(_ribble, GREEN);
        
        // уничтожаем список инцидентных ребер, т.к. перешли на новую вершину
        _lastNearestRibbles = NULL;
        _ribble = NULL;
    }
}


void ShapeHandler::changeRibble( bool isNext )
{
    ExternalGraphIterator<CElement>* lastNearestRibbles = refreshNearestRibbles();
    // убираем подсветку с текущего ребра
    drawRibble(_ribble, GREEN);
    // двигаемся
    if (isNext)
    {
        if (lastNearestRibbles->hasNext())
        {
            _ribble = lastNearestRibbles->next();
        } 
        else
        {
            _ribble = lastNearestRibbles->first();
        }
    }
    else
    {
        if (lastNearestRibbles->hasPrevious())
        {
            _ribble = lastNearestRibbles->previous();
        } 
        else
        {
            _ribble = lastNearestRibbles->last();
        }
    }
    // подсвечиваем новое ребро
    drawRibble(_ribble, SELECT_COLOR);
}


bool ShapeHandler::canProceed()
{
    if (_ribble == NULL)
    { // ребра нет - нужно подготовить
        //выбираем ребро для перемещения
        ExternalGraphIterator<CElement>* lastNearestRibbles = refreshNearestRibbles();
        
        if (lastNearestRibbles->getGraphRibbleCount() == 0)
        {   // начали обход из петли - перейти никуда не можем
            AfxMessageBox("Тупик!");
            return false;
        } 
        else if (lastNearestRibbles->getGraphRibbleCount() == 1)
        {   // ребро всего одно - по нему и переходим
            _ribble = lastNearestRibbles->next();
            drawRibble(_ribble, SELECT_COLOR);
            return true;
        }
        else
        {   // ребер много - нужно дождаться выбора
            return false;
        }
    }
    return true;
}


void ShapeHandler::markHighlighted(CElement* pCurrentSelection )
{
    CClientDC aDC(_view);
    _view->OnPrepareDC(&aDC);
    CRect aRect;
    if(pCurrentSelection != m_pSelected)
    {
        if(m_pSelected)             // Old elemented selected?
        {                           // Yes, so draw it unselected
            aRect = m_pSelected->GetBoundRect(); // Get bounding rectangle
            aDC.LPtoDP(aRect);                   // Conv to device coords
            aRect.NormalizeRect();               // Normalize
            _view->InvalidateRect(aRect, FALSE);        // Invalidate area
        }
        
        m_pSelected = pCurrentSelection;        // Save elem under cursor
        
        if(m_pSelected)                         // Is there one?
        {                                       // Yes, so get it redrawn
            aRect = m_pSelected->GetBoundRect(); // Get bounding rectangle
            aDC.LPtoDP(aRect);                   // Conv to device coords
            aRect.NormalizeRect();               // Normalize
            _view->InvalidateRect(aRect, FALSE);        // Invalidate area
        }
    }
}


ExternalGraphIterator<CElement>* ShapeHandler::refreshNearestRibbles()
{
    if (_lastNearestRibbles == NULL)
    {
        // готовим вершину для начала обхода
        if (_firstVertex == NULL)
        { // ничего не выбрано - начинаем обход с первой вершины
            Iterator<CElement>* iter = GetDocument()->getShapeContainer()->getNewIterator();
            Ribble<CElement>* firstRibble = iter->first();
            _firstVertex = firstRibble->get__vertex1();
            // вершина подготовлена - можно выбирать инцидентные ей ребра
        }
        markHighlighted(_firstVertex);
        _lastNearestRibbles = GetDocument()->getShapeContainer()->getNearestRibbles(_firstVertex);
    }
    return _lastNearestRibbles;
}


void ShapeHandler::drawRibble( Ribble<CElement>* ribble, COLORREF aColor )
{
    if ( _isGraphVisible && ribble != NULL )
    {   // граф отображается - рисуем
        CPoint start = ribble->get__vertex1()->GetBoundRect().CenterPoint();
        CPoint end = ribble->get__vertex2()->GetBoundRect().CenterPoint();
        
        CLine* visibleRibble = new CLine(start, end, aColor);

        CClientDC pDC(_view);
        _view->OnPrepareDC(&pDC);
        visibleRibble->Draw(&pDC);
    }
}


void ShapeHandler::onDraw( CDC* pDC )
{
    CSketcherDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    
    CElement* pElement = NULL;
    Iterator<CElement>* iter = pDoc->getShapeContainer()->getNewIterator();
    
    while (iter->hasNext())
    {
        Ribble<CElement>* ribble = iter->next();
        
        pElement = ribble->get__vertex1();
        if(pDC->RectVisible(pElement->GetBoundRect()))
        {
            pElement->Draw(pDC, m_pSelected, _isGraphVisible);
        }
        
        pElement = ribble->get__vertex2();
        if(pDC->RectVisible(pElement->GetBoundRect()))
        {
            pElement->Draw(pDC, m_pSelected, _isGraphVisible);
        }
        
        drawRibble(ribble, GREEN);
    }
}


void ShapeHandler::onLBDown( CPoint &point )
{
    if (!m_MoveMode && GetDocument()->getShapeContainer()->GetElementType()!=RIBBLE)
    {
        CClientDC aDC(_view);
        _view->OnPrepareDC(&aDC);
        aDC.DPtoLP(&point);                 // convert point to Logical
    }
    
    if(m_MoveMode)
    {
        // In moving mode, so drop the element
        m_MoveMode = FALSE;                 // Kill move mode
        m_pSelected = 0;                    // De-select the element
        GetDocument()->UpdateAllViews(0);   // Redraw all the views
    }
    else
    {
        if (GetDocument()->getShapeContainer()->GetElementType() == RIBBLE)
        {   // добавляем ребро
            CElement* currentSelection = SelectElement(point);
            if (currentSelection != NULL)
            {   // найдена начальная вершина
                CPoint* exactCenter = &(currentSelection->GetBoundRect().CenterPoint());
                m_FirstPoint = *exactCenter;
                // запоминаем ее
                m_pSelected = currentSelection;
                _view->SetCapture();                       // Capture subsequent mouse messages
            }
        }
        else
        {
            m_FirstPoint = point;               // Record the cursor position
            _view->SetCapture();                       // Capture subsequent mouse messages
        }
    }
}


CElement* ShapeHandler::CreateElement()
{
    // Get a pointer to the document for this view
    CSketcherDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);                  // Verify the pointer is good
    
    // Now select the element using the type stored in the document
    switch(pDoc->getShapeContainer()->GetElementType())
    {
        case RECTANGLE:
            return Rectangle2::create(m_FirstPoint, m_SecondPoint, pDoc->getShapeContainer()->GetElementColor());
        case TEXT:
            return Text::create(m_FirstPoint, m_SecondPoint, pDoc->getShapeContainer()->GetElementColor());
        case OVAL:
            return Oval::create(m_FirstPoint, m_SecondPoint, pDoc->getShapeContainer()->GetElementColor());
        case TEXT_IN_OVAL:
            return TextInOval::create(m_FirstPoint, m_SecondPoint, pDoc->getShapeContainer()->GetElementColor());
        //////////////////////////////////////////////////////////////////////////
        case RIBBLE:                  
            return new CLine(m_FirstPoint, m_SecondPoint, GREEN);
        //////////////////////////////////////////////////////////////////////////
        default:
            //	Something's gone wrong
            AfxMessageBox("Bad Element code", MB_OK);
            AfxAbort();
            return NULL;
    }
}


CElement* ShapeHandler::SelectElement( CPoint aPoint)
{
    CClientDC aDC(_view);
    _view->OnPrepareDC(&aDC);

    // Convert parameter aPoint to logical coordinates
    aDC.DPtoLP(&aPoint);
    
    CSketcherDoc* pDoc = GetDocument();  // Get a pointer to the document
    CElement* pElement = NULL;  // Store an element pointer
    CRect aRect(0,0,0,0);       // Store a rectangle
    
    Iterator<CElement>* iter = pDoc->getShapeContainer()->getNewIterator();
    while (iter->hasNext())
    {
        Ribble<CElement>* ribble = iter->next();
        
        pElement = ribble->get__vertex1();
        aRect = pElement->GetBoundRect();
        if(aRect.PtInRect(aPoint))
            return pElement;
        
        pElement = ribble->get__vertex2();
        aRect = pElement->GetBoundRect();
        if(aRect.PtInRect(aPoint))
            return pElement;
    }
    
    return NULL;                              // No element found
}


void ShapeHandler::MoveElement( CPoint& point )
{
    CClientDC aDC(_view);
    _view->OnPrepareDC(&aDC);
    
    CSize Distance = point - m_CursorPos;   // Get move distance
    m_CursorPos = point;          // Set current point as 1st for next time
    
    // If there is an element, selected, move it
    if(m_pSelected)
    {
        aDC.SetROP2(R2_NOTXORPEN);
        m_pSelected->Draw(&aDC,m_pSelected,_isGraphVisible); // Draw the element to erase it
        m_pSelected->Move(Distance);                        // Now move the element
        m_pSelected->Draw(&aDC,m_pSelected,_isGraphVisible); // Draw the moved element
    }
}


void ShapeHandler::onLBUp( CPoint& point )
{
    if(_view == _view->GetCapture())
        ReleaseCapture();        // Stop capturing mouse messages

    // If there is an element, add it to the document
    if(m_pTempElement)
    {
        if (GetDocument()->getShapeContainer()->GetElementType()==RIBBLE)
        {   // соединяем ребрами
            CElement* secondVertex = SelectElement(point);
            if (secondVertex!=NULL)
            {   // найдена конечная вершина
                GetDocument()->getShapeContainer()->linkElements(m_pSelected, secondVertex);
            }
        } 
        else
        {   // добавляем новый элемент
            GetDocument()->getShapeContainer()->AddElement(m_pTempElement);
        }
        
        GetDocument()->UpdateAllViews(0,0,m_pTempElement);  // Tell all the views
        m_pTempElement = 0;        // Reset the element pointer
    }
}


void ShapeHandler::onMMove( CPoint& point, bool flag )
{
    // Define a Device Context object for the view
    CClientDC aDC(_view);
    _view->OnPrepareDC(&aDC);            // Get origin adjusted

    if(m_MoveMode)
    { // передвигаем фигуру
        aDC.DPtoLP(&point);        // Convert to logical coordinatess
        MoveElement(point);   // Move the element
    }
    else if( flag && (_view == _view->GetCapture()))
    { // рисуем фигуру
        aDC.DPtoLP(&point);
        m_SecondPoint = point;     // Save the current cursor position
        
        if(m_pTempElement)
        { // фигура есть
            aDC.SetROP2(R2_NOTXORPEN);      // Set drawing mode
            m_pTempElement->Draw(&aDC);  
            m_pTempElement->resize(m_FirstPoint, m_SecondPoint);
        }
        else
        { // фигуры нет
            m_pTempElement = CreateElement();
        }
        m_pTempElement->Draw(&aDC);  
    }
    else
    { // ничего не двигаем и не рисуем, только подсвечиваем
        CElement* pCurrentSelection = SelectElement(point);
        markHighlighted(pCurrentSelection);
    }

}


CSketcherDoc* ShapeHandler::GetDocument()
{
    return _view->GetDocument();
}


void ShapeHandler::onMove()
{
    CClientDC aDC(_view);
    _view->OnPrepareDC(&aDC);       // Set up the device context
    
    GetCursorPos(&m_CursorPos);     // Get cursor position in screen coords
    _view->ScreenToClient(&m_CursorPos);   // Convert to client coords
    aDC.DPtoLP(&m_CursorPos);       // Convert to logical
    
    m_FirstPos = m_CursorPos;       // Remember first position
    m_MoveMode = TRUE;              // Start move mode
}


void ShapeHandler::onRBDown( CPoint &point )
{
    if(m_MoveMode)
    {
        // In moving mode, so drop element back in original position
        CClientDC aDC(_view);
        _view->OnPrepareDC(&aDC);                  // Get origin adjusted

        MoveElement(point);       // Move element to orig position
        m_MoveMode = FALSE;                 // Kill move mode
        m_pSelected = NULL;                    // De-select element

        GetDocument()->UpdateAllViews(0);   // Redraw all the views
    }   
}


void ShapeHandler::onRBUp( CPoint &point )
{
    // Create the cursor menu
    CMenu aMenu;
    aMenu.LoadMenu(IDR_CURSOR_MENU);    // Load the cursor menu
    _view->ClientToScreen(&point);             // Convert to screen coordinates
    
    // Display the pop-up at the cursor position
    if(m_pSelected)
    {
        aMenu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,
            point.x, point.y, _view);
    }
    else
    {
        // Check color menu items
        COLORREF Color = GetDocument()->getShapeContainer()->GetElementColor();
        aMenu.CheckMenuItem(ID_COLOR_BLACK,
            (BLACK==Color?MF_CHECKED:MF_UNCHECKED)|MF_BYCOMMAND);
        aMenu.CheckMenuItem(ID_COLOR_RED,
            (RED==Color?MF_CHECKED:MF_UNCHECKED)|MF_BYCOMMAND);
        
        // Check element menu items
        WORD ElementType = GetDocument()->getShapeContainer()->GetElementType();
        aMenu.CheckMenuItem(ID_ELEMENT_LINE,
            (RIBBLE==ElementType?MF_CHECKED:MF_UNCHECKED)|MF_BYCOMMAND);
        aMenu.CheckMenuItem(ID_ELEMENT_RECTANGLE,
            (RECTANGLE==ElementType?MF_CHECKED:MF_UNCHECKED)|MF_BYCOMMAND);
        
        // Display the context pop-up
        aMenu.GetSubMenu(1)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, _view);
    }
}


void ShapeHandler::onDelete()
{
    if(m_pSelected)
    {
        CSketcherDoc* pDoc = GetDocument();  // Get the document pointer
        pDoc->getShapeContainer()->DeleteElement(m_pSelected);    // Delete the element
        pDoc->UpdateAllViews(0);             // Redraw all the views
        m_pSelected = NULL;                  // Reset selected element ptr
    }
}
Соседние файлы в папке Sketcher02