CustomPanel.cs 7.27 KB
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace flowchart
{
    // flowchart를 그리는 판넬에 필요한 기능을 삽입. (Panel 객체를 상속해서 사용했음)
    // 마우스 클릭을 놓으면 어떤 도형 또는 선을 선택했는지 판단해서, 해당 자료구조를 생성하고, 페인트 함수를 통해 그린다. 
    class CustomPanel : Panel
    {
        private String _state;            // NONE, DRAW, MOVE
        private String _figName;          // NONE, RECTANGLE, RHOMBUS, LINKLINE, ETC
        
        private List<FigBase> _shapes = new List<FigBase>();             // 도형을 저장한 리스트 자료구조
        private List<FigLinkline> _linkLines = new List<FigLinkline>();  // 링크 선을 저장한 리스트 자료구조

        private FigBase _linkStartShape = null;   // 처음 선택한 도형을 저장하는 변수
        private FigBase _movingShape = null;      // 도형을 움직이겠다고 선택된 경우 해당 도형을 저장하는 변수                          
        

        // private 변수를 클래스 밖에서 읽고 쓰게 하는 함수
        public string FigName { get { return _figName; }  set { _figName = value; } }
        public String State { get { return _state; } set { _state = value; } }

        // 마우스를 판넬에서 움질일때 호출되는 이벤트 함수
        protected override void OnMouseMove(MouseEventArgs e)
        {
            // System.Diagnostics.Trace.WriteLine("debug >>>" + _state); // 디버깅

            // 마우스 버튼을 누르지 않은 상태일 경우
            if (e.Button == MouseButtons.None)
            {
                // 그려진 도형위에 마우스가 오면 마우스 모양을 변경
                FigBase shape = FindShapeByLocation(e.Location);
                
                if (shape != null)
                    Cursor = Cursors.SizeAll; // 도형 안에 마우스가 있을 경우
                else
                    Cursor = Cursors.Default; // 도형 밖에 마우스 포인터가 있을 경우

                if (shape != null && _figName == "LINKLINE")  // 링크 라인을 그리겠다고 선택하고, 도형 안에 마우스가 있을 경우
                    Cursor = Cursors.Cross;

            }
            // 마우스를 클릭한 상태에서 링크 라인을 그리지 않겠다고 선택된 경우
            else if (e.Button == MouseButtons.Left && _figName != "LINKLINE")
            {
                FigBase shape = FindShapeByLocation(e.Location);
                if (shape != null)
                {
                    _state = "MOVE";        // 움직이는 상태로 바꿈
                    _movingShape = shape;   // 해당 도형을 레퍼런스
                }
            }
            // 마우스를 클릭한 상태에서 링크 라인을 그리겠다고 선택한 경우
            else if (e.Button == MouseButtons.Left && _figName == "LINKLINE")
            {
                if (_linkStartShape == null)  // 처음 도형을 선택한것만 저장하기 위함. (다른 영역의 도형으로 넘어가도 실행안함)
                {
                    _linkStartShape = FindShapeByLocation(e.Location);
                    if (_linkStartShape != null)
                    {
                        _state = "MOVE";
                    }
                }
            }

            base.OnMouseMove(e);
        }

        // 실제 도형을 그리거나 이동하는 함수, 최종 OnPaint() 함수가 호출되어 실행됨
        protected override void OnMouseUp(MouseEventArgs e)
        {
            //System.Diagnostics.Trace.WriteLine("debug >>>" + _state);
            // 그리기 상태
            if (_state == "DRAW")
            {
                if (_figName == "RECTANGLE")
                {
                    // 사각형에 대한 정보를 자료구조에 삽입한다.
                    FigRectangle rectangle = new FigRectangle(e.Location, new System.Drawing.Size(100, 100));
                    _shapes.Add(rectangle);
                }
                else if (_figName == "RHOMBUS")
                {
                    FigRhombus rhombus = new FigRhombus(e.Location, new System.Drawing.Size(100, 100));
                    _shapes.Add(rhombus);
                }
                else if (_figName == "PARALLELOGRAM")
                {
                    FigParallelogram parallelogram = new FigParallelogram(e.Location, new System.Drawing.Size(100, 100));
                    _shapes.Add(parallelogram);
                }
            }
            // 움직이는 상태이고 링크 라인을 그리지 않는 경우 (단순 도형 이동)
            else if (_state == "MOVE" && _figName != "LINKLINE")
            {
                if (_movingShape != null)
                {
                    _movingShape.Location = e.Location; // 찾은 도형의 위치값을 옮길위치로 수정
                }
            }
            // 움직이는 상태이고 링크 라인을 그리는 경우 (링크 라인을 긋는 경우)
            else if (_state == "MOVE" && _figName == "LINKLINE")
            {
                if (_linkStartShape != null)
                {
                    FigBase shape = FindShapeByLocation(e.Location);  // 마우스를 클릭을 놓은 위치에 도형이 있는지 확인
                    if (shape == null)
                    {
                        MessageBox.Show(this, "해당 위치에 연결대상 도형이 없습니다.", "알림",
                            MessageBoxButtons.OK, MessageBoxIcon.Information);
                        _linkStartShape = null;     // mouse move 이벤트 함수에서 한번은 실행하게 처리
                    }
                    else
                    {
                        FigLinkline linkLine = new FigLinkline(_linkStartShape, shape);  // 처음 선택한 도형과 현재 도형에 링크 라인을 연결 함
                        _linkLines.Add(linkLine);
                        _linkStartShape = null;    // mouse move 이벤트 함수에서 한번은 실행하게 처리
                    }
                  
                }
            }

            _state = "NONE";
            this.Refresh(); // 다시 그리기 요청: OnPaint()
            base.OnMouseUp(e);
        }

        // 실제 그리는 OnPaint를 통해 내가 작성한 Draw함수를 호출한다.
        protected override void OnPaint(PaintEventArgs e)
        {
            // 자료구조에 저장된 도형을 다시 그림
            foreach (FigBase s in _shapes)
            {
                s.Draw(e.Graphics);
            }
            // 자료구조에 저장된 링크라인을 다시 그림
            foreach (FigLinkline l in _linkLines)
            {
                l.Draw(e.Graphics);
            }

            base.OnPaint(e);
        }
        // 현재 위치에 해당하는 도형을 자료구조에서 레퍼런스 함
        private FigBase FindShapeByLocation(Point location)
        {
            foreach (FigBase s in _shapes)
            {
                if (s.PointInRegion(location))
                {
                    return s;
                }
            }

            return null;
        }
    }
}