CTreeDoc* GetDocument()
{
	return dynamic_cast<CTreeDoc*>(m_pDocument);
}


class CTreeFrame : public CMDIChildWnd
{
	DECLARE_DYNCREATE(CTreeFrame)
public:
	CTreeFrame();
	virtual ~CTreeFrame();
	//======    (split)   
	virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs,
								CCreateContext* pContext);
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
	//======     
	CSplitterWnd m_wndSplitter;
	DECLARE_MESSAGE_MAP()
};


#pragma once
class CTreeDoc;				//  

class CLeftView : public CTreeView
{
protected:
	//======      
	CTreeCtrl& m_Tree;
	//======    
	CImageList *m_pImgList;
	
	CLeftView();
	virtual void OnInitialUpdate();

	DECLARE_DYNCREATE(CLeftView)
public:
	virtual ~CLeftView();
	CTreeDoc* GetDocument()  
	{
		return dynamic_cast<CTreeDoc*>(m_pDocument);
	}

	//======   
	void GetSysImgList();
	//======    ()
	void AddItem(HTREEITEM h, LPCTSTR s);
	//======   
	void SearchForDocs(CString s);
	//======   
	bool NotEmpty(CString s);
	//======      
	CString GetPath (HTREEITEM hCur);
	DECLARE_MESSAGE_MAP()
};



IMPLEMENT_DYNCREATE(CLeftView, CTreeView)

BEGIN_MESSAGE_MAP(CLeftView, CTreeView)
END_MESSAGE_MAP()

CLeftView::CLeftView(){}
CLeftView::~CLeftView(){}

void CLeftView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();
}



CLeftView::CLeftView()
	: m_Tree(GetTreeCtrl()) {}


::SetWindowLongPtr (m_Tree.m_hWnd, GWL_STYLE,
		::GetWindowLong(m_Tree.m_hWnd, GWL_STYLE)
			| TVS_HASBUTTONS | TVS_HASLINES
			| TVS_LINESATROOT | TVS_SHOWSELALWAYS);



m_Tree.InsertItem("Item",0,0);



//======   MS  
//======    -  
m_pImgList = new CImageList;
m_pImgList->Create(16, 16, ILC_MASK, 0, 32);

for (UINT nID = IDB_1; nID <= IDB_3; nID++)
{
	//======  
	CBitmap bitmap;
	//======   
	bitmap.LoadBitmap(nID);	

	//======     
	m_pImgList->Add(&bitmap, (COLORREF)0xFFFFFF);

	//======  
	bitmap.DeleteObject();
}

//===      CTreeCtrl
m_Tree.SetImageList(m_pImgList, TVSIL_NORMAL);



TVINSERTSTRUCT gtv;		//  



//======     
gtv.hParent = TVI_ROOT;
//======    
gtv.hInsertAfter = TVI_LAST;
//======   -    
gtv.item.mask= TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
//======       
gtv.item.iImage = 0;
//===       
gtv.item.iSelectedImage = 1;
//====== ,  
gtv.item.pszText = "First";
		
//======   
HTREEITEM h1, h2, h3;
//======   
h1 = m_Tree.InsertItem(&gtv);

//======     
gtv.hParent = h1;
//======   
gtv.item.iImage = 1;
gtv.item.pszText = "Second";
//======   	
h2 = m_Tree.InsertItem(&gtv);

//======     
gtv.hParent = h2;
gtv.item.iImage = 2;
gtv.item.pszText = "Third";
//======   
h3 = m_Tree.InsertItem(&gtv);



void CLeftView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();

	::SetWindowLongPtr(m_Tree.m_hWnd, GWL_STYLE,
		GetWindowLong(m_Tree.m_hWnd, GWL_STYLE)|TVS_HASLINES
		| TVS_HASBUTTONS|TVS_LINESATROOT|TVS_SHOWSELALWAYS);
	
	//======    
	m_pImgList = new CImageList;

	//======      
	GetSysImgList();
	
	char s [1024];
	//======    
	DWORD size = ::GetLogicalDriveStrings (1024, s);

	if (!size)		//   
		return;		//  

	//===       
	for (char *pName = s; *pName; pName += strlen(pName) + 1)
		AddItem (TVI_ROOT, pName);		
}



void CLeftView::GetSysImgList()
{
	SHFILEINFO info;

	//      
	HIMAGELIST hImg = (HIMAGELIST)::SHGetFileInfo("C:\\",0,
							&info,sizeof(info),
							SHGFI_SYSICONINDEX | SHGFI_SMALLICON);

	//===    
	//===   CImageList
	if (!hImg || !m_pImgList->Attach(hImg))
	{
		MessageBox(0,"   System Image List!");
		return;
	}

	//===      
	m_Tree.SetImageList(m_pImgList, TVSIL_NORMAL);
}



void CLeftView::AddItem (HTREEITEM h, LPCTSTR s)
{
	SHFILEINFO Info;
	int len = sizeof(Info);

	//===   ( )
	::SHGetFileInfo (s, 0, &Info, len, SHGFI_ICON
							| SHGFI_SMALLICON);
	int id = Info.iIcon;

	//===     
	::SHGetFileInfo (s,0,&Info,len,
				SHGFI_ICON | SHGFI_OPENICON | SHGFI_SMALLICON);
	int idSel = Info.iIcon;

	//======     
	CString sName(s);

	//===    (   )
	if (sName.Right(1) == '\\')
		sName.SetAt (sName.GetLength() - 1, '\0');

	//======   
	int iPos = sName.ReverseFind('\\');
	if (iPos != -1)
		sName = sName.Mid(iPos + 1);
	
	//===    
	HTREEITEM hNew = m_Tree.InsertItem(sName, id, idSel, h);

	//======   
	if (NotEmpty(s))
		m_Tree.InsertItem("", 0, 0, hNew);
}



bool CLeftView::NotEmpty(CString s)
{
	//======  s    
	//======  ,     
	CFileFind cff;

	//======    *.*  \*.*	
	s += s.Right(1) == '\\' ? "*.*" : "\\*.*";

	BOOL bFound = cff.FindFile(s);
	
	//======    
	while (bFound)
	{
		bFound = cff.FindNextFile();
			
		//======  ?
		if (cff.IsDirectory() && !cff.IsDots())
			return true;

		//======  ?
		if (!cff.IsDirectory() && !cff.IsHidden())
			return true;
	}
	//======   ,  
	return false;
}


void CLeftView::OnItemexpanding (NMHDR* pNMHDR,
											LRESULT* pResult) 
{
	//======   
	NM_TREEVIEW* p = (NM_TREEVIEW*)pNMHDR;

	//======    
	if ( !(p->itemNew.state & TVIS_EXPANDED) )
		//======  
		SetRedraw(FALSE);
	*pResult = 0;
}



void CLeftView::OnItemexpanded (NMHDR* pNMHDR,
											LRESULT* pResult)
{
	NM_TREEVIEW* p = (NM_TREEVIEW*)pNMHDR;
	
	//======   
	CWaitCursor wait;

	//======    (   )
	if (p->itemNew.state & TVIS_EXPANDED)
	{	
		//      	
		HTREEITEM	hCur = p->itemNew.hItem,
					h = m_Tree.GetChildItem(hCur);

		//======     ,
		//======     
		if (m_Tree.GetItemText(h) == "")
		{
			//======  
			m_Tree.DeleteItem(h);
			//======   
			CString s = GetPath(hCur) + "*.*";

			//======   
			CFileFind cff;
			BOOL bFound = cff.FindFile(s);
	
			while (bFound)
			{
				bFound = cff.FindNextFile();
				if (cff.IsDirectory() && !cff.IsDots())
					AddItem(hCur, cff.GetFilePath());
			}
		}
		//======  
		SetRedraw(TRUE);
	}
	*pResult = 0;
}



CString CLeftView::GetPath (HTREEITEM hCur)
{
	//======      hCur
	CString s = "";
	for (HTREEITEM h=hCur;  h;  h=m_Tree.GetParentItem(h))
		s = m_Tree.GetItemText(h) + '\\' + s;
	return s;
}



void CLeftView::OnSelchanged (NMHDR *pNMHDR,
										LRESULT *pResult)
{
	NM_TREEVIEW* p = (NM_TREEVIEW*)pNMHDR;

	//======    
	GetDocument()->FreeDocs();

	//======   
	SearchForDocs (GetPath(p->itemNew.hItem));

	//======       
	//======  
	GetDocument()->ProcessDocs();
	*pResult = 0;
}



void CLeftView::SearchForDocs (CString s)
{
	//======     
	s += "*.mgn";
	
	CFileFind cff;
	BOOL bFound = cff.FindFile(s);
	
	while (bFound)
	{
		bFound = cff.FindNextFile();
		//======      
		GetDocument()->m_sFiles.push_back(cff.GetFilePath());
	}
}



typedef vector<CDPoint, allocator<CDPoint> > VECPTS;



class CPolygon: public CObject
{
	DECLARE_SERIAL(CPolygon)
public:
	CTreeDoc *m_pDoc;		//  
	VECPTS m_Points;			//   
	UINT m_nPenWidth;		//  
	COLORREF m_PenColor;	//  
	COLORREF m_BrushColor;	//  
	CDPoint m_ptLT;			//    
	CDPoint m_ptRB;			//    

	//======   
	CPolygon();
	//======  
	CPolygon(const CPolygon& poly);

	//======  
	CPolygon& operator= (const CPolygon& poly);
	//======   i- 
	CDPoint& operator[] (UINT i);
	//======   
	void GetRect(CDPoint& ptLT, CDPoint& ptRB);
	//======   
	void Set (CTreeDoc *p);	
	//======  
	void Set(CTreeDoc *p,COLORREF bCl,COLORREF pCl,UINT pen);

	//======    
	void MakeStar();			// 
	void MakeTria();			// 
	void MakePent();			// 

	//======    
	virtual void Draw (CDC *pDC, bool bContour);

	//======    
	virtual void Serialize(CArchive& ar);
	virtual ~CPolygon();		// 
};

//======   :  
typedef vector<CPolygon, allocator<CPolygon> > VECPOLY;


IMPLEMENT_SERIAL(CPolygon, CObject, 1)

//======   
CPolygon::CPolygon()
{
	m_pDoc = 0;			//    	
	MakeStar();			//     
}



CPolygon& CPolygon::operator=(const CPolygon& poly)
{
	//======   
	m_pDoc = poly.m_pDoc;
	m_nPenWidth = poly.m_nPenWidth;
	m_PenColor = poly.m_PenColor;
	m_BrushColor = poly.m_BrushColor;
		
	m_ptLT = poly.m_ptLT;
	m_ptRB = poly.m_ptRB;
	
	//======   
	if (!m_Points.empty())
		m_Points.clear();

	//======   
	for (UINT i=0;  i<poly.m_Points.size();  i++)
		m_Points.push_back(poly.m_Points[i]);

	//======   
	return *this;
}

//======    
//======    
CPolygon::CPolygon(const CPolygon& poly)
{
	*this = poly;
}



CDPoint& CPolygon::operator[](UINT i)
{
	if (0 <= i && i < m_Points.size())
		return m_Points[i];
	return m_ptLT;
}



//======   
void CPolygon::Set (CTreeDoc *p)
{
	m_pDoc = p;
}

//======     
void CPolygon::Set (CTreeDoc *p, COLORREF bCl,
							COLORREF pCl, UINT pen)
{
	m_pDoc			= p;
	m_BrushColor	= bCl;
	m_PenColor	= pCl;
	m_nPenWidth	= pen;
}



CPolygon::~CPolygon() 
{
 m_Points.clear(); 
}



void CPolygon::GetRect(CDPoint& ptLT, CDPoint& ptRB)
{
	m_ptLT = m_ptRB = CDPoint(0.,0.);

	//======     
	UINT n = m_Points.size();	
	if (n > 0)
	{	
		//======     
		for (UINT i=0; i<n; i++)
		{
			//======    
			double	x = m_Points[i].x,
					y = m_Points[i].y;
			if (x < m_ptLT.x)
				m_ptLT.x = x;
			else if (x > m_ptRB.x)
				m_ptRB.x = m_Points[i].x;
			if (y > m_ptLT.y)
				m_ptLT.y = y;
			else if (y < m_ptRB.y)
				m_ptRB.y = y;
		}
	}
	//======    ()
	ptLT = m_ptLT;
	ptRB = m_ptRB;
}



void CPolygon::Serialize(CArchive& ar)
{
	//======     ,
	if (ar.IsStoring())
	{
		//===      
		ar	<< m_nPenWidth << m_PenColor << m_BrushColor 
			<< m_Points.size() << m_ptLT.x << m_ptLT.y
			<< m_ptRB.x << m_ptRB.y; 
		
		for (UINT i=0; i <m_Points.size(); i++)
			ar << m_Points[i].x << m_Points[i].y;
	}
	else
	{
		//===       
		UINT size;
		ar	>> m_nPenWidth >> m_PenColor >> m_BrushColor
			>> size >> m_ptLT.x >> m_ptLT.y
			>> m_ptRB.x >> m_ptRB.y;

		//======     
		m_Points.clear();
		while (size--)
		{
			double x, y;
			ar >> x >> y;
			m_Points.push_back(CDPoint(x,y));
		}
	}
}



void CPolygon::Draw (CDC *pDC, bool bContour)
{
	//======   World- 
	UINT nPoints = m_Points.size();
	if (!nPoints)
		return;

	//======     
	CPoint *pts = new CPoint[nPoints];

	//======  
	for (UINT i=0; i<nPoints; i++)
		pts[i] = m_pDoc->MapToLogPt(m_Points[i]);
	
	pDC->SaveDC();

	CPen pen (PS_SOLID,m_nPenWidth,m_PenColor);
	pDC->SelectObject(&pen);
	CBrush brush (bContour ? GetSysColor(COLOR_WINDOW)
				 	: m_BrushColor);
	pDC->SelectObject(&brush);

	//======    
	//======   
	pDC->Polygon(pts, nPoints);

	//======  
	delete [] pts;
	pDC->RestoreDC(-1);
}



void CPolygon::MakeStar()
{
	m_Points.clear();

	//======  
	double	pi = 4. * atan(1.),				// 
			a1 = pi / 10.,
			a2 = 3. * a1,
			//====== 2  
			x1 = cos(a1),
			y1 = sin(a1),	
			x2 = cos(a2),
			y2 = sin(a2);
	
	//===  (World)   
	m_Points.push_back(CDPoint(0., 1.));
	m_Points.push_back(CDPoint(-x2, -y2));
	m_Points.push_back(CDPoint( x1,  y1));
	m_Points.push_back(CDPoint(-x1,  y1));
	m_Points.push_back(CDPoint( x2, -y2));

	//======  
	m_ptLT = CDPoint(-x1, 1.);
	m_ptRB = CDPoint( x1,-y2);
}

//======  
void CPolygon::MakeTria()
{
	m_Points.clear();
	double	pi = 4. * atan(1.),
			a = pi / 6.,
			x = cos(a),
			y = sin(a);
	
	m_Points.push_back (CDPoint(0., 1.));
	m_Points.push_back (CDPoint(-x, -y));
	m_Points.push_back (CDPoint( x, -y));
	m_ptLT = CDPoint (-x, 1.);
	m_ptRB = CDPoint ( x,-y);
}

//======  
void CPolygon::MakePent()
{
	m_Points.clear();

	double	pi = 4. * atan(1.),
			a1 = pi / 10.,
			a2 = 3. * a1,
			x1 = cos(a1),
			y1 = sin(a1),
			x2 = cos(a2),
			y2 = sin(a2);
	
	//  (World)   
	m_Points.push_back(CDPoint(0., 1.));
	m_Points.push_back(CDPoint(-x1,  y1));
	m_Points.push_back(CDPoint(-x2, -y2));
	m_Points.push_back(CDPoint( x2, -y2));
	m_Points.push_back(CDPoint( x1,  y1));

	m_ptLT = CDPoint(-x1, 1.);
	m_ptRB = CDPoint( x1,-y2);
}



class CTreeDoc : public CDocument
{
	//===  3       
	friend class CLeftView;	
	friend class CRightView;
	friend class CDrawView;
protected:
	virtual ~CTreeDoc();	
	CTreeDoc();

	DECLARE_DYNCREATE(CTreeDoc)
public:
	//==========   =============
	CPolygon m_Poly;				//  
	VECPOLY m_Shapes;			//  

	//======   
	vector<CString> m_sFiles;

	//======    Page space
	CSize m_szDoc;
	//==     World->Page
	UINT m_nLogZoom;
	//====== :    CTreeFrame
	bool m_bTreeExist;
	//====== :    CDrawFrame
	bool m_bDrawExist;

	//======     =======
	//======   
	CView* GetView(const CRuntimeClass* pViewClass);
	//======   
	bool MakeView();
	//======   World -> Page
	CPoint MapToLogPt(CDPoint& pt);
	//======   Page -> World
	CDPoint MapToWorldPt(CPoint& pt);
	//======   
	void UpdateDrawView();

	//======      
	void ProcessDocs();
	//======  
	void FreeDocs();
	//======   
	int FindPoint(CDPoint& pt);

	// Overrides
	public:
	virtual BOOL OnNewDocument();
	virtual void Serialize(CArchive& ar);

// Generated message map functions
protected:
	DECLARE_MESSAGE_MAP()
};



CTreeDoc::CTreeDoc() : m_szDoc(2000,2000), m_Poly()
{
	//======    
	//======   
	m_Poly.Set(this, RGB(240,255,250), RGB(0,96,0), 2);
	m_nLogZoom = 700;
}



CTreeDoc::~CTreeDoc()
{
	FreeDocs();
	m_Poly.m_Points.clear();
}



void CTreeDoc::Serialize(CArchive& ar)
{
	//     
	m_Poly.Serialize(ar);

	if (ar.IsStoring())
	{
		//     "" 
	}
	else
	{
		//     "" 
	}
}



CPoint CTreeDoc::MapToLogPt(CDPoint& pt)
{
	//======   
	int	x = m_szDoc.cx/2 + int(m_nLogZoom * pt.x),	
		y = m_szDoc.cy/2 + int(m_nLogZoom * pt.y);	
	return CPoint(x,y);
}



CDPoint CTreeDoc::MapToWorldPt(CPoint& pt)
{
	//======  
	double	x = double(pt.x - m_szDoc.cx/2) / m_nLogZoom,
			y = double(pt.y - m_szDoc.cy/2) / m_nLogZoom;
	return CDPoint(x, y);
}



class CTreeApp : public CWinApp
{
public:
	//======   
	CMultiDocTemplate *m_pTemplDraw, *m_pTemplTree;

	CTreeApp();
	virtual BOOL InitInstance();
	afx_msg void OnAppAbout();
	DECLARE_MESSAGE_MAP()
};



//======   
m_pTemplTree = new CMultiDocTemplate(IDR_TreeTYPE,
		RUNTIME_CLASS(CTreeDoc),
		RUNTIME_CLASS(CTreeFrame),
		RUNTIME_CLASS(CLeftView));

//======    
AddDocTemplate(m_pTemplTree);

//======   
m_pTemplDraw = new CMultiDocTemplate(IDR_DrawTYPE,
		RUNTIME_CLASS(CTreeDoc),
		RUNTIME_CLASS(CDrawFrame),
		RUNTIME_CLASS(CDrawView));

//======    
AddDocTemplate(m_pTemplDraw);



\nTree\nTree\nTree Files (*.mgn)\n.mgn\nTree.Document\nTree.Document



void CTreeApp::OnAppAbout()
{
	CDialog(IDD_ABOUTBOX).DoModal();
}



#pragma once
class CTreeDoc;				//  

class CDrawView : public CView
{
	DECLARE_DYNCREATE(CDrawView)
protected:
	CSize m_szView;		//    
	bool m_bNewPoints;	//     
	bool m_bReady;		//    
	bool m_bLock; 		//   
	int m_CurID;			//    
	HCURSOR m_hGrab;		//  
	CPen m_penLine;		//    

	CDrawView();
	virtual ~CDrawView();

public:
	CTreeDoc* GetDocument()  
	{
 	return dynamic_cast<CTreeDoc*>(m_pDocument); 
	}
	virtual void OnDraw(CDC* pDC);

	//======   
	void SetDC(CDC* pDC);

	//======  
	void RedrawLines (CDC *pDC, CPoint& point);

	DECLARE_MESSAGE_MAP()
};



CDrawView::CDrawView()
{
	//======    
	m_bNewPoints = false;
	m_bReady = false;
	m_bLock = false;
	m_CurID = -1;
}

void CDrawView::OnDraw(CDC* pDC)
{
	CTreeDoc* pDoc = GetDocument();

	//======   
	SetDC(pDC);
	//======     ,
	//======   
	pDoc->m_Poly.Draw(pDC, m_bLock);
}



void CDrawView::SetDC(CDC* pDC)
{
	CTreeDoc* pDoc = GetDocument();

	//======     
	pDC->SetMapMode(MM_ISOTROPIC);

	//======     
	pDC->SetWindowExt(pDoc->m_szDoc);
	pDC->SetWindowOrg(pDoc->m_szDoc.cx/2,pDoc->m_szDoc.cy/2);

	//======     
	pDC->SetViewportExt (m_szView.cx, -m_szView.cy);
	pDC->SetViewportOrg (m_szView.cx/2, m_szView.cy/2);
}



void CDrawView::OnSize(UINT nType, int cx, int cy) 
{
	CView::OnSize(nType, cx, cy);

	//        cx,cy
	if (cx==0 || cy==0)
		return;

	//======    	
	m_szView = CSize (cx, cy);	
}



void CDrawView::OnInitialUpdate()
{
	//======   
	m_hGrab = ((CTreeApp*)AfxGetApp())->LoadCursor(IDC_MOVE);
	//===     ( )
	m_penLine.CreatePen (PS_DOT,0,COLORREF(0));
}



#pragma once

//======     
class CRightView : public CScrollView
{
	//======     
	friend class CWndGeom;
protected:
	CSize m_szView;		//   
	CSize m_szScroll;	//   
	CSize m_szItem;		//  
	CSize m_szMargin;	//  
	CString m_WndClass;	//    
	
	CRightView();
	DECLARE_DYNCREATE(CRightView)
public:
	//======   
	vector<CWndGeom*> m_pWnds;
	
	CTreeDoc* GetDocument()
	{
 	return dynamic_cast<CTreeDoc*>(m_pDocument);
	}
	virtual ~CRightView();
	void Show();					//  
	void Clear();					//  

	// Overrides
	public:
	virtual void OnDraw(CDC* pDC);
	protected:
	virtual void OnInitialUpdate();
	DECLARE_MESSAGE_MAP()
};



IMPLEMENT_DYNCREATE(CRightView, CScrollView)

BEGIN_MESSAGE_MAP(CRightView, CScrollView)
END_MESSAGE_MAP()

CRightView::CRightView(){}
CRightView::~CRightView(){}

void CRightView::OnDraw(CDC* pDC)
{
	CTreeDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
}



void CRightView::OnSize(UINT nType, int cx, int cy) 
{
	CScrollView::OnSize(nType, cx, cy);

	if (cx==0 || cy==0)
		return;

	//======    
	m_szView = CSize (cx, cy);	
}

void CRightView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	//======   
	m_szScroll = m_szView;
	SetScrollSizes(MM_TEXT, m_szScroll); 
}



CRightView::CRightView()
{
	m_szItem = CSize(200,150);		//  
	m_szMargin = CSize(20,20);		//  
	try
	{
		//======    
		m_WndClass=AfxRegisterWndClass(CS_VREDRAW|CS_HREDRAW,
		::LoadCursor(GetModuleHandle(0),(char*)IDC_MYHAND),
		(HBRUSH) CreateSolidBrush(GetSysColor(COLOR_INFOBK)));
	}
	catch (CResourceException* pEx)
	{
		AfxMessageBox(_T("  "));
		pEx->Delete();
	}
}



void CRightView::Show()
{
	CTreeDoc *pDoc = GetDocument();

	//======  
	int nPoly = pDoc->m_Shapes.size();	
	//======  ,    
	int	dx = m_szItem.cx + m_szMargin.cx,
		dy = m_szItem.cy + m_szMargin.cy,
		nCols = m_szView.cx/dx;		//  

	//====== 
	if (nCols < 1)
		nCols = 1;
	if (nCols > nPoly)
		nCols = nPoly;

	//======  
	int nRows = int(double(nPoly)/nCols + .5);

	//===      
	m_szScroll = CSize(nCols*dx, nRows*dy);
	SetScrollSizes(MM_TEXT, m_szScroll);

	//======     
	CRect r(CPoint(0,0),m_szItem);
	r.OffsetRect (15,15);

	//======   
	DWORD style = WS_CHILD | WS_BORDER | WS_VISIBLE;

	//======     (n -  )
	for (int i=0, n=0; i < nRows; i++)
	{	
		//======    
		for (int j=0; j<nCols && n<nPoly; j++, n++)
		{
			CWndGeom *pWnd = new CWndGeom(this, n);

			//======    
			m_pWnds.push_back(pWnd);
			//======  Windows-
			pWnd->Create (m_WndClass, 0, style, r, this, 0);

			//======    
			r.OffsetRect (dx,0);
		}
		//======      
		r.OffsetRect(-nCols*dx, dy);
	}
}



void CRightView::Clear()
{
	//======      
	for (UINT i=0; i<m_pWnds.size(); i++)
	{
		//======  Windows-
		m_pWnds[i]->DestroyWindow();
	
		//  ,   
		delete m_pWnds[i];
	}
	//======  ,  
	m_pWnds.clear();
}

		//    Clear
CRightView::~CRightView()
{
	Clear();
}



class CWndGeom : public CWnd
{
public:
	CTreeDoc *m_pDoc;	//   ( )
	CRightView *m_pView;//   
	int m_ID; 			//     
	CRect m_Rect;			//     

	//======    
	CWndGeom(CRightView *p, int id);
	~CWndGeom();
protected:
	DECLARE_MESSAGE_MAP()
};



CWndGeom::CWndGeom(CRightView *p, int id) 
{
	//======    
	m_pView = p;
	//======   
	m_pDoc = p->GetDocument();
	//======     
	m_ID = id;
}

void CWndGeom::OnPaint() 
{
	CPaintDC dc(this);
	
	dc.SetMapMode(MM_ISOTROPIC);

	//======   
	dc.SetWindowOrg (m_pDoc->m_szDoc.cx/2,
						m_pDoc->m_szDoc.cy/2);
	dc.SetWindowExt(m_pDoc->m_szDoc);

	//======    
	GetClientRect(&m_Rect);
	int w = m_Rect.Width(),
		 h = m_Rect.Height();

	//======   
	dc.SetViewportOrg (w/2, h/2);
	dc.SetViewportExt (w, -h);

	//===       
	//===      
	m_pDoc->m_Shapes[m_ID].Draw(&dc);
}

void CWndGeom::OnLButtonDown(UINT nFlags, CPoint point)
{
	//======   
	m_pDoc->m_Poly = m_pDoc->m_Shapes[m_ID];

	//======     CDrawView,   
	if (m_pDoc->MakeView())
		return;

	//===   ,       
	CView *pView=m_pDoc->GetView(&CDrawView::classCDrawView);
	((CMDIChildWnd*)pView->GetParentFrame())->MDIActivate();

	//======    
	pView->Invalidate();
}



void CWndGeom::OnMouseMove(UINT nFlags, CPoint point) 
{
	//======      ,
	if (m_Rect.PtInRect(point))
	{
		//======   ,  
		//======    
		SetCapture();
		CClientDC dc(this);
		CPen pen (PS_SOLID, 4, RGB(192,192,255));
		dc.SelectObject(&pen);

		dc.MoveTo(m_Rect.left+4, m_Rect.top+4);
		dc.LineTo(m_Rect.right-4, m_Rect.top+4);
		dc.LineTo(m_Rect.right-4, m_Rect.bottom-4);
		dc.LineTo(m_Rect.left+4, m_Rect.bottom-4);
		dc.LineTo(m_Rect.left+4, m_Rect.top+4);
	}
	else
	{
		ReleaseCapture();	//  
		Invalidate();			//   
	}
}



CView* CTreeDoc::GetView(const CRuntimeClass* pViewClass)
{
	//======     
	POSITION pos = GetFirstViewPosition();
	//======  
	CView *pView = 0;

	//======    
	while (pos)
	{
		pView = GetNextView(pos);
		//===    ,    
		if (pView->IsKindOf(pViewClass))
			break;
	}

	//======   
	return pView;
}



bool CTreeDoc::MakeView()
{
	//======   -   
	if (!m_bDrawExist || !m_bTreeExist)
	{
		//======   
		CTreeApp* pApp = dynamic_cast<CTreeApp*>(AfxGetApp());
		CDocTemplate *pTempl;
				
		//======    
		if (!m_bDrawExist)
		{
			pTempl = pApp->m_pTemplDraw;
			m_bDrawExist = true;
		}
		else
		{
			pTempl = pApp->m_pTemplTree;
			m_bTreeExist = true;
		}
		
		//===        
		//===      
		CFrameWnd *pFrame = pTempl->CreateNewFrame(this, 0);
		pTempl->InitialUpdateFrame(pFrame, this);
		return true;
	}
	return false;
}



BOOL CTreeDoc::OnNewDocument()
{
	//======    
	if (!CDocument::OnNewDocument())
		return FALSE;

	//======    
	CDocTemplate* pTempl = GetDocTemplate();
	CString s;

	//======      
	pTempl->GetDocString(s, CDocTemplate::fileNewName);
	
	m_bDrawExist = s == "Draw";
	m_bTreeExist = !m_bDrawExist;

	return TRUE;
}



void CTreeDoc::FreeDocs()
{
	m_sFiles.clear();
	m_Shapes.clear();

	//======    		
	CRightView *pView = dynamic_cast<CRightView*>
						(GetView(RUNTIME_CLASS(CRightView)));
	//======   -
	if (pView)
		pView->Clear();
}



void CTreeDoc::ProcessDocs()
{
	UINT nFiles = m_sFiles.size();
	//======    
	if (!nFiles)
		return;
	
	for (UINT i=0; i < nFiles; i++)
	{	
		//======   
		CFile file; 				// ,  
		CFileException e;		//    
		CString fn = m_sFiles[i];	//  
		
		if (!file.Open (fn, CFile::modeRead 	|
								CFile::shareDenyWrite, &e))
		{
			//===       
			//===     
			CString msg = 
				e.m_cause == CFileException::fileNotFound ?
				": " + fn + "   "
				:	"  " + fn;
			AfxMessageBox(msg);
			return;
		}
		//======    
		CArchive ar (&file, CArchive::load);
		CPolygon poly;				//  
		poly.Set(this);				//  
		poly.Serialize (ar); 		//  
		m_Shapes.push_back(poly);	//   
	}
	
	//======      	
	CRightView *pView = dynamic_cast<CRightView*>
						(GetView(RUNTIME_CLASS(CRightView)));
	pView->Show();
}



void CTreeFrame::OnClose() 
{
	//======    
	CTreeDoc *pDoc = dynamic_cast<CTreeDoc*>
										(GetActiveDocument());
	pDoc->m_bTreeExist = false;
	CMDIChildWnd::OnClose();
}

void CDrawFrame::OnClose() 
{
	CTreeDoc *pDoc = dynamic_cast<CTreeDoc*>
										(GetActiveDocument());
	pDoc->m_bDrawExist = false;
	CMDIChildWnd::OnClose();
}



void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	//======     
	if (m_bNewPoints)
	{
		CTreeDoc *pDoc = GetDocument();
		//======      
		VECPTS& pts = pDoc->m_Poly.m_Points;

		//===     
		CDC *pDC = GetDC();
		//======      
		SetDC(pDC);

		//===     
		pDC->DPtoLP(&point);

		//===  Page-  World-
		CDPoint pt = pDoc->MapToWorldPt(point);
		//======   
		pts.push_back(pt);
	}
	//======     
	else if (m_bReady)
	{
		m_bLock = true;		//   
		m_bReady = false;	//   
	}
	//======    
	else if (m_bLock)
		m_bLock = false;		//   
	else						//    
		return;				// 

	Invalidate();				//  
}

void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
{
	//===       
	if (m_bNewPoints)
		return;
	
	//======    
	CDC *pDC = GetDC();
	SetDC(pDC);

	//===     
	pDC->DPtoLP(&point);

	//===  Page-  World-
	CTreeDoc *pDoc = GetDocument();
	CDPoint pt = pDoc->MapToWorldPt(point);

	//======   ,  
	//======      
	if (m_bLock)
	{
		//     
		SetCursor(m_hGrab);
		//======   
		pDC->SetROP2(R2_XORPEN);
		
		//======  
		//======    
		RedrawLines(pDC,	pDoc->MapToLogPt(pDoc->
								m_Poly.m_Points[m_CurID]));

		//======   
		RedrawLines(pDC, point);

		//======    
		pDoc->m_Poly.m_Points[m_CurID] = pt;
	}
	//======      
	else
	{
		m_CurID = pDoc->FindPoint(pt);

		//===  ,  m_CurID   
		//===  ,     -1
		m_bReady = m_CurID >= 0;

		//===  ,   
		if (m_bReady)
			SetCursor(m_hGrab);
	}
}

//======   , 
//======     
void CDrawView::RedrawLines (CDC *pDC, CPoint& point)
{
	CTreeDoc *pDoc = GetDocument();

	//======      
	VECPTS& pts = pDoc->m_Poly.m_Points;
	UINT size = pts.size();

	//======   , 
	if (size < 2)
		return;
	
	//======   
	int i1 = m_CurID == 0 ? size - 1 : m_CurID - 1;
	int i2 = m_CurID == size - 1 ? 0 : m_CurID + 1;
	
	//======      
	pDC->SelectObject(&m_penLine);
	pDC->MoveTo(pDoc->MapToLogPt(pts[i1]));
	pDC->LineTo(point);
	pDC->LineTo(pDoc->MapToLogPt(pts[i2]));
}


int CTreeDoc::FindPoint(CDPoint& pt)
{
	//======  
	int id = -1;
	//======     
	for (UINT i=0; i<m_Poly.m_Points.size(); i++)
	{
		//===    World-.
		//===      
		//=== ,     CDPoint
		if ( !(m_Poly.m_Points[i] - pt) <= 5e-2)
		{
			id = i;
			break;			// 
		}
	}
	//======  
	return id;
}



void CDrawView::OnEditNewpoly(void)
{
	//====== /   
	m_bNewPoints = !m_bNewPoints;
	//===    
	m_bReady = false;
	m_bLock = false;

	//======   ,   
	if (m_bNewPoints)
	{
		GetDocument()->m_Poly.m_Points.clear();
		Invalidate();
	}
}



void CDrawView::OnUpdateEditNewpoly(CCmdUI *pCmdUI)
{
	pCmdUI->SetCheck(m_bNewPoints);
}



void CMainFrame::ChangeToolbar(UINT tb)
{ 
	//===   tb    
	m_wndToolBar.LoadToolBar (tb);
	//===  toolbar
	RecalcLayout();
}



void CTreeFrame::OnSetFocus(CWnd* pOldWnd)
{
	//======    ,
	CMDIChildWnd::OnSetFocus(pOldWnd);
	
	//======    
	((CMainFrame*)GetParentFrame())->
							ChangeToolbar(IDR_TreeTYPE);
}

void CDrawFrame::OnSetFocus(CWnd* pOldWnd)
{
	CMDIChildWnd::OnSetFocus(pOldWnd);
	((CMainFrame*)AfxGetMainWnd())->
								ChangeToolbar(IDR_DrawTYPE);
}



void CTreeDoc::OnViewRefresh(void)
{
	//======    
	CLeftView *pView = dynamic_cast<CLeftView*>
					(GetView(RUNTIME_CLASS(CLeftView)));

	//======     
	//======    
	FreeDocs();
	pView->SearchForDocs(pView->GetPath(pView->
									m_Tree.GetSelectedItem()));
	ProcessDocs();
}



void CWndGeom::OnMouseMove(UINT nFlags, CPoint point) 
{
	//======   (CWndGeom  CRightView)
	CRect rChild, rParent;
	//===    ( !)
	GetWindowRect(rChild);
	m_pView->GetWindowRect(rParent);

	//===    ,  
	//===    14  ( )
	if (m_pView->m_szScroll.cx - m_pView->m_szView.cx > 0)
		rParent.right -= 14;
	if (m_pView->m_szScroll.cy - m_pView->m_szView.cy > 0)
		rParent.bottom -= 14;
	
	//===   ,  rChild
	rChild.IntersectRect (rChild, rParent);
	//===      	
	ClientToScreen(&point);

	//===      ,	
	if (rChild.PtInRect(point))
	{
		//===    ,
		//     CWndGeom
		SetCapture();

		//===    ()
		CRect r(m_Rect);
		r.DeflateRect(4,4);
		CClientDC dc(this);
		//======   
		dc.FrameRect(&r, &CBrush(RGB(192,192,255)));
	}
	else
	{
		ReleaseCapture();
		Invalidate();
	}
}	


if (rChild.PtInRect(point))
{
	SetCapture();
	CPen pen (PS_SOLID, 4, RGB(192,192,255));
	CClientDC dc(this);
	dc.SelectObject(&pen);
	CRect r(m_Rect);
	//======  
	r.DeflateRect(4,4);

	//===     , 
	//===    
	dc.SelectObject(GetStockObject(NULL_BRUSH));	
	dc.Rectangle(r);
}






IDD_POLYCOLOR
  Size:
IDC_PEN
 TRI
IDC_TRI
 PENT
IDC_ PENT
 STAR
IDC_ STAR
 Close
IDOK
  Red
IDC_RED
  Green
IDC_GREEN
  Blue
IDC_BLUE
 (Slider)
IDC_RSLIDER
Slider
IDC_GSLIDER
Slider
IDC_BSLIDER
  Color
IDC_COLOR

IDD_POLYCOLOR
  Size:
IDC_PEN
 TRI
IDC_TRI
 PENT
IDC_ PENT
 STAR
IDC_ STAR
 Close
IDOK
  Red
IDC_RED
  Green
IDC_GREEN
  Blue
IDC_BLUE
 (Slider)
IDC_RSLIDER
Slider
IDC_GSLIDER





#pragma once

//=====    
class CClrEdit : public CEdit
{
	DECLARE_DYNAMIC(CClrEdit)

public:
	CClrEdit();
	virtual ~CClrEdit();
	void ChangeColor(COLORREF clr);	//  

protected:
	DECLARE_MESSAGE_MAP()

private:
	COLORREF m_clrText; 	//  
	COLORREF m_clrBk;		//  
	CBrush m_brBk; 			//    
};

//======     
class CPolyDlg : public CDialog
{
	friend class CClrEdit;
	DECLARE_DYNAMIC(CPolyDlg)

public:
	enum { IDD = IDD_POLYCOLOR };

	//======    
	CPolyDlg(CTreeDoc* p);
	virtual ~CPolyDlg();

	//======  
	void UpdateColor();
	
protected:
	virtual void DoDataExchange(CDataExchange* pDX);

	DECLARE_MESSAGE_MAP()
private:
	CTreeDoc* m_pDoc;		//  
	CBitmapButton m_cTri;	//   
	CBitmapButton m_cPent;	
	CBitmapButton m_cStar; 
	bool m_bScroll;			//   
};



HBRUSH CClrEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
	pDC->SetTextColor (m_clrText);	//  
	pDC->SetBkColor (m_clrBk);			//   
	return m_brBk;						//  
}



void CClrEdit::ChangeColor(COLORREF clr)
{
	//======   -   
	m_clrText = ~clr & 0xffffff;
	m_clrBk = clr;
	//======    
	m_brBk.DeleteObject();
	m_brBk.CreateSolidBrush (clr);
	Invalidate();
}



void CPolyDlg::DoDataExchange(CDataExchange* pDX)
{
	//======  Control-  
	DDX_Control(pDX, IDC_BSLIDER, m_bSlider);
	DDX_Control(pDX, IDC_GSLIDER, m_gSlider);
	DDX_Control(pDX, IDC_RSLIDER, m_rSlider);

	//====  Control-  
	//====  
	DDX_Control(pDX, IDC_COLOR, m_cColor);
	DDX_Control(pDX, IDC_BLUE, m_cBlue);
	DDX_Control(pDX, IDC_GREEN, m_cGreen);
	DDX_Control(pDX, IDC_RED, m_cRed);

	//====  Value-  
	//====     
	DDX_Text(pDX, IDC_BLUE, m_nBlue);
	DDV_MinMaxUInt(pDX, m_nBlue, 0, 255);
	DDX_Text(pDX, IDC_GREEN, m_nGreen);
	DDV_MinMaxUInt(pDX, m_nGreen, 0, 255);
	DDX_Text(pDX, IDC_RED, m_nRed);
	DDV_MinMaxUInt(pDX, m_nRed, 0, 255);
	DDX_Text(pDX, IDC_PEN, m_nPen);
	DDV_MinMaxUInt(pDX, m_nPen, 1, 100);	

	//====     	
	CDialog::DoDataExchange(pDX);
}



void CPolyDlg::OnHScroll(UINT nSBCode, UINT nPos,
									CScrollBar* pScrollBar) 
{
	//======    
	if (nSBCode==SB_ENDSCROLL)
		return;

	//======     
	m_bScroll = true;

	//======    
	switch(GetFocus()->GetDlgCtrlID())
	{
	case IDC_RSLIDER:
		//======    
		m_nRed = m_rSlider.GetPos();
		//======   
		SetDlgItemInt(IDC_RED, m_nRed);
		break;
	case IDC_GSLIDER:
		m_nGreen = m_gSlider.GetPos();
		SetDlgItemInt(IDC_GREEN, m_nGreen);
		break;
	case IDC_BSLIDER:
		m_nBlue = m_bSlider.GetPos();
		SetDlgItemInt(IDC_BLUE, m_nBlue);
		break;
	}
	//======     
	m_bScroll = false;
}



void CPolyDlg::OnChangePen(void)
{
	BOOL bSuccess;
	//======    
	UINT nSize = GetDlgItemInt(IDC_PEN, &bSuccess, FALSE);
	if (bSuccess && nSize < 101)
	{
		m_nPen = nSize;
		m_pDoc->m_Poly.m_nPenWidth = m_nPen;
		m_pDoc->UpdateDrawView();
	}
}



void CPolyDlg::OnChangeRed(void)
{
	//======    ,
	//======     
	if (!m_bScroll)
	{
		m_nRed = GetDlgItemInt(IDC_RED, 0, FALSE);
		m_rSlider.SetPos(m_nRed);
	}

	//======     
	m_cRed.ChangeColor(RGB(m_nRed, 0, 0));
	//======    
	UpdateColor();
}

void CPolyDlg::OnChangeGreen(void)
{
	if (!m_bScroll)
	{
		m_nGreen = GetDlgItemInt(IDC_GREEN, 0, FALSE);
		m_gSlider.SetPos(m_nGreen);
	}
	m_cGreen.ChangeColor(RGB(0, m_nGreen, 0));
	UpdateColor();
}

void CPolyDlg::OnChangeBlue(void)
{
	if (!m_bScroll)
	{
		m_nBlue = GetDlgItemInt(IDC_BLUE, 0, FALSE);
		m_bSlider.SetPos(m_nBlue);
	}
	m_cBlue.ChangeColor(RGB(0, 0, m_nBlue));
	UpdateColor();
}



void CPolyDlg::UpdateColor()
{
	COLORREF clr = RGB(m_nRed,m_nGreen,m_nBlue);
	m_cColor.ChangeColor(clr);
	m_pDoc->m_Poly.m_BrushColor = clr;
	m_pDoc->UpdateDrawView();
}
void CPolyDlg::OnClickedTri(void)
{
	m_pDoc->m_Poly.MakeTria();
	m_pDoc->UpdateDrawView();
}

void CPolyDlg::OnClickedPent(void)
{
	m_pDoc->m_Poly.MakePent();
	m_pDoc->UpdateDrawView();
}

void CPolyDlg::OnClickedStar(void)
{
	m_pDoc->m_Poly.MakeStar();
	m_pDoc->UpdateDrawView();
}



CPolyDlg::CPolyDlg(CTreeDoc* p): CDialog(CPolyDlg::IDD,0)
{
	m_pDoc = p;
	m_nPen = p->m_Poly.m_nPenWidth;

	//======     
	COLORREF brush = p->m_Poly.m_BrushColor;
	m_nRed		= GetRValue(brush); 	//   
	m_nGreen	= GetGValue(brush);
	m_nBlue	= GetBValue(brush);
	m_bScroll	= false;					//   
}



BOOL CPolyDlg::OnInitDialog()
{
	//======     
	m_cTri.AutoLoad(IDC_TRI,this);
	m_cPent.AutoLoad(IDC_PENT,this);
	m_cStar.AutoLoad(IDC_STAR,this);

	CDialog::OnInitDialog();

	//======   
	m_rSlider.SetRange(0,255);
	m_gSlider.SetRange(0,255);
	m_bSlider.SetRange(0,255);

	//======    
	m_rSlider.SetTicFreq(50);
	m_gSlider.SetTicFreq(50);
	m_bSlider.SetTicFreq(50);

	//===    
	//===     
	OnChangeRed();
	OnChangeGreen();
	OnChangeBlue();
	return TRUE;
}



void CPolyDlg::OnClickedOk(void) 
{
	//===      
	m_pDoc->m_pPolyDlg = 0;

	//======    DestroyWindow
	CDialog::OnOK();

	//======   
	delete this;
}



void CTreeDoc::OnEditPolycolor(void)
{
	//======   
	if (!m_pPolyDlg)
	{
		//======     
		m_pPolyDlg = new CPolyDlg(this);
		m_pPolyDlg->Create(IDD_POLYCOLOR);
	}
	else
		//=====     
		m_pPolyDlg->SetActiveWindow();
}



void CTreeDoc::UpdateDrawView()
{
	//======    
	CDrawView *pView = dynamic_cast<CDrawView*>
			(GetView(&CDrawView::classCDrawView));
	//======       
	if (pView)
		pView->Invalidate();
}




